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
1 changed files with 150 additions and 79 deletions

View File

@ -125,7 +125,6 @@ typedef struct
{ {
MSIPACKAGE* package; MSIPACKAGE* package;
LPCSTR cab_path; LPCSTR cab_path;
LPCSTR file_name;
} CabData; } CabData;
static void * cabinet_alloc(ULONG cb) 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) static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{ {
/* FIXME: try to do more processing in this function */
switch (fdint) switch (fdint)
{ {
case fdintCOPY_FILE: case fdintCOPY_FILE:
@ -208,9 +206,29 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
LPWSTR trackpath; LPWSTR trackpath;
LPWSTR tracknametmp; LPWSTR tracknametmp;
static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
LPWSTR given_file;
INT index;
if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1)) 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; 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)); file = cabinet_alloc((len+1)*sizeof(char));
strcpy(file, data->cab_path); strcpy(file, data->cab_path);
@ -233,6 +251,19 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
HeapFree(GetProcessHeap(),0,trackname); HeapFree(GetProcessHeap(),0,trackname);
HeapFree(GetProcessHeap(),0,tracknametmp); 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); return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
} }
case fdintCLOSE_FILE_INFO: case fdintCLOSE_FILE_INFO:
@ -259,19 +290,17 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
* *
* Extract files from a cab file. * Extract files from a cab file.
*/ */
static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
const WCHAR* path, const WCHAR* file) LPCWSTR path)
{ {
HFDI hfdi; HFDI hfdi;
ERF erf; ERF erf;
BOOL ret; BOOL ret;
char *cabinet; char *cabinet;
char *cab_path; char *cab_path;
char *file_name;
CabData data; CabData data;
TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
debugstr_w(file), debugstr_w(path));
hfdi = FDICreate(cabinet_alloc, hfdi = FDICreate(cabinet_alloc,
cabinet_free, cabinet_free,
@ -302,11 +331,6 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
data.package = package; data.package = package;
data.cab_path = cab_path; 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); 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, cabinet);
HeapFree(GetProcessHeap(), 0, cab_path); HeapFree(GetProcessHeap(), 0, cab_path);
HeapFree(GetProcessHeap(), 0, file_name);
return ret; return ret;
} }
static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
MSIFILE* file) 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; UINT rc = ERROR_SUCCESS;
MSIRECORD * row = 0; MSIRECORD * row = 0;
@ -338,27 +375,46 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
DWORD sz; DWORD sz;
INT seq; INT seq;
static UINT last_sequence = 0; 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; return ERROR_SUCCESS;
} }
file = &package->files[fileindex];
if (file->Sequence <= last_sequence) if (file->Sequence <= last_sequence)
{ {
set_file_source(package,file,comp,last_path);
TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
/*extract_a_cabinet_file(package, source,path,file->File); */
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence); row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
if (!row) if (!row)
{
TRACE("Unable to query row\n");
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
}
seq = MSI_RecordGetInteger(row,2); seq = MSI_RecordGetInteger(row,2);
last_sequence = seq; 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); cab = MSI_RecordGetString(row,4);
if (cab) if (cab)
{ {
@ -367,12 +423,13 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
if (cab[0]=='#') if (cab[0]=='#')
{ {
writeout_cabinet_stream(package,&cab[1],source); writeout_cabinet_stream(package,&cab[1],source);
strcpyW(path,source); last_path = strdupW(source);
*(strrchrW(path,'\\')+1)=0; *(strrchrW(last_path,'\\')+1)=0;
} }
else else
{ {
sz = MAX_PATH; sz = MAX_PATH;
last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
if (MSI_GetPropertyW(package, cszSourceDir, source, &sz)) if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
{ {
ERR("No Source dir defined \n"); ERR("No Source dir defined \n");
@ -380,24 +437,29 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
} }
else else
{ {
strcpyW(path,source); strcpyW(last_path,source);
strcatW(source,cab); strcatW(source,cab);
/* extract the cab file into a folder in the temp folder */ /* extract the cab file into a folder in the temp folder */
sz = MAX_PATH; sz = MAX_PATH;
if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz)
!= ERROR_SUCCESS) != 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 else
{ {
sz = MAX_PATH; sz = MAX_PATH;
last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
MSI_GetPropertyW(package,cszSourceDir,source,&sz); 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); msiobj_release(&row->hdr);
return rc; return rc;
} }
@ -426,12 +488,17 @@ inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
return ERROR_FUNCTION_FAILED; 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 ACTION_InstallFiles(MSIPACKAGE *package)
{ {
UINT rc = ERROR_SUCCESS; UINT rc = ERROR_SUCCESS;
DWORD index; DWORD index;
MSIRECORD * uirow;
WCHAR uipath[MAX_PATH];
if (!package) if (!package)
return ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE;
@ -439,17 +506,17 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
/* increment progress bar each time action data is sent */ /* increment progress bar each time action data is sent */
ui_progress(package,1,1,0,0); ui_progress(package,1,1,0,0);
/* Pass 1 */
for (index = 0; index < package->loaded_files; index++) for (index = 0; index < package->loaded_files; index++)
{ {
WCHAR path_to_source[MAX_PATH];
MSIFILE *file; MSIFILE *file;
MSICOMPONENT* comp = NULL;
file = &package->files[index]; file = &package->files[index];
if (file->Temporary) if (file->Temporary)
continue; continue;
if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
INSTALLSTATE_LOCAL)) INSTALLSTATE_LOCAL))
{ {
@ -457,28 +524,15 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
TRACE("File %s is not scheduled for install\n", TRACE("File %s is not scheduled for install\n",
debugstr_w(file->File)); debugstr_w(file->File));
file->State = 5;
continue; continue;
} }
if ((file->State == 1) || (file->State == 2)) if ((file->State == 1) || (file->State == 2))
{ {
LPWSTR p; LPWSTR p = NULL;
MSICOMPONENT* comp = NULL;
TRACE("Installing %s\n",debugstr_w(file->File)); TRACE("Pass 1: %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;
}
create_component_directory( package, file->ComponentIndex); create_component_directory( package, file->ComponentIndex);
@ -486,39 +540,56 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
if (file->ComponentIndex >= 0) if (file->ComponentIndex >= 0)
comp = &package->components[file->ComponentIndex]; comp = &package->components[file->ComponentIndex];
else
{
ERR("No Component for file\n");
continue;
}
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
HeapFree(GetProcessHeap(),0,file->TargetPath); HeapFree(GetProcessHeap(),0,file->TargetPath);
file->TargetPath = build_directory_name(2, p, file->FileName); file->TargetPath = build_directory_name(2, p, file->FileName);
HeapFree(GetProcessHeap(),0,p); HeapFree(GetProcessHeap(),0,p);
if (file->Attributes & msidbFileAttributesNoncompressed)
{
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_to_source,
file->File);
/* 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)
{
ERR("Unable to ready media\n");
rc = ERROR_FUNCTION_FAILED;
break;
}
/*
* 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), TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
debugstr_w(file->TargetPath)); 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) if (file->Attributes & msidbFileAttributesNoncompressed)
rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
else else
@ -559,6 +630,8 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
} }
} }
/* cleanup */
ready_media_for_file(NULL, 0, NULL);
return rc; return rc;
} }
@ -608,9 +681,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
} }
if (MSI_RecordIsNull(row,4)) if (MSI_RecordIsNull(row,4))
{
strcpyW(dest_name,strrchrW(file_source,'\\')+1); strcpyW(dest_name,strrchrW(file_source,'\\')+1);
}
else else
{ {
sz=0x100; sz=0x100;