From aba6afc85eea0bad16c7478ce2a1f5cd88bda587 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 5 Mar 2010 12:26:41 +0100 Subject: [PATCH] msi: Move the implementation of the MoveFiles action to files.c. --- dlls/msi/action.c | 336 --------------------------------------------- dlls/msi/files.c | 336 +++++++++++++++++++++++++++++++++++++++++++++ dlls/msi/msipriv.h | 1 + 3 files changed, 337 insertions(+), 336 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 897e9c90278..cabd1531283 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -6266,342 +6266,6 @@ static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package ) return rc; } -#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) - -typedef struct -{ - struct list entry; - LPWSTR sourcename; - LPWSTR destname; - LPWSTR source; - LPWSTR dest; -} FILE_LIST; - -static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options) -{ - BOOL ret; - - if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY || - GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY) - { - WARN("Source or dest is directory, not moving\n"); - return FALSE; - } - - if (options == msidbMoveFileOptionsMove) - { - TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest)); - ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING); - if (!ret) - { - WARN("MoveFile failed: %d\n", GetLastError()); - return FALSE; - } - } - else - { - TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest)); - ret = CopyFileW(source, dest, FALSE); - if (!ret) - { - WARN("CopyFile failed: %d\n", GetLastError()); - return FALSE; - } - } - - return TRUE; -} - -static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename) -{ - LPWSTR path, ptr; - DWORD dirlen, pathlen; - - ptr = strrchrW(wildcard, '\\'); - dirlen = ptr - wildcard + 1; - - pathlen = dirlen + lstrlenW(filename) + 1; - path = msi_alloc(pathlen * sizeof(WCHAR)); - - lstrcpynW(path, wildcard, dirlen + 1); - lstrcatW(path, filename); - - return path; -} - -static void free_file_entry(FILE_LIST *file) -{ - msi_free(file->source); - msi_free(file->dest); - msi_free(file); -} - -static void free_list(FILE_LIST *list) -{ - while (!list_empty(&list->entry)) - { - FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry); - - list_remove(&file->entry); - free_file_entry(file); - } -} - -static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest) -{ - FILE_LIST *new, *file; - LPWSTR ptr, filename; - DWORD size; - - new = msi_alloc_zero(sizeof(FILE_LIST)); - if (!new) - return FALSE; - - new->source = strdupW(source); - ptr = strrchrW(dest, '\\') + 1; - filename = strrchrW(new->source, '\\') + 1; - - new->sourcename = filename; - - if (*ptr) - new->destname = ptr; - else - new->destname = new->sourcename; - - size = (ptr - dest) + lstrlenW(filename) + 1; - new->dest = msi_alloc(size * sizeof(WCHAR)); - if (!new->dest) - { - free_file_entry(new); - return FALSE; - } - - lstrcpynW(new->dest, dest, ptr - dest + 1); - lstrcatW(new->dest, filename); - - if (list_empty(&files->entry)) - { - list_add_head(&files->entry, &new->entry); - return TRUE; - } - - LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry) - { - if (lstrcmpW(source, file->source) < 0) - { - list_add_before(&file->entry, &new->entry); - return TRUE; - } - } - - list_add_after(&file->entry, &new->entry); - return TRUE; -} - -static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options) -{ - WIN32_FIND_DATAW wfd; - HANDLE hfile; - LPWSTR path; - BOOL res; - FILE_LIST files, *file; - DWORD size; - - hfile = FindFirstFileW(source, &wfd); - if (hfile == INVALID_HANDLE_VALUE) return FALSE; - - list_init(&files.entry); - - for (res = TRUE; res; res = FindNextFileW(hfile, &wfd)) - { - if (is_dot_dir(wfd.cFileName)) continue; - - path = wildcard_to_file(source, wfd.cFileName); - if (!path) - { - res = FALSE; - goto done; - } - - add_wildcard(&files, path, dest); - msi_free(path); - } - - /* no files match the wildcard */ - if (list_empty(&files.entry)) - goto done; - - /* only the first wildcard match gets renamed to dest */ - file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); - size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2; - file->dest = msi_realloc(file->dest, size * sizeof(WCHAR)); - if (!file->dest) - { - res = FALSE; - goto done; - } - - /* file->dest may be shorter after the reallocation, so add a NULL - * terminator. This is needed for the call to strrchrW, as there will no - * longer be a NULL terminator within the bounds of the allocation in this case. - */ - file->dest[size - 1] = '\0'; - lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname); - - while (!list_empty(&files.entry)) - { - file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); - - msi_move_file(file->source, file->dest, options); - - list_remove(&file->entry); - free_file_entry(file); - } - - res = TRUE; - -done: - free_list(&files); - FindClose(hfile); - return res; -} - -static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - LPCWSTR sourcename, component; - LPWSTR destname = NULL; - LPWSTR sourcedir = NULL, destdir = NULL; - LPWSTR source = NULL, dest = NULL; - int options; - DWORD size; - BOOL ret, wildcards; - - component = MSI_RecordGetString(rec, 2); - comp = get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - if (comp->ActionRequest != INSTALLSTATE_LOCAL && comp->ActionRequest != INSTALLSTATE_SOURCE) - { - TRACE("Component not scheduled for installation: %s\n", debugstr_w(component)); - comp->Action = comp->Installed; - return ERROR_SUCCESS; - } - comp->Action = comp->ActionRequest; - - sourcename = MSI_RecordGetString(rec, 3); - options = MSI_RecordGetInteger(rec, 7); - - sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5)); - if (!sourcedir) - goto done; - - destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6)); - if (!destdir) - goto done; - - if (!sourcename) - { - if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES) - goto done; - - source = strdupW(sourcedir); - if (!source) - goto done; - } - else - { - size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2; - source = msi_alloc(size * sizeof(WCHAR)); - if (!source) - goto done; - - lstrcpyW(source, sourcedir); - if (source[lstrlenW(source) - 1] != '\\') - lstrcatW(source, szBackSlash); - lstrcatW(source, sourcename); - } - - wildcards = strchrW(source, '*') || strchrW(source, '?'); - - if (MSI_RecordIsNull(rec, 4)) - { - if (!wildcards) - { - destname = strdupW(sourcename); - if (!destname) - goto done; - } - } - else - { - destname = strdupW(MSI_RecordGetString(rec, 4)); - if (destname) - reduce_to_longfilename(destname); - } - - size = 0; - if (destname) - size = lstrlenW(destname); - - size += lstrlenW(destdir) + 2; - dest = msi_alloc(size * sizeof(WCHAR)); - if (!dest) - goto done; - - lstrcpyW(dest, destdir); - if (dest[lstrlenW(dest) - 1] != '\\') - lstrcatW(dest, szBackSlash); - - if (destname) - lstrcatW(dest, destname); - - if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES) - { - ret = CreateDirectoryW(destdir, NULL); - if (!ret) - { - WARN("CreateDirectory failed: %d\n", GetLastError()); - return ERROR_SUCCESS; - } - } - - if (!wildcards) - msi_move_file(source, dest, options); - else - move_files_wildcard(source, dest, options); - -done: - msi_free(sourcedir); - msi_free(destdir); - msi_free(destname); - msi_free(source); - msi_free(dest); - - return ERROR_SUCCESS; -} - -static UINT ACTION_MoveFiles( MSIPACKAGE *package ) -{ - UINT rc; - MSIQUERY *view; - - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','o','v','e','F','i','l','e','`',0}; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package); - msiobj_release(&view->hdr); - - return rc; -} - typedef struct tagMSIASSEMBLY { struct list entry; diff --git a/dlls/msi/files.c b/dlls/msi/files.c index c55bbfa75f9..bf6f1faf240 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -328,6 +328,342 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) return rc; } +#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) + +typedef struct +{ + struct list entry; + LPWSTR sourcename; + LPWSTR destname; + LPWSTR source; + LPWSTR dest; +} FILE_LIST; + +static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options) +{ + BOOL ret; + + if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY || + GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY) + { + WARN("Source or dest is directory, not moving\n"); + return FALSE; + } + + if (options == msidbMoveFileOptionsMove) + { + TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest)); + ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING); + if (!ret) + { + WARN("MoveFile failed: %d\n", GetLastError()); + return FALSE; + } + } + else + { + TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest)); + ret = CopyFileW(source, dest, FALSE); + if (!ret) + { + WARN("CopyFile failed: %d\n", GetLastError()); + return FALSE; + } + } + + return TRUE; +} + +static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename) +{ + LPWSTR path, ptr; + DWORD dirlen, pathlen; + + ptr = strrchrW(wildcard, '\\'); + dirlen = ptr - wildcard + 1; + + pathlen = dirlen + lstrlenW(filename) + 1; + path = msi_alloc(pathlen * sizeof(WCHAR)); + + lstrcpynW(path, wildcard, dirlen + 1); + lstrcatW(path, filename); + + return path; +} + +static void free_file_entry(FILE_LIST *file) +{ + msi_free(file->source); + msi_free(file->dest); + msi_free(file); +} + +static void free_list(FILE_LIST *list) +{ + while (!list_empty(&list->entry)) + { + FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry); + + list_remove(&file->entry); + free_file_entry(file); + } +} + +static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest) +{ + FILE_LIST *new, *file; + LPWSTR ptr, filename; + DWORD size; + + new = msi_alloc_zero(sizeof(FILE_LIST)); + if (!new) + return FALSE; + + new->source = strdupW(source); + ptr = strrchrW(dest, '\\') + 1; + filename = strrchrW(new->source, '\\') + 1; + + new->sourcename = filename; + + if (*ptr) + new->destname = ptr; + else + new->destname = new->sourcename; + + size = (ptr - dest) + lstrlenW(filename) + 1; + new->dest = msi_alloc(size * sizeof(WCHAR)); + if (!new->dest) + { + free_file_entry(new); + return FALSE; + } + + lstrcpynW(new->dest, dest, ptr - dest + 1); + lstrcatW(new->dest, filename); + + if (list_empty(&files->entry)) + { + list_add_head(&files->entry, &new->entry); + return TRUE; + } + + LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry) + { + if (lstrcmpW(source, file->source) < 0) + { + list_add_before(&file->entry, &new->entry); + return TRUE; + } + } + + list_add_after(&file->entry, &new->entry); + return TRUE; +} + +static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options) +{ + WIN32_FIND_DATAW wfd; + HANDLE hfile; + LPWSTR path; + BOOL res; + FILE_LIST files, *file; + DWORD size; + + hfile = FindFirstFileW(source, &wfd); + if (hfile == INVALID_HANDLE_VALUE) return FALSE; + + list_init(&files.entry); + + for (res = TRUE; res; res = FindNextFileW(hfile, &wfd)) + { + if (is_dot_dir(wfd.cFileName)) continue; + + path = wildcard_to_file(source, wfd.cFileName); + if (!path) + { + res = FALSE; + goto done; + } + + add_wildcard(&files, path, dest); + msi_free(path); + } + + /* no files match the wildcard */ + if (list_empty(&files.entry)) + goto done; + + /* only the first wildcard match gets renamed to dest */ + file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); + size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2; + file->dest = msi_realloc(file->dest, size * sizeof(WCHAR)); + if (!file->dest) + { + res = FALSE; + goto done; + } + + /* file->dest may be shorter after the reallocation, so add a NULL + * terminator. This is needed for the call to strrchrW, as there will no + * longer be a NULL terminator within the bounds of the allocation in this case. + */ + file->dest[size - 1] = '\0'; + lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname); + + while (!list_empty(&files.entry)) + { + file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); + + msi_move_file(file->source, file->dest, options); + + list_remove(&file->entry); + free_file_entry(file); + } + + res = TRUE; + +done: + free_list(&files); + FindClose(hfile); + return res; +} + +static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param ) +{ + MSIPACKAGE *package = param; + MSICOMPONENT *comp; + LPCWSTR sourcename, component; + LPWSTR destname = NULL; + LPWSTR sourcedir = NULL, destdir = NULL; + LPWSTR source = NULL, dest = NULL; + int options; + DWORD size; + BOOL ret, wildcards; + + component = MSI_RecordGetString(rec, 2); + comp = get_loaded_component(package, component); + if (!comp) + return ERROR_SUCCESS; + + if (comp->ActionRequest != INSTALLSTATE_LOCAL && comp->ActionRequest != INSTALLSTATE_SOURCE) + { + TRACE("Component not scheduled for installation: %s\n", debugstr_w(component)); + comp->Action = comp->Installed; + return ERROR_SUCCESS; + } + comp->Action = comp->ActionRequest; + + sourcename = MSI_RecordGetString(rec, 3); + options = MSI_RecordGetInteger(rec, 7); + + sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5)); + if (!sourcedir) + goto done; + + destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6)); + if (!destdir) + goto done; + + if (!sourcename) + { + if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES) + goto done; + + source = strdupW(sourcedir); + if (!source) + goto done; + } + else + { + size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2; + source = msi_alloc(size * sizeof(WCHAR)); + if (!source) + goto done; + + lstrcpyW(source, sourcedir); + if (source[lstrlenW(source) - 1] != '\\') + lstrcatW(source, szBackSlash); + lstrcatW(source, sourcename); + } + + wildcards = strchrW(source, '*') || strchrW(source, '?'); + + if (MSI_RecordIsNull(rec, 4)) + { + if (!wildcards) + { + destname = strdupW(sourcename); + if (!destname) + goto done; + } + } + else + { + destname = strdupW(MSI_RecordGetString(rec, 4)); + if (destname) + reduce_to_longfilename(destname); + } + + size = 0; + if (destname) + size = lstrlenW(destname); + + size += lstrlenW(destdir) + 2; + dest = msi_alloc(size * sizeof(WCHAR)); + if (!dest) + goto done; + + lstrcpyW(dest, destdir); + if (dest[lstrlenW(dest) - 1] != '\\') + lstrcatW(dest, szBackSlash); + + if (destname) + lstrcatW(dest, destname); + + if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES) + { + ret = CreateDirectoryW(destdir, NULL); + if (!ret) + { + WARN("CreateDirectory failed: %d\n", GetLastError()); + return ERROR_SUCCESS; + } + } + + if (!wildcards) + msi_move_file(source, dest, options); + else + move_files_wildcard(source, dest, options); + +done: + msi_free(sourcedir); + msi_free(destdir); + msi_free(destname); + msi_free(source); + msi_free(dest); + + return ERROR_SUCCESS; +} + +UINT ACTION_MoveFiles( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','M','o','v','e','F','i','l','e','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package); + msiobj_release(&view->hdr); + + return rc; +} + static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const WCHAR *file_key, const WCHAR *src ) { DWORD len; diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 97d79c43716..07ee1a8871b 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -955,6 +955,7 @@ extern UINT ACTION_CCPSearch(MSIPACKAGE *package); extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); extern UINT ACTION_InstallFiles(MSIPACKAGE *package); extern UINT ACTION_RemoveFiles(MSIPACKAGE *package); +extern UINT ACTION_MoveFiles(MSIPACKAGE *package); extern UINT ACTION_DuplicateFiles(MSIPACKAGE *package); extern UINT ACTION_RemoveDuplicateFiles(MSIPACKAGE *package); extern UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);