From 17b05316a5a62d48cca50f416da5e7f2f14fef99 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Wed, 1 Apr 2015 12:33:11 +0200 Subject: [PATCH] msi: Clean up handling of temporary files. --- dlls/msi/action.c | 37 ++++++++++++++++----- dlls/msi/custom.c | 81 +++++++++++++++++++++++++++------------------ dlls/msi/database.c | 1 + dlls/msi/dialog.c | 29 ++-------------- dlls/msi/files.c | 49 +++++++++++++-------------- dlls/msi/msipriv.h | 9 ++--- dlls/msi/package.c | 65 +++++++++--------------------------- 7 files changed, 120 insertions(+), 151 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 4eec12ae152..e87dd7f4102 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -2107,18 +2107,38 @@ BOOL msi_file_hash_matches( MSIFILE *file ) return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) ); } -static WCHAR *get_temp_dir( void ) +static WCHAR *create_temp_dir( MSIDATABASE *db ) { static UINT id; - WCHAR tmp[MAX_PATH], dir[MAX_PATH]; + WCHAR *ret; - GetTempPathW( MAX_PATH, tmp ); - for (;;) + if (!db->tempfolder) { - if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL; - if (CreateDirectoryW( dir, NULL )) break; + WCHAR tmp[MAX_PATH]; + UINT len = sizeof(tmp)/sizeof(tmp[0]); + + if (msi_get_property( db, szTempFolder, tmp, &len ) || + GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY) + { + GetTempPathW( MAX_PATH, tmp ); + } + if (!(db->tempfolder = strdupW( tmp ))) return NULL; } - return strdupW( dir ); + + if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) ))) + { + for (;;) + { + if (!GetTempFileNameW( db->tempfolder, szMsi, ++id, ret )) + { + msi_free( ret ); + return NULL; + } + if (CreateDirectoryW( ret, NULL )) break; + } + } + + return ret; } /* @@ -2181,9 +2201,8 @@ static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) { MSIASSEMBLY *assembly = file->Component->assembly; - if (!assembly->tempdir) assembly->tempdir = get_temp_dir(); + if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db ); file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName ); - msi_track_tempfile( package, file->TargetPath ); } else { diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c index d492e19e933..4e934bdce04 100644 --- a/dlls/msi/custom.c +++ b/dlls/msi/custom.c @@ -201,6 +201,35 @@ static void set_deferred_action_props( MSIPACKAGE *package, const WCHAR *deferre msi_set_property( package->db, szProductCode, beg, end - beg ); } +WCHAR *msi_create_temp_file( MSIDATABASE *db ) +{ + WCHAR *ret; + + if (!db->tempfolder) + { + WCHAR tmp[MAX_PATH]; + UINT len = sizeof(tmp)/sizeof(tmp[0]); + + if (msi_get_property( db, szTempFolder, tmp, &len ) || + GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY) + { + GetTempPathW( MAX_PATH, tmp ); + } + if (!(db->tempfolder = strdupW( tmp ))) return NULL; + } + + if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) ))) + { + if (!GetTempFileNameW( db->tempfolder, szMsi, 0, ret )) + { + msi_free( ret ); + return NULL; + } + } + + return ret; +} + static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll ) { static const WCHAR query[] = { @@ -208,38 +237,21 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ', '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0}; MSIRECORD *row; - MSIBINARY *binary; + MSIBINARY *binary = NULL; HANDLE file; CHAR buffer[1024]; - WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH]; - DWORD sz = MAX_PATH, write; + WCHAR *tmpfile; + DWORD sz, write; UINT r; - if (msi_get_property(package->db, szTempFolder, fmt, &sz) != ERROR_SUCCESS || - GetFileAttributesW(fmt) == INVALID_FILE_ATTRIBUTES) GetTempPathW(MAX_PATH, fmt); + if (!(tmpfile = msi_create_temp_file( package->db ))) return NULL; - if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile )) - { - TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError()); - return NULL; - } + if (!(row = MSI_QueryGetRecord( package->db, query, source ))) goto error; + if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) goto error; - row = MSI_QueryGetRecord(package->db, query, source); - if (!row) - return NULL; + file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if (file == INVALID_HANDLE_VALUE) goto error; - if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) - { - msiobj_release( &row->hdr ); - return NULL; - } - file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - if (file == INVALID_HANDLE_VALUE) - { - msiobj_release( &row->hdr ); - msi_free( binary ); - return NULL; - } do { sz = sizeof(buffer); @@ -253,13 +265,7 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL } while (sz == sizeof buffer); CloseHandle( file ); - msiobj_release( &row->hdr ); - if (r != ERROR_SUCCESS) - { - DeleteFileW( tmpfile ); - msi_free( binary ); - return NULL; - } + if (r != ERROR_SUCCESS) goto error; /* keep a reference to prevent the dll from being unloaded */ if (dll && !(binary->module = LoadLibraryW( tmpfile ))) @@ -267,9 +273,18 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() ); } binary->source = strdupW( source ); - binary->tmpfile = strdupW( tmpfile ); + binary->tmpfile = tmpfile; list_add_tail( &package->binaries, &binary->entry ); + + msiobj_release( &row->hdr ); return binary; + +error: + if (row) msiobj_release( &row->hdr ); + DeleteFileW( tmpfile ); + msi_free( tmpfile ); + msi_free( binary ); + return NULL; } static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll ) diff --git a/dlls/msi/database.c b/dlls/msi/database.c index 18e1445558b..32e5a635350 100644 --- a/dlls/msi/database.c +++ b/dlls/msi/database.c @@ -99,6 +99,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) DeleteFileW( db->deletefile ); msi_free( db->deletefile ); } + msi_free( db->tempfolder ); } static HRESULT db_initialize( IStorage *stg, const GUID *clsid ) diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c index 6baf08ddd5e..0b81951a9f5 100644 --- a/dlls/msi/dialog.c +++ b/dlls/msi/dialog.c @@ -495,42 +495,17 @@ static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) return MSI_QueryGetRecord( db, query, name ); } -static LPWSTR msi_create_tmp_path(void) -{ - WCHAR tmp[MAX_PATH]; - LPWSTR path = NULL; - DWORD len, r; - - r = GetTempPathW( MAX_PATH, tmp ); - if( !r ) - return path; - len = lstrlenW( tmp ) + 20; - path = msi_alloc( len * sizeof (WCHAR) ); - if( path ) - { - r = GetTempFileNameW( tmp, szMsi, 0, path ); - if (!r) - { - msi_free( path ); - path = NULL; - } - } - return path; -} - static HANDLE msi_load_image( MSIDATABASE *db, LPCWSTR name, UINT type, UINT cx, UINT cy, UINT flags ) { - MSIRECORD *rec = NULL; + MSIRECORD *rec; HANDLE himage = NULL; LPWSTR tmp; UINT r; TRACE("%p %s %u %u %08x\n", db, debugstr_w(name), cx, cy, flags); - tmp = msi_create_tmp_path(); - if( !tmp ) - return himage; + if (!(tmp = msi_create_temp_file( db ))) return NULL; rec = msi_get_binary_record( db, name ); if( rec ) diff --git a/dlls/msi/files.c b/dlls/msi/files.c index fb56a6d70c9..b6833e9ec54 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -275,33 +275,33 @@ static MSIFILE *find_file( MSIPACKAGE *package, UINT disk_id, const WCHAR *filen return NULL; } -static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action, +static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR filename, DWORD action, LPWSTR *path, DWORD *attrs, PVOID user) { - static MSIFILE *f = NULL; + static MSIFILE *file = NULL; UINT_PTR disk_id = (UINT_PTR)user; if (action == MSICABEXTRACT_BEGINEXTRACT) { - if (!(f = find_file( package, disk_id, file ))) + if (!(file = find_file( package, disk_id, filename ))) { - TRACE("unknown file in cabinet (%s)\n", debugstr_w(file)); + TRACE("unknown file in cabinet (%s)\n", debugstr_w(filename)); return FALSE; } - if (f->disk_id != disk_id || (f->state != msifs_missing && f->state != msifs_overwrite)) + if (file->state != msifs_missing && file->state != msifs_overwrite) return FALSE; - if (!msi_is_global_assembly( f->Component )) + if (!msi_is_global_assembly( file->Component )) { - msi_create_directory(package, f->Component->Directory); + msi_create_directory( package, file->Component->Directory ); } - *path = strdupW(f->TargetPath); - *attrs = f->Attributes; + *path = strdupW( file->TargetPath ); + *attrs = file->Attributes; } else if (action == MSICABEXTRACT_FILEEXTRACTED) { - if (!msi_is_global_assembly( f->Component )) f->state = msifs_installed; - f = NULL; + if (!msi_is_global_assembly( file->Component )) file->state = msifs_installed; + file = NULL; } return TRUE; @@ -378,8 +378,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) data.cb = installfiles_cb; data.user = (PVOID)(UINT_PTR)mi->disk_id; - if (file->IsCompressed && - !msi_cabextract(package, mi, &data)) + if (file->IsCompressed && !msi_cabextract(package, mi, &data)) { ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet)); rc = ERROR_INSTALL_FAILURE; @@ -419,8 +418,8 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) { MSICOMPONENT *comp = file->Component; - if (!msi_is_global_assembly( comp ) || (file->state != msifs_missing && file->state != msifs_overwrite)) - continue; + if (!msi_is_global_assembly( comp ) || comp->assembly->installed || + (file->state != msifs_missing && file->state != msifs_overwrite)) continue; rc = msi_install_assembly( package, comp ); if (rc != ERROR_SUCCESS) @@ -453,22 +452,18 @@ static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action, LPWSTR *path, DWORD *attrs, PVOID user) { static MSIFILEPATCH *patch; - static WCHAR tmpfile[MAX_PATH], tmpdir[MAX_PATH]; UINT_PTR disk_id = (UINT_PTR)user; - if (!tmpdir[0]) GetTempPathW( MAX_PATH, tmpdir ); - if (action == MSICABEXTRACT_BEGINEXTRACT) { if (!(patch = find_filepatch( package, disk_id, file ))) return FALSE; - GetTempFileNameW( tmpdir, NULL, 0, tmpfile ); - *path = strdupW( tmpfile ); + patch->path = msi_create_temp_file( package->db ); + *path = strdupW( patch->path ); *attrs = patch->File->Attributes; } else if (action == MSICABEXTRACT_FILEEXTRACTED) { - patch->path = strdupW( tmpfile ); patch->extracted = TRUE; patch = NULL; } @@ -531,14 +526,16 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package ) LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) { - WCHAR tmpdir[MAX_PATH], tmpfile[MAX_PATH]; + WCHAR *tmpfile; BOOL ret; if (!patch->path) continue; - GetTempPathW( MAX_PATH, tmpdir ); - GetTempFileNameW( tmpdir, NULL, 0, tmpfile ); - + if (!(tmpfile = msi_create_temp_file( package->db ))) + { + rc = ERROR_INSTALL_FAILURE; + goto done; + } ret = ApplyPatchToFileW( patch->path, patch->File->TargetPath, tmpfile, 0 ); if (ret) { @@ -550,7 +547,7 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package ) DeleteFileW( patch->path ); DeleteFileW( tmpfile ); - RemoveDirectoryW( tmpdir ); + msi_free( tmpfile ); if (!ret && !(patch->Attributes & msidbPatchAttributesNonVital)) { diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 9c016f373f3..5a8c24f2f3c 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -100,6 +100,7 @@ typedef struct tagMSIDATABASE UINT bytes_per_strref; LPWSTR path; LPWSTR deletefile; + LPWSTR tempfolder; LPCWSTR mode; UINT media_transform_offset; UINT media_transform_disk_id; @@ -580,12 +581,6 @@ typedef struct tagMSIFILE UINT disk_id; } MSIFILE; -typedef struct tagMSITEMPFILE -{ - struct list entry; - LPWSTR Path; -} MSITEMPFILE; - typedef struct tagMSIFILEPATCH { struct list entry; @@ -1025,7 +1020,7 @@ extern MSICOMPONENT *msi_get_loaded_component(MSIPACKAGE *package, const WCHAR * extern MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE *package, const WCHAR *Feature) DECLSPEC_HIDDEN; extern MSIFILE *msi_get_loaded_file(MSIPACKAGE *package, const WCHAR *file) DECLSPEC_HIDDEN; extern MSIFOLDER *msi_get_loaded_folder(MSIPACKAGE *package, const WCHAR *dir) DECLSPEC_HIDDEN; -extern int msi_track_tempfile(MSIPACKAGE *package, const WCHAR *path) DECLSPEC_HIDDEN; +extern WCHAR *msi_create_temp_file(MSIDATABASE *db) DECLSPEC_HIDDEN; extern void msi_free_action_script(MSIPACKAGE *package, UINT script) DECLSPEC_HIDDEN; extern WCHAR *msi_build_icon_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN; extern WCHAR *msi_build_directory_name(DWORD , ...) DECLSPEC_HIDDEN; diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 1053053cdfe..7ab2b19d8af 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -49,22 +49,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -static void remove_tracked_tempfiles( MSIPACKAGE *package ) -{ - struct list *item, *cursor; - - LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles ) - { - MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry ); - - list_remove( &temp->entry ); - TRACE("deleting temp file %s\n", debugstr_w( temp->Path )); - DeleteFileW( temp->Path ); - msi_free( temp->Path ); - msi_free( temp ); - } -} - static void free_feature( MSIFEATURE *feature ) { struct list *item, *cursor; @@ -170,6 +154,22 @@ static void free_package_structures( MSIPACKAGE *package ) free_folder( folder ); } + LIST_FOR_EACH_SAFE( item, cursor, &package->files ) + { + MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry ); + + list_remove( &file->entry ); + msi_free( file->File ); + msi_free( file->FileName ); + msi_free( file->ShortName ); + msi_free( file->LongName ); + msi_free( file->Version ); + msi_free( file->Language ); + if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath ); + msi_free( file->TargetPath ); + msi_free( file ); + } + LIST_FOR_EACH_SAFE( item, cursor, &package->components ) { MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry ); @@ -185,21 +185,6 @@ static void free_package_structures( MSIPACKAGE *package ) msi_free( comp ); } - LIST_FOR_EACH_SAFE( item, cursor, &package->files ) - { - MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry ); - - list_remove( &file->entry ); - msi_free( file->File ); - msi_free( file->FileName ); - msi_free( file->ShortName ); - msi_free( file->LongName ); - msi_free( file->Version ); - msi_free( file->Language ); - msi_free( file->TargetPath ); - msi_free( file ); - } - LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches ) { MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry ); @@ -347,8 +332,6 @@ static void free_package_structures( MSIPACKAGE *package ) msi_free( package->LastAction ); msi_free( package->langids ); - remove_tracked_tempfiles(package); - /* cleanup control event subscriptions */ msi_event_cleanup_all_subscriptions( package ); } @@ -1329,22 +1312,6 @@ static UINT validate_package( MSIPACKAGE *package ) return ERROR_INSTALL_LANGUAGE_UNSUPPORTED; } -int msi_track_tempfile( MSIPACKAGE *package, const WCHAR *path ) -{ - MSITEMPFILE *temp; - - TRACE("%s\n", debugstr_w(path)); - - LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry ) - { - if (!strcmpW( path, temp->Path )) return 0; - } - if (!(temp = msi_alloc_zero( sizeof (MSITEMPFILE) ))) return -1; - list_add_head( &package->tempfiles, &temp->entry ); - temp->Path = strdupW( path ); - return 0; -} - static WCHAR *get_product_code( MSIDATABASE *db ) { static const WCHAR query[] = {