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:
Aric Stewart 2005-06-24 12:14:35 +00:00 committed by Alexandre Julliard
parent 9adacf6a72
commit b9c6b85779

View file

@ -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());