Commit fbdd7096 authored by Aric Stewart's avatar Aric Stewart Committed by Alexandre Julliard

- Rework how we handle Feature and Component States. I have confirmed

from testing that, although documented nowhere, having ADDLOCAL on the install line overrides INSTALLLEVEL. - Track all files extracted from cabinents as tempfiles so they can be removed at the end of the install to not leave uninstalled but uncabbed files laying around.
parent ae1aa32c
...@@ -64,8 +64,10 @@ typedef struct tagMSIFEATURE ...@@ -64,8 +64,10 @@ typedef struct tagMSIFEATURE
WCHAR Directory[96]; WCHAR Directory[96];
INT Attributes; INT Attributes;
INSTALLSTATE State; INSTALLSTATE Installed;
BOOL Enabled; INSTALLSTATE ActionRequest;
INSTALLSTATE Action;
INT ComponentCount; INT ComponentCount;
INT Components[1024]; /* yes hardcoded limit.... I am bad */ INT Components[1024]; /* yes hardcoded limit.... I am bad */
INT Cost; INT Cost;
...@@ -80,8 +82,10 @@ typedef struct tagMSICOMPONENT ...@@ -80,8 +82,10 @@ typedef struct tagMSICOMPONENT
WCHAR Condition[0x100]; WCHAR Condition[0x100];
WCHAR KeyPath[96]; WCHAR KeyPath[96];
INSTALLSTATE State; INSTALLSTATE Installed;
BOOL FeatureState; INSTALLSTATE ActionRequest;
INSTALLSTATE Action;
BOOL Enabled; BOOL Enabled;
INT Cost; INT Cost;
} MSICOMPONENT; } MSICOMPONENT;
...@@ -411,7 +415,10 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) ...@@ -411,7 +415,10 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
for (i = 0; i < package->loaded_files; i++) for (i = 0; i < package->loaded_files; i++)
{ {
if (package->files[i].Temporary) if (package->files[i].Temporary)
{
TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
DeleteFileW(package->files[i].TargetPath); DeleteFileW(package->files[i].TargetPath);
}
} }
} }
...@@ -1832,9 +1839,11 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) ...@@ -1832,9 +1839,11 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row)
sz = 96; sz = 96;
MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
package->components[index].State = INSTALLSTATE_ABSENT; package->components[index].Installed = INSTALLSTATE_ABSENT;
package->components[index].Action = INSTALLSTATE_UNKNOWN;
package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
package->components[index].Enabled = TRUE; package->components[index].Enabled = TRUE;
package->components[index].FeatureState= FALSE;
return index; return index;
} }
...@@ -1894,7 +1903,10 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) ...@@ -1894,7 +1903,10 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
package->features[index].Attributes= MSI_RecordGetInteger(row,8); package->features[index].Attributes= MSI_RecordGetInteger(row,8);
package->features[index].State = INSTALLSTATE_ABSENT;
package->features[index].Installed = INSTALLSTATE_ABSENT;
package->features[index].Action = INSTALLSTATE_UNKNOWN;
package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
/* load feature components */ /* load feature components */
...@@ -2372,39 +2384,84 @@ static UINT SetFeatureStates(MSIPACKAGE *package) ...@@ -2372,39 +2384,84 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
else else
install_level = 1; install_level = 1;
override = load_dynamic_property(package,szAddLocal,NULL); /* ok hereis the rub
* ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
/* * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
* Components FeatureState defaults to FALSE. The idea is we want to * itnored for all the features. seems strange, epsecially since it is not
* enable the component is ANY feature that uses it is enabled to install * documented anywhere, but it is how it works.
*/ */
for(i = 0; i < package->loaded_features; i++)
override = load_dynamic_property(package,szAddLocal,NULL);
if (override)
{ {
BOOL feature_state= ((package->features[i].Level > 0) && for(i = 0; i < package->loaded_features; i++)
{
if (strcmpiW(override,all)==0 ||
strstrW(override,package->features[i].Feature))
{
package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
package->features[i].Action = INSTALLSTATE_LOCAL;
}
}
HeapFree(GetProcessHeap(),0,override);
}
else
{
for(i = 0; i < package->loaded_features; i++)
{
BOOL feature_state= ((package->features[i].Level > 0) &&
(package->features[i].Level <= install_level)); (package->features[i].Level <= install_level));
if (override && (strcmpiW(override,all)==0 || if (feature_state)
strstrW(override,package->features[i].Feature))) {
{ package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
TRACE("Override of install level found\n"); package->features[i].Action = INSTALLSTATE_LOCAL;
feature_state = TRUE; }
} }
package->features[i].Enabled = feature_state; }
/*
* now we want to enable or disable components base on feature
*/
for(i = 0; i < package->loaded_features; i++)
{
MSIFEATURE* feature = &package->features[i];
TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
debugstr_w(feature->Feature), feature->Installed, feature->Action,
feature->ActionRequest);
TRACE("Feature %s has a state of %i\n", for( j = 0; j < feature->ComponentCount; j++)
debugstr_w(package->features[i].Feature), feature_state);
for( j = 0; j < package->features[i].ComponentCount; j++)
{ {
package->components[package->features[i].Components[j]].FeatureState MSICOMPONENT* component = &package->components[
|= feature_state; feature->Components[j]];
if (!component->Enabled)
{
component->Action = INSTALLSTATE_ABSENT;
component->ActionRequest = INSTALLSTATE_ABSENT;
}
else
{
if (feature->Action == INSTALLSTATE_LOCAL)
component->Action = INSTALLSTATE_LOCAL;
if (feature->ActionRequest == INSTALLSTATE_LOCAL)
component->ActionRequest = INSTALLSTATE_LOCAL;
}
} }
} }
if (override)
HeapFree(GetProcessHeap(),0,override); for(i = 0; i < package->loaded_components; i++)
/* {
* So basically we ONLY want to install a component if its Enabled AND MSICOMPONENT* component= &package->components[i];
* FeatureState are both TRUE
*/ TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
debugstr_w(component->Component), component->Installed,
component->Action, component->ActionRequest);
}
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
...@@ -2686,6 +2743,11 @@ end: ...@@ -2686,6 +2743,11 @@ end:
/* Support functions for FDI functions */ /* Support functions for FDI functions */
typedef struct
{
MSIPACKAGE* package;
LPCSTR cab_path;
} CabData;
static void * cabinet_alloc(ULONG cb) static void * cabinet_alloc(ULONG cb)
{ {
...@@ -2758,14 +2820,35 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) ...@@ -2758,14 +2820,35 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{ {
case fdintCOPY_FILE: case fdintCOPY_FILE:
{ {
ULONG len = strlen((char*)pfdin->pv) + strlen(pfdin->psz1); CabData *data = (CabData*) pfdin->pv;
ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
char *file = cabinet_alloc((len+1)*sizeof(char)); char *file = cabinet_alloc((len+1)*sizeof(char));
strcpy(file, (char*)pfdin->pv); LPWSTR trackname;
LPWSTR trackpath;
LPWSTR tracknametmp;
static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
strcpy(file, data->cab_path);
strcat(file, pfdin->psz1); strcat(file, pfdin->psz1);
TRACE("file: %s\n", debugstr_a(file)); TRACE("file: %s\n", debugstr_a(file));
/* track this file so it can be deleted if not installed */
trackpath=strdupAtoW(file);
tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
strlenW(tmpprefix)+1) * sizeof(WCHAR));
strcpyW(trackname,tmpprefix);
strcatW(trackname,tracknametmp);
track_tempfile(data->package, trackname, trackpath);
HeapFree(GetProcessHeap(),0,trackpath);
HeapFree(GetProcessHeap(),0,trackname);
HeapFree(GetProcessHeap(),0,tracknametmp);
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:
...@@ -2792,13 +2875,15 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) ...@@ -2792,13 +2875,15 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
* *
* Extract files from a cab file. * Extract files from a cab file.
*/ */
static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path) static BOOL extract_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
const WCHAR* path)
{ {
HFDI hfdi; HFDI hfdi;
ERF erf; ERF erf;
BOOL ret; BOOL ret;
char *cabinet; char *cabinet;
char *cab_path; char *cab_path;
CabData data;
TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
...@@ -2829,7 +2914,10 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path) ...@@ -2829,7 +2914,10 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
return FALSE; return FALSE;
} }
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, cab_path); data.package = package;
data.cab_path = cab_path;
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
if (!ret) if (!ret)
ERR("FDICopy failed\n"); ERR("FDICopy failed\n");
...@@ -2921,7 +3009,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, ...@@ -2921,7 +3009,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
GetTempPathW(MAX_PATH,path); GetTempPathW(MAX_PATH,path);
} }
} }
rc = !extract_cabinet_file(source,path); rc = !extract_cabinet_file(package, source,path);
} }
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
MSI_ViewClose(view); MSI_ViewClose(view);
...@@ -2974,11 +3062,12 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) ...@@ -2974,11 +3062,12 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
if (file->Temporary) if (file->Temporary)
continue; continue;
if (!package->components[file->ComponentIndex].Enabled || if (package->components[file->ComponentIndex].ActionRequest !=
!package->components[file->ComponentIndex].FeatureState) INSTALLSTATE_LOCAL)
{ {
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));
continue; continue;
} }
...@@ -3127,8 +3216,8 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) ...@@ -3127,8 +3216,8 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
} }
component_index = get_loaded_component(package,component); component_index = get_loaded_component(package,component);
if (!package->components[component_index].Enabled || if (package->components[component_index].ActionRequest !=
!package->components[component_index].FeatureState) INSTALLSTATE_LOCAL)
{ {
TRACE("Skipping copy due to disabled component\n"); TRACE("Skipping copy due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
...@@ -3358,8 +3447,8 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) ...@@ -3358,8 +3447,8 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
component = load_dynamic_stringW(row, 6); component = load_dynamic_stringW(row, 6);
component_index = get_loaded_component(package,component); component_index = get_loaded_component(package,component);
if (!package->components[component_index].Enabled || if (package->components[component_index].ActionRequest !=
!package->components[component_index].FeatureState) INSTALLSTATE_LOCAL)
{ {
TRACE("Skipping write due to disabled component\n"); TRACE("Skipping write due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
...@@ -3865,8 +3954,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) ...@@ -3865,8 +3954,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
continue; continue;
} }
if (!package->components[index].Enabled || if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
!package->components[index].FeatureState)
{ {
TRACE("Skipping typelib reg due to disabled component\n"); TRACE("Skipping typelib reg due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
...@@ -4110,8 +4198,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) ...@@ -4110,8 +4198,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
continue; continue;
} }
if (!package->components[index].Enabled || if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
!package->components[index].FeatureState)
{ {
TRACE("Skipping class reg due to disabled component\n"); TRACE("Skipping class reg due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
...@@ -4471,8 +4558,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) ...@@ -4471,8 +4558,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
continue; continue;
} }
if (!package->components[index].Enabled || if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
!package->components[index].FeatureState)
{ {
TRACE("Skipping shortcut creation due to disabled component\n"); TRACE("Skipping shortcut creation due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
...@@ -5027,7 +5113,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, ...@@ -5027,7 +5113,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
if (index < 0) if (index < 0)
return ERROR_UNKNOWN_FEATURE; return ERROR_UNKNOWN_FEATURE;
package->features[index].State = iState; package->features[index].ActionRequest= iState;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
...@@ -5057,15 +5143,11 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature, ...@@ -5057,15 +5143,11 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
return ERROR_UNKNOWN_FEATURE; return ERROR_UNKNOWN_FEATURE;
if (piInstalled) if (piInstalled)
*piInstalled = package->features[index].State; *piInstalled = package->features[index].Installed;
if (piAction) if (piAction)
{ *piAction = package->features[index].Action;
if (package->features[index].Enabled)
*piAction = INSTALLSTATE_LOCAL;
else
*piAction = package->features[index].State;
}
TRACE("returning %i %i\n",*piInstalled,*piAction); TRACE("returning %i %i\n",*piInstalled,*piAction);
return ERROR_SUCCESS; return ERROR_SUCCESS;
...@@ -5116,16 +5198,10 @@ piAction); ...@@ -5116,16 +5198,10 @@ piAction);
return ERROR_UNKNOWN_COMPONENT; return ERROR_UNKNOWN_COMPONENT;
if (piInstalled) if (piInstalled)
*piInstalled = package->components[index].State; *piInstalled = package->components[index].Installed;
if (piAction) if (piAction)
{ *piInstalled = package->components[index].Action;
if (package->components[index].Enabled &&
package->components[index].FeatureState)
*piAction = INSTALLSTATE_LOCAL;
else
*piAction = INSTALLSTATE_UNKNOWN;
}
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment