diff --git a/dlls/msi/files.c b/dlls/msi/files.c index 521cdb3a9fb..f8268066327 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -435,9 +435,99 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package) return rc; } +static BOOL verify_comp_for_removal(MSICOMPONENT *comp, UINT install_mode) +{ + INSTALLSTATE request = comp->ActionRequest; + + if (install_mode == msidbRemoveFileInstallModeOnInstall && + (request == INSTALLSTATE_LOCAL || request == INSTALLSTATE_SOURCE)) + return TRUE; + + if (request == INSTALLSTATE_ABSENT) + { + if (!comp->ComponentId) + return FALSE; + + if (install_mode == msidbRemoveFileInstallModeOnRemove) + return TRUE; + } + + if (install_mode == msidbRemoveFileInstallModeOnBoth) + return TRUE; + + return FALSE; +} + +static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + MSICOMPONENT *comp; + LPCWSTR component, filename, dirprop; + UINT install_mode; + LPWSTR dir = NULL, path = NULL; + DWORD size; + UINT r; + + component = MSI_RecordGetString(row, 2); + filename = MSI_RecordGetString(row, 3); + dirprop = MSI_RecordGetString(row, 4); + install_mode = MSI_RecordGetInteger(row, 5); + + comp = get_loaded_component(package, component); + if (!comp) + { + ERR("Invalid component: %s\n", debugstr_w(component)); + return ERROR_FUNCTION_FAILED; + } + + if (!verify_comp_for_removal(comp, install_mode)) + { + TRACE("Skipping removal due to missing conditions\n"); + comp->Action = comp->Installed; + return ERROR_SUCCESS; + } + + dir = msi_dup_property(package, dirprop); + if (!dir) + return ERROR_OUTOFMEMORY; + + size = lstrlenW(filename) + lstrlenW(dir) + 2; + path = msi_alloc(size * sizeof(WCHAR)); + if (!path) + { + r = ERROR_OUTOFMEMORY; + goto done; + } + + lstrcpyW(path, dir); + lstrcatW(path, filename); + + TRACE("Deleting misc file: %s\n", debugstr_w(path)); + if (!DeleteFileW(path)) + TRACE("DeleteFileW failed: %d\n", GetLastError()); + +done: + msi_free(path); + msi_free(dir); + return ERROR_SUCCESS; +} + UINT ACTION_RemoveFiles( MSIPACKAGE *package ) { + MSIQUERY *view; MSIFILE *file; + UINT r; + + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','R','e','m','o','v','e','F','i','l','e','`',0}; + + r = MSI_DatabaseOpenViewW(package->db, query, &view); + if (r == ERROR_SUCCESS) + { + MSI_IterateRecords(view, NULL, ITERATE_RemoveFiles, package); + msiobj_release(&view->hdr); + } LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) { diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index 04f9e4be331..a60b3abfde2 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -4206,19 +4206,16 @@ static void test_removefiles(void) ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); ok(!pf_exists("msitest\\helium"), "File installed\n"); ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(!pf_exists("msitest\\furlong"), "File not deleted\n"); + ok(!pf_exists("msitest\\firkin"), "File not deleted\n"); + ok(!pf_exists("msitest\\fortnight"), "File not deleted\n"); ok(pf_exists("msitest\\becquerel"), "File not installed\n"); ok(pf_exists("msitest\\dioptre"), "File not installed\n"); ok(pf_exists("msitest\\attoparsec"), "File not installed\n"); + ok(!pf_exists("msitest\\storeys"), "File not deleted\n"); + ok(!pf_exists("msitest\\block"), "File not deleted\n"); + ok(!pf_exists("msitest\\siriometer"), "File not deleted\n"); ok(pf_exists("msitest"), "File not installed\n"); - todo_wine - { - ok(!pf_exists("msitest\\firkin"), "File not deleted\n"); - ok(!pf_exists("msitest\\fortnight"), "File not deleted\n"); - ok(!pf_exists("msitest\\furlong"), "File not deleted\n"); - ok(!pf_exists("msitest\\storeys"), "File not deleted\n"); - ok(!pf_exists("msitest\\block"), "File not deleted\n"); - ok(!pf_exists("msitest\\siriometer"), "File not deleted\n"); - } create_pf("msitest\\furlong", TRUE); create_pf("msitest\\firkin", TRUE); @@ -4235,15 +4232,12 @@ static void test_removefiles(void) ok(delete_pf("msitest\\furlong", TRUE), "File deleted\n"); ok(delete_pf("msitest\\firkin", TRUE), "File deleted\n"); ok(delete_pf("msitest\\fortnight", TRUE), "File deleted\n"); + ok(!delete_pf("msitest\\becquerel", TRUE), "File not deleted\n"); + ok(!delete_pf("msitest\\dioptre", TRUE), "File not deleted\n"); ok(delete_pf("msitest\\attoparsec", TRUE), "File deleted\n"); + ok(!delete_pf("msitest\\storeys", TRUE), "File not deleted\n"); + ok(!delete_pf("msitest\\block", TRUE), "File not deleted\n"); ok(delete_pf("msitest\\siriometer", TRUE), "File deleted\n"); - todo_wine - { - ok(!delete_pf("msitest\\becquerel", TRUE), "File not deleted\n"); - ok(!delete_pf("msitest\\dioptre", TRUE), "File not deleted\n"); - ok(!delete_pf("msitest\\storeys", TRUE), "File not deleted\n"); - ok(!delete_pf("msitest\\block", TRUE), "File not deleted\n"); - } ok(delete_pf("msitest", FALSE), "File deleted\n"); DeleteFile(msifile); diff --git a/include/msidefs.h b/include/msidefs.h index 141e2034b2a..d87569f61c6 100644 --- a/include/msidefs.h +++ b/include/msidefs.h @@ -215,6 +215,13 @@ enum msidbSumInfoSourceType msidbSumInfoSourceTypeLUAPackage = 0x00000008, }; +enum msidbRemoveFileInstallMode +{ + msidbRemoveFileInstallModeOnInstall = 0x00000001, + msidbRemoveFileInstallModeOnRemove = 0x00000002, + msidbRemoveFileInstallModeOnBoth = 0x00000003, +}; + /* * Windows SDK braindamage alert *