From: Hans Leidekker hans@codeweavers.com
--- dlls/msi/action.c | 176 ++++++++++++++++++++++++++++++++++++++- dlls/msi/files.c | 12 +-- dlls/msi/msipriv.h | 4 + dlls/msi/suminfo.c | 38 ++++----- dlls/msi/tests/install.c | 11 +-- 5 files changed, 207 insertions(+), 34 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 63f2e382b27..d5e3af9cdba 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -2172,6 +2172,14 @@ static WCHAR *get_install_location( MSIPACKAGE *package ) return path; }
+static BOOL is_admin_install( MSIPACKAGE *package ) +{ + WCHAR *action = msi_dup_property( package->db, L"ACTION" ); + BOOL ret = (action && !wcscmp( action, L"ADMIN" )); + free( action ); + return ret; +} + void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop ) { FolderList *fl; @@ -2189,6 +2197,7 @@ void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL loa { path = msi_dup_property( package->db, L"ROOTDRIVE" ); } + if (is_admin_install( package )) load_prop = FALSE; } else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory ))) { @@ -7251,12 +7260,175 @@ static UINT ACTION_DisableRollback( MSIPACKAGE *package ) return ERROR_SUCCESS; }
-static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package ) +static UINT admin_remove_cabinet_streams( MSIPACKAGE *package ) +{ + WCHAR decoded[MAX_STREAM_NAME_LEN + 1]; + IEnumSTATSTG *iter = NULL; + STATSTG stat; + ULONG count; + UINT r = ERROR_SUCCESS; + HRESULT hr; + + hr = IStorage_EnumElements( package->db->storage, 0, NULL, 0, &iter ); + if (FAILED( hr )) return ERROR_FUNCTION_FAILED; + + for (;;) + { + count = 0; + hr = IEnumSTATSTG_Next( iter, 1, &stat, &count ); + if (FAILED( hr ) || !count) break; + + if (stat.type != STGTY_STREAM || *stat.pwcsName != 0x4176) + { + CoTaskMemFree( stat.pwcsName ); + continue; + } + + decode_streamname( stat.pwcsName, decoded ); + TRACE( "removing cabinet stream %s\n", debugstr_w(decoded) ); + + hr = IStorage_DestroyElement( package->db->storage, stat.pwcsName ); + if (FAILED( hr )) WARN( "failed to remove stream %08lx\n", hr ); + CoTaskMemFree( stat.pwcsName ); + } + + IEnumSTATSTG_Release( iter ); + return r; +} + +static UINT admin_update_package_info( MSIPACKAGE *package ) +{ + MSISUMMARYINFO *info = NULL; + UINT r, type; + int flags; + + if ((r = msi_get_suminfo( package->db->storage, 0, &info ))) return r; + if ((r = msi_suminfo_get_prop( info, PID_WORDCOUNT, &type, &flags, NULL, NULL, NULL ))) goto done; + + flags &= ~msidbSumInfoSourceTypeCompressed; + flags |= msidbSumInfoSourceTypeAdminImage; + + if ((r = msi_suminfo_set_prop( info, PID_WORDCOUNT, type, flags, NULL, NULL ))) goto done; + if ((r = msi_suminfo_persist( info ))) goto done; + +done: + msiobj_release( &info->hdr ); + return r; +} + +static BOOL remove_path( MSIPACKAGE *package, const WCHAR *path ) +{ + WCHAR *p, *copy = wcsdup( path ); + BOOL ret = FALSE; + + if (!copy) return FALSE; + for (p = copy + wcslen( copy ); p >= copy; p--) + { + if (*p != '\') continue; + *p = 0; + if (!(ret = msi_remove_directory( package, copy ))) break; + } + free( copy ); + return ret; +} + +static UINT admin_create_dest_file( MSIPACKAGE *package, WCHAR **ret_filename ) { - FIXME("%p\n", package); + WCHAR *filename, *path; + const WCHAR *ptr; + HANDLE handle; + + if (!(path = msi_dup_property( package->db, L"TARGETDIR" ))) return ERROR_FUNCTION_FAILED; + if (!msi_create_full_path( package, path )) + { + free( path ); + return ERROR_FUNCTION_FAILED; + } + + if (!(ptr = wcsrchr( package->PackagePath, '\' )) && !(ptr = wcsrchr( package->PackagePath, '/' ))) + { + remove_path( package, path ); + free( path ); + return ERROR_FUNCTION_FAILED; + } + ptr++; + + if (!(filename = malloc( (wcslen(path) + wcslen(ptr) + 1) * sizeof(WCHAR) ))) + { + remove_path( package, path ); + free( path ); + return ERROR_OUTOFMEMORY; + } + + wcscpy( filename, path ); + wcscat( filename, ptr ); + handle = msi_create_file( package, filename, GENERIC_READ|GENERIC_WRITE, 0, CREATE_NEW, 0 ); + if (handle == INVALID_HANDLE_VALUE) + { + WARN( "failed to create file %lu\n", GetLastError() ); + remove_path( package, path ); + free( path ); + free( filename ); + return ERROR_FUNCTION_FAILED; + } + CloseHandle( handle ); + + free( path ); + *ret_filename = filename; return ERROR_SUCCESS; }
+static UINT admin_copy_package( MSIPACKAGE *package, const WCHAR *filename ) +{ + UINT r = ERROR_FUNCTION_FAILED; + IStorage *storage = NULL; + HRESULT hr; + + hr = IStorage_Commit( package->db->storage, 0 ); + if (FAILED( hr )) return ERROR_FUNCTION_FAILED; + + hr = StgCreateDocfile( filename, STGM_CREATE|STGM_TRANSACTED|STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, &storage ); + if (FAILED( hr )) return ERROR_FUNCTION_FAILED; + + hr = IStorage_CopyTo( package->db->storage, 0, NULL, NULL, storage ); + if (FAILED( hr )) goto done; + + hr = IStorage_Commit( storage, 0 ); + if (FAILED( hr )) goto done; + + r = ERROR_SUCCESS; + +done: + IStorage_Release( storage ); + return r; +} + +static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package ) +{ + WCHAR temppath[MAX_PATH], tempfile[MAX_PATH], *filename = NULL; + MSIPACKAGE *admin = NULL; + UINT r = ERROR_FUNCTION_FAILED; + + TRACE("%p\n", package); + + GetTempPathW( ARRAY_SIZE(temppath), temppath ); + if (!msi_get_temp_file_name( package, temppath, L"msi", tempfile )) return ERROR_FUNCTION_FAILED; + if (!msi_copy_file( package, package->localfile, tempfile, FALSE )) goto done; + if ((r = MSI_OpenPackageW( tempfile, 0, &admin ))) goto done; + if ((r = admin_remove_cabinet_streams( admin ))) goto done; + if ((r = admin_update_package_info( admin ))) goto done; + if ((r = admin_create_dest_file( package, &filename ))) goto done; + if ((r = admin_copy_package( admin, filename ))) goto done; + + r = ERROR_SUCCESS; + +done: + if (admin) msiobj_release( &admin->hdr ); + DeleteFileW( tempfile ); + free( filename ); + return r; +} + static UINT ACTION_SetODBCFolders( MSIPACKAGE *package ) { MSIQUERY *view; diff --git a/dlls/msi/files.c b/dlls/msi/files.c index 96c6c5eaa4b..35166788dae 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -67,7 +67,7 @@ HANDLE msi_create_file( MSIPACKAGE *package, const WCHAR *filename, DWORD access return handle; }
-static BOOL copy_file( MSIPACKAGE *package, const WCHAR *src, const WCHAR *dst, BOOL fail_if_exists ) +BOOL msi_copy_file( MSIPACKAGE *package, const WCHAR *src, const WCHAR *dst, BOOL fail_if_exists ) { BOOL ret; msi_disable_fs_redirection( package ); @@ -405,7 +405,7 @@ static UINT copy_file_attributes( MSIPACKAGE *package, MSIFILE *file, WCHAR *sou { BOOL ret;
- ret = copy_file( package, source, file->TargetPath, FALSE ); + ret = msi_copy_file( package, source, file->TargetPath, FALSE ); if (!ret) return GetLastError();
@@ -453,7 +453,7 @@ static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source) if (!GetTempFileNameW( pathW, L"msi", 0, tmpfileW )) tmpfileW[0] = 0; free( pathW );
- if (copy_file( package, source, tmpfileW, FALSE ) && + if (msi_copy_file( package, source, tmpfileW, FALSE ) && msi_move_file( package, file->TargetPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT ) && msi_move_file( package, tmpfileW, file->TargetPath, MOVEFILE_DELAY_UNTIL_REBOOT )) { @@ -751,7 +751,7 @@ UINT msi_patch_assembly( MSIPACKAGE *package, MSIASSEMBLY *assembly, MSIFILEPATC
if ((path = msi_get_assembly_path( package, displayname ))) { - if (!copy_file( package, path, patch->File->TargetPath, FALSE )) + if (!msi_copy_file( package, path, patch->File->TargetPath, FALSE )) { ERR( "failed to copy file %s -> %s (%lu)\n", debugstr_w(path), debugstr_w(patch->File->TargetPath), GetLastError() ); @@ -884,7 +884,7 @@ static BOOL move_file( MSIPACKAGE *package, const WCHAR *source, const WCHAR *de else { TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest)); - ret = copy_file( package, source, dest, FALSE ); + ret = msi_copy_file( package, source, dest, FALSE ); if (!ret) { WARN( "copy_file failed: %lu\n", GetLastError() ); @@ -1294,7 +1294,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) }
TRACE("Duplicating file %s to %s\n", debugstr_w(file->TargetPath), debugstr_w(dest)); - if (!copy_file( package, file->TargetPath, dest, TRUE )) + if (!msi_copy_file( package, file->TargetPath, dest, TRUE )) { WARN( "failed to copy file %s -> %s (%lu)\n", debugstr_w(file->TargetPath), debugstr_w(dest), GetLastError() ); diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 70d2a4d6705..bfc1c1c0b4c 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -982,6 +982,9 @@ extern WCHAR *msi_get_suminfo_product( IStorage *stg ) __WINE_DEALLOC(free) __WI extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ); extern UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle ); extern UINT msi_load_suminfo_properties( MSIPACKAGE *package ); +extern UINT msi_suminfo_persist( MSISUMMARYINFO * ); +extern UINT msi_suminfo_get_prop( MSISUMMARYINFO *, UINT, UINT *, INT *, FILETIME *, awstring *, DWORD * ); +extern UINT msi_suminfo_set_prop( MSISUMMARYINFO *, UINT, UINT, INT, FILETIME *, awcstring * );
/* undocumented functions */ UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD ); @@ -1090,6 +1093,7 @@ static inline void msi_revert_fs_redirection( MSIPACKAGE *package ) } extern BOOL msi_get_temp_file_name( MSIPACKAGE *, const WCHAR *, const WCHAR *, WCHAR * ); extern HANDLE msi_create_file( MSIPACKAGE *, const WCHAR *, DWORD, DWORD, DWORD, DWORD ); +extern BOOL msi_copy_file( MSIPACKAGE *, const WCHAR *, const WCHAR *, BOOL ); extern BOOL msi_delete_file( MSIPACKAGE *, const WCHAR * ); extern BOOL msi_remove_directory( MSIPACKAGE *, const WCHAR * ); extern DWORD msi_get_file_attributes( MSIPACKAGE *, const WCHAR * ); diff --git a/dlls/msi/suminfo.c b/dlls/msi/suminfo.c index 93ecc9f5e04..b1934cf41c7 100644 --- a/dlls/msi/suminfo.c +++ b/dlls/msi/suminfo.c @@ -628,8 +628,8 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount( MSIHANDLE hSummaryInfo, UINT *pCount return ERROR_SUCCESS; }
-static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue, - FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) +UINT msi_suminfo_get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue, + FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) { PROPVARIANT *prop; UINT ret = ERROR_SUCCESS; @@ -770,7 +770,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT str.unicode = FALSE; str.str.a = szValueBuf;
- r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); + r = msi_suminfo_get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); msiobj_release( &si->hdr ); return r; } @@ -819,7 +819,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT str.unicode = TRUE; str.str.w = szValueBuf;
- r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); + r = msi_suminfo_get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); msiobj_release( &si->hdr ); return r; } @@ -878,17 +878,17 @@ static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type, return ERROR_SUCCESS; }
-static UINT suminfo_set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT uiDataType, INT iValue, FILETIME *pftValue, - awcstring *str ) +UINT msi_suminfo_set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT uiDataType, INT iValue, FILETIME *pftValue, + awcstring *str ) { UINT type = get_type( uiProperty ); - if( type == VT_EMPTY || type != uiDataType ) + if (type == VT_EMPTY || type != uiDataType) return ERROR_DATATYPE_MISMATCH;
- if( uiDataType == VT_LPSTR && !str->str.a ) + if (uiDataType == VT_LPSTR && !str->str.a) return ERROR_INVALID_PARAMETER;
- if( uiDataType == VT_FILETIME && !pftValue ) + if (uiDataType == VT_FILETIME && !pftValue) return ERROR_INVALID_PARAMETER;
return set_prop( si, uiProperty, type, iValue, pftValue, str ); @@ -919,7 +919,7 @@ UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT str.unicode = TRUE; str.str.w = szValue;
- ret = suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); + ret = msi_suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); msiobj_release( &si->hdr ); return ret; } @@ -949,12 +949,12 @@ UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT str.unicode = FALSE; str.str.a = szValue;
- ret = suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); + ret = msi_suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); msiobj_release( &si->hdr ); return ret; }
-static UINT suminfo_persist( MSISUMMARYINFO *si ) +UINT msi_suminfo_persist( MSISUMMARYINFO *si ) { UINT ret = ERROR_FUNCTION_FAILED; IStream *stm = NULL; @@ -1087,7 +1087,7 @@ UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int nu
end: if (r == ERROR_SUCCESS) - r = suminfo_persist( si ); + r = msi_suminfo_persist( si );
msiobj_release( &si->hdr ); return r; @@ -1110,7 +1110,7 @@ static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row ) str.unicode = FALSE; str.str.a = NULL; len = 0; - r = get_prop( si, row, &data_type, &int_value, &file_time, &str, &len ); + r = msi_suminfo_get_prop( si, row, &data_type, &int_value, &file_time, &str, &len ); if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) return r; if (data_type == VT_EMPTY) @@ -1131,7 +1131,7 @@ static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row ) len++; if (!(str.str.a = malloc( len ))) return ERROR_OUTOFMEMORY; - r = get_prop( si, row, NULL, NULL, NULL, &str, &len ); + r = msi_suminfo_get_prop( si, row, NULL, NULL, NULL, &str, &len ); if (r != ERROR_SUCCESS) { free( str.str.a ); @@ -1212,7 +1212,7 @@ UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle ) if( !si ) return ERROR_INVALID_HANDLE;
- ret = suminfo_persist( si ); + ret = msi_suminfo_persist( si );
msiobj_release( &si->hdr ); return ret; @@ -1264,7 +1264,7 @@ UINT msi_load_suminfo_properties( MSIPACKAGE *package ) str.unicode = TRUE; str.str.w = NULL; len = 0; - r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); + r = msi_suminfo_get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); if (r != ERROR_MORE_DATA) { WARN("Unable to query revision number %u\n", r); @@ -1276,7 +1276,7 @@ UINT msi_load_suminfo_properties( MSIPACKAGE *package ) if (!(package_code = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; str.str.w = package_code;
- r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); + r = msi_suminfo_get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); if (r != ERROR_SUCCESS) { free( package_code ); @@ -1288,7 +1288,7 @@ UINT msi_load_suminfo_properties( MSIPACKAGE *package ) free( package_code );
count = 0; - get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL ); + msi_suminfo_get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL ); package->WordCount = count;
msiobj_release( &si->hdr ); diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index 0d1af5449b5..c3d0ed2d16b 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -3875,13 +3875,10 @@ static void test_admin(void)
r = MsiInstallProductA(msifile, "ACTION=ADMIN"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); - todo_wine - { - ok(!delete_pf("msitest\augustus", TRUE), "File installed\n"); - ok(!delete_pf("msitest", FALSE), "Directory created\n"); - ok(DeleteFileA("c:\msitest\augustus"), "File not installed\n"); - ok(RemoveDirectoryA("c:\msitest"), "File not installed\n"); - } + ok(!delete_pf("msitest\augustus", TRUE), "File installed\n"); + ok(!delete_pf("msitest", FALSE), "Directory created\n"); + ok(DeleteFileA("c:\msitest\augustus"), "File not installed\n"); + ok(RemoveDirectoryA("c:\msitest"), "File not installed\n");
error: DeleteFileA(msifile);