Redo how we extract files from a cabinet in order to dramatically
improve performance, especially if picking and choosing files out of the cabinet.
This commit is contained in:
parent
9adacf6a72
commit
b9c6b85779
229
dlls/msi/files.c
229
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());
|
||||
|
||||
|
|
Loading…
Reference in New Issue