diff --git a/dlls/msi/files.c b/dlls/msi/files.c index 46334976062..a4fd40e493d 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -125,7 +125,6 @@ typedef struct { MSIPACKAGE* package; LPCSTR cab_path; - LPCSTR file_name; } CabData; static void * cabinet_alloc(ULONG cb) @@ -195,7 +194,6 @@ static long cabinet_seek(INT_PTR hf, long dist, int seektype) static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) { - /* FIXME: try to do more processing in this function */ switch (fdint) { case fdintCOPY_FILE: @@ -208,10 +206,30 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) LPWSTR trackpath; LPWSTR tracknametmp; static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; - - if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1)) - return 0; - + LPWSTR given_file; + INT index; + + MSIRECORD * uirow; + LPWSTR uipath; + + given_file = strdupAtoW(pfdin->psz1); + index = get_loaded_file(data->package, given_file); + + if (index < 0) + { + ERR("Unknown File in Cabinent (%s)\n",debugstr_w(given_file)); + HeapFree(GetProcessHeap(),0,given_file); + return 0; + } + + if (!((data->package->files[index].State == 1 || + data->package->files[index].State == 2))) + { + TRACE("Skipping extraction of %s\n",debugstr_w(given_file)); + HeapFree(GetProcessHeap(),0,given_file); + return 0; + } + file = cabinet_alloc((len+1)*sizeof(char)); strcpy(file, data->cab_path); strcat(file, pfdin->psz1); @@ -233,6 +251,19 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) HeapFree(GetProcessHeap(),0,trackname); HeapFree(GetProcessHeap(),0,tracknametmp); + /* the UI chunk */ + uirow=MSI_CreateRecord(9); + MSI_RecordSetStringW(uirow,1,data->package->files[index].File); + uipath = strdupW(data->package->files[index].TargetPath); + *(strrchrW(uipath,'\\')+1)=0; + MSI_RecordSetStringW(uirow,9,uipath); + MSI_RecordSetInteger(uirow,6,data->package->files[index].FileSize); + ui_actiondata(data->package,szInstallFiles,uirow); + msiobj_release( &uirow->hdr ); + HeapFree(GetProcessHeap(),0,uipath); + + ui_progress(data->package,2,data->package->files[index].FileSize,0,0); + return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); } case fdintCLOSE_FILE_INFO: @@ -259,19 +290,17 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) * * Extract files from a cab file. */ -static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, - const WCHAR* path, const WCHAR* file) +static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source, + LPCWSTR path) { HFDI hfdi; ERF erf; BOOL ret; char *cabinet; char *cab_path; - char *file_name; CabData data; - TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), - debugstr_w(file), debugstr_w(path)); + TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); hfdi = FDICreate(cabinet_alloc, cabinet_free, @@ -302,11 +331,6 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, data.package = package; data.cab_path = cab_path; - if (file) - file_name = strdupWtoA(file); - else - file_name = NULL; - data.file_name = file_name; ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); @@ -317,13 +341,26 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, HeapFree(GetProcessHeap(), 0, cabinet); HeapFree(GetProcessHeap(), 0, cab_path); - HeapFree(GetProcessHeap(), 0, file_name); return ret; } -static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, - MSIFILE* file) +static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT* + comp, LPCWSTR path) +{ + if (file->Attributes & msidbFileAttributesNoncompressed) + { + LPWSTR p; + p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + file->SourcePath = build_directory_name(2, p, file->ShortName); + HeapFree(GetProcessHeap(),0,p); + } + else + file->SourcePath = build_directory_name(2, path, file->File); +} + +static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, + MSICOMPONENT* comp) { UINT rc = ERROR_SUCCESS; MSIRECORD * row = 0; @@ -338,27 +375,46 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, DWORD sz; INT seq; static UINT last_sequence = 0; + static LPWSTR last_path = NULL; + MSIFILE* file = NULL; - if (file->Attributes & msidbFileAttributesNoncompressed) + /* cleanup signal */ + if (!package) { - TRACE("Uncompressed File, no media to ready.\n"); + HeapFree(GetProcessHeap(),0,last_path); return ERROR_SUCCESS; } + file = &package->files[fileindex]; + if (file->Sequence <= last_sequence) { + set_file_source(package,file,comp,last_path); TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); - /*extract_a_cabinet_file(package, source,path,file->File); */ return ERROR_SUCCESS; } row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence); if (!row) + { + TRACE("Unable to query row\n"); return ERROR_FUNCTION_FAILED; + } seq = MSI_RecordGetInteger(row,2); last_sequence = seq; + HeapFree(GetProcessHeap(),0,last_path); + last_path = NULL; + + if (file->Attributes & msidbFileAttributesNoncompressed) + { + last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + set_file_source(package,file,comp,last_path); + msiobj_release(&row->hdr); + return rc; + } + cab = MSI_RecordGetString(row,4); if (cab) { @@ -367,12 +423,13 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, if (cab[0]=='#') { writeout_cabinet_stream(package,&cab[1],source); - strcpyW(path,source); - *(strrchrW(path,'\\')+1)=0; + last_path = strdupW(source); + *(strrchrW(last_path,'\\')+1)=0; } else { sz = MAX_PATH; + last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); if (MSI_GetPropertyW(package, cszSourceDir, source, &sz)) { ERR("No Source dir defined \n"); @@ -380,24 +437,29 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, } else { - strcpyW(path,source); + strcpyW(last_path,source); strcatW(source,cab); /* extract the cab file into a folder in the temp folder */ sz = MAX_PATH; - if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) + if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz) != ERROR_SUCCESS) - GetTempPathW(MAX_PATH,path); + GetTempPathW(MAX_PATH,last_path); } } - rc = !extract_a_cabinet_file(package, source,path,NULL); + rc = !extract_cabinet_file(package, source, last_path); + /* reaquire file ptr */ + file = &package->files[fileindex]; } else { sz = MAX_PATH; + last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); MSI_GetPropertyW(package,cszSourceDir,source,&sz); - strcpyW(path,source); + strcpyW(last_path,source); } + set_file_source(package, file, comp, last_path); msiobj_release(&row->hdr); + return rc; } @@ -426,12 +488,17 @@ inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, return ERROR_FUNCTION_FAILED; } +/* + * In order to make this work more effeciencly I am going to do this in 2 + * passes. + * Pass 1) Correct all the TargetPaths and determin what files are to be + * installed. + * Pass 2) Extract Cabinents and copy files. + */ UINT ACTION_InstallFiles(MSIPACKAGE *package) { UINT rc = ERROR_SUCCESS; DWORD index; - MSIRECORD * uirow; - WCHAR uipath[MAX_PATH]; if (!package) return ERROR_INVALID_HANDLE; @@ -439,17 +506,17 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) /* increment progress bar each time action data is sent */ ui_progress(package,1,1,0,0); + /* Pass 1 */ for (index = 0; index < package->loaded_files; index++) { - WCHAR path_to_source[MAX_PATH]; MSIFILE *file; - + MSICOMPONENT* comp = NULL; + file = &package->files[index]; if (file->Temporary) continue; - if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, INSTALLSTATE_LOCAL)) { @@ -457,28 +524,15 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) TRACE("File %s is not scheduled for install\n", debugstr_w(file->File)); + file->State = 5; continue; } if ((file->State == 1) || (file->State == 2)) { - LPWSTR p; - MSICOMPONENT* comp = NULL; + LPWSTR p = NULL; - TRACE("Installing %s\n",debugstr_w(file->File)); - rc = ready_media_for_file(package, path_to_source, file); - /* - * WARNING! - * our file table could change here because a new temp file - * may have been created - */ - file = &package->files[index]; - if (rc != ERROR_SUCCESS) - { - ERR("Unable to ready media\n"); - rc = ERROR_FUNCTION_FAILED; - break; - } + TRACE("Pass 1: %s\n",debugstr_w(file->File)); create_component_directory( package, file->ComponentIndex); @@ -486,39 +540,56 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) if (file->ComponentIndex >= 0) comp = &package->components[file->ComponentIndex]; + else + { + ERR("No Component for file\n"); + continue; + } p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); HeapFree(GetProcessHeap(),0,file->TargetPath); file->TargetPath = build_directory_name(2, p, file->FileName); HeapFree(GetProcessHeap(),0,p); + } + } - if (file->Attributes & msidbFileAttributesNoncompressed) + /* Pass 2 */ + for (index = 0; index < package->loaded_files; index++) + { + MSIFILE *file; + MSICOMPONENT* comp = NULL; + + file = &package->files[index]; + + if (file->Temporary) + continue; + + if ((file->State == 1) || (file->State == 2)) + { + TRACE("Pass 2: %s\n",debugstr_w(file->File)); + + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + + rc = ready_media_for_file(package, index, comp); + if (rc != ERROR_SUCCESS) { - p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); - file->SourcePath = build_directory_name(2, p, file->ShortName); - HeapFree(GetProcessHeap(),0,p); + ERR("Unable to ready media\n"); + rc = ERROR_FUNCTION_FAILED; + break; } - else - file->SourcePath = build_directory_name(2, path_to_source, - file->File); + /* + * WARNING! + * our file table could change here because a new temp file + * may have been created. So reaquire our ptr. + */ + file = &package->files[index]; TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), debugstr_w(file->TargetPath)); - /* the UI chunk */ - uirow=MSI_CreateRecord(9); - MSI_RecordSetStringW(uirow,1,file->File); - strcpyW(uipath,file->TargetPath); - *(strrchrW(uipath,'\\')+1)=0; - MSI_RecordSetStringW(uirow,9,uipath); - MSI_RecordSetInteger(uirow,6,file->FileSize); - ui_actiondata(package,szInstallFiles,uirow); - msiobj_release( &uirow->hdr ); - ui_progress(package,2,file->FileSize,0,0); - - if (file->Attributes & msidbFileAttributesNoncompressed) rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); else @@ -559,6 +630,8 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) } } + /* cleanup */ + ready_media_for_file(NULL, 0, NULL); return rc; } @@ -576,15 +649,15 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) component = MSI_RecordGetString(row,2); component_index = get_loaded_component(package,component); - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) { TRACE("Skipping copy due to disabled component %s\n", debugstr_w(component)); /* the action taken was the same as the current install state */ package->components[component_index].Action = - package->components[component_index].Installed; + package->components[component_index].Installed; return ERROR_SUCCESS; } @@ -608,15 +681,13 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) } if (MSI_RecordIsNull(row,4)) - { strcpyW(dest_name,strrchrW(file_source,'\\')+1); - } else { sz=0x100; MSI_RecordGetStringW(row,4,dest_name,&sz); reduce_to_longfilename(dest_name); - } + } if (MSI_RecordIsNull(row,5)) { @@ -645,15 +716,15 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) } dest = build_directory_name(2, dest_path, dest_name); - + TRACE("Duplicating file %s to %s\n",debugstr_w(file_source), - debugstr_w(dest)); - + debugstr_w(dest)); + if (strcmpW(file_source,dest)) rc = !CopyFileW(file_source,dest,TRUE); else rc = ERROR_SUCCESS; - + if (rc != ERROR_SUCCESS) ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());