This patch adds a simple structure to contain commonly-requested file properties (named `struct fileops_file_data`, wondering whether that name should that change?)
Functions added:
-void printFileData(): debugging function, printing contents of a `struct fileops_file_data` thing; -int shfileops_delete_file() function to delete given file -- making sure to call the right functions for either a regular file or a directory -int shfileop_unmasked_setup() the extracted code common for move and copy calls -int shfileop_move_unmasked the specific code on moving unmasked -- this one does a lot of recursion on SHFileOperationW -int shfileop_copy_unmasked the specific code on copying unmasked -- this one does some recursion too
Further more, I seperated code of deleting, renaming, moving, and copying, and the overall result is that code becomes simpler - though a small amount of code is duplicated (mostly in move/copy operations, that's why I split the largest part of common code in a separate function)
When this patch is accepted I'll submit the rest (that is, the code using these functions)
Index: shlfileop.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/shlfileop.c,v retrieving revision 1.56 diff -u -p -r1.56 shlfileop.c --- shlfileop.c 10 Nov 2005 11:15:22 -0000 1.56 +++ shlfileop.c 16 Dec 2005 15:21:05 -0000 @@ -866,9 +866,69 @@ static const char * debug_shfileops_acti return wine_dbg_sprintf("%s", cFO_Name[ op ]); }
+struct fileops_file_data +{ + LPCWSTR next; + LPCWSTR name; + LPWSTR temp; + LPWSTR file; + DWORD attr; + DWORD pathAttr; + BOOL multi; + BOOL invalidTail; + BOOL valid; + BOOL tailSlash; +}; + +void printFileData(struct fileops_file_data *field) +{ + + TRACE("data on %p:\n" + "next: %s\n" + "name: %s\n" + "temp: %s\n" + "file: %s\n" + "attr: %lx\n" + "pathAttr: %lx\n" + "multi: %d\n" + "invalidTail: %d\n" + "valid: %d\n" + "tailSlash: %d\n", + field, + debugstr_w(field->next), + debugstr_w(field->name), + debugstr_w(field->temp), + debugstr_w(field->file), + field->attr, + field->pathAttr, + field->multi, + field->invalidTail, + field->valid, + field->tailSlash + ); +} + #define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026 #define HIGH_ADR (LPWSTR)0xffffffff
+static int shfileops_delete_file(WIN32_FIND_DATAW *wfd,int confirm,LPWSTR pFromFile,LPWSTR pTempFrom) +{ + int retCode = 0; + LPWSTR lpFileName; + lpFileName = wfd->cAlternateFileName; + if (!lpFileName[0]) + lpFileName = wfd->cFileName; + SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL); + if (IsAttribFile(wfd->dwFileAttributes)) + { + if(SHNotifyDeleteFileW(pTempFrom) != ERROR_SUCCESS) + retCode = 0x78; /* value unknown */ + } + else if(!SHELL_DeleteDirectoryW(pTempFrom,confirm)) + retCode = 0x79; /* value unknown */ + return retCode; +} + /* handle the complete deletion of `pTempFrom` */ static int shfileops_delete(WIN32_FIND_DATAW *wfd,SHFILEOPSTRUCTW nFileOp, LPWSTR pFromFile,LPWSTR pTempFrom,HANDLE *hFind)
@@ -884,20 +944,12 @@ static int shfileops_delete(WIN32_FIND_D if (IsDotDir(lpFileName) || ((b_Mask) && IsAttribDir(wfd->dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY))) continue; - SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL); - /* TODO: Check the SHELL_DeleteFileOrDirectoryW() function in shell32.dll */ - if (IsAttribFile(wfd->dwFileAttributes)) - { - if(SHNotifyDeleteFileW(pTempFrom) != ERROR_SUCCESS) - { - nFileOp.fAnyOperationsAborted = TRUE; - retCode = 0x78; /* value unknown */ - } - } - else if(!SHELL_DeleteDirectoryW(pTempFrom, (!(nFileOp.fFlags & FOF_NOCONFIRMATION)))) + + retCode = shfileops_delete_file(wfd,(nFileOp.fFlags & FOF_NOCONFIRMATION) == 0,pFromFile,pTempFrom); + if (retCode) { - nFileOp.fAnyOperationsAborted = TRUE; - retCode = 0x79; /* value unknown */ + nFileOp.fAnyOperationsAborted = TRUE; + break; } } while (!nFileOp.fAnyOperationsAborted && FindNextFileW(*hFind,wfd)); @@ -1001,6 +1053,210 @@ static DWORD shfileops_get_parent_attr(L return PathAttr; }
+static int shfileop_unmasked_setup(WIN32_FIND_DATAW wfd, struct fileops_file_data *to,struct fileops_file_data *from,BOOL b_Multi,long FuncSwitch) +{ + int retCode = 0; + + TRACE("b_Multi: %d\n",b_Multi); + TRACE("to:\n"); + printFileData(to); + TRACE("from:\n"); + printFileData(from); + + if (IsAttribDir(wfd.dwFileAttributes) && (to->attr == INVALID_FILE_ATTRIBUTES)) + { + if (to->file) + { + to->pathAttr = shfileops_get_parent_attr2(to->file,to->temp,to->valid,&retCode); + if (retCode) + return retCode; + if (to->invalidTail) + { + retCode = 0x10003; + return retCode; + } + } + } + + /* trailing BackSlash is ever removed and to->file points to BackSlash before */ + if (!to->multi && (from->multi || (!(b_Multi) && IsAttribDir(to->attr)))) + { + if ((FO_MOVE == FuncSwitch) && IsAttribDir(to->attr) && IsAttribDir(wfd.dwFileAttributes)) + { + if (b_Multi) + { + retCode = 0x73; /* !b_Multi = 0x8 ?? */ + return retCode; + } + } + to->file = SHFileStrCpyCatW(to->temp, NULL, wfd.cFileName); + to->attr = GetFileAttributesW(to->temp); + } + + if (IsAttribDir(to->attr)) + { + if (IsAttribFile(wfd.dwFileAttributes)) + { + retCode = (FO_COPY == FuncSwitch) ? 0x75 : 0xb7; + return retCode; + } + } + else + { + to->pathAttr = shfileops_get_parent_attr(to->file,to->temp); + if (IsAttribFile(to->pathAttr)) + { + /* error, is this tested ? */ + retCode = 0x777402; + return retCode; + } + } + + /* singlesource + no mask */ + if (INVALID_FILE_ATTRIBUTES == (to->attr & to->pathAttr)) + { + /* Target-dir does not exist, and cannot be created */ + retCode=0x75; + return retCode; + } + + return retCode; +} + +static int shfileop_move_unmasked( SHFILEOPSTRUCTW nFileOp,WIN32_FIND_DATAW wfd, struct fileops_file_data to, struct fileops_file_data from) +{ + int retCode = 0; + int level = nFileOp.wFunc >> 4; + + BOOL b_SameRoot = (toupperW(from.temp[0]) == toupperW(to.temp[0])); + + to.file = NULL; + if ((to.attr == INVALID_FILE_ATTRIBUTES) && SHFileStrICmpW(from.temp, to.temp, from.file, NULL)) + { + nFileOp.wFunc = ((level+1)<<4) + FO_RENAME; + } + else + { + if (b_SameRoot && IsAttribDir(to.attr) && IsAttribDir(wfd.dwFileAttributes)) + { + /* FIXME: moving directory contents into the other one: + * - path\ -> path\* + * MOVE + * - loop over files in path\*, eg path\file + * MOVE + * - COPY, DELETE + * + * is this really necessary? why not a dedicated recursive + * (light-weight) function? + */ + /* we need to.file for FO_DELETE after FO_MOVE contence */ + to.file = SHFileStrCpyCatW(from.temp, NULL, wWildcardFile); + } + else + { + nFileOp.wFunc = ((level+1)<<4) + FO_COPY; + } + } + + switch(nFileOp.wFunc & FO_MASK) + { + case FO_MOVE: + retCode = SHFileOperationW(&nFileOp); + break; + case FO_RENAME: + /* + retCode = SHFileOperationW(&nFileOp); + */ + if (SHNotifyMoveFileW(from.temp, to.temp) != ERROR_SUCCESS) + { + /* we need still the value for the returncode, we use the mostly assumed */ + retCode = 0xb7; + nFileOp.fAnyOperationsAborted = TRUE; + } + break; + case FO_COPY: + retCode = SHFileOperationW(&nFileOp); + break; + default: + retCode = SHFileOperationW(&nFileOp); + break; + } + + if (to.file) + ((DWORD*)to.file)[0] = '\0'; + if (!nFileOp.fAnyOperationsAborted && (FO_RENAME != (nFileOp.wFunc & 0xf))) + { + /* + TRACE("preparing for delete\n"); + nFileOp.wFunc = ((level+1)<<4) + FO_DELETE; + TRACE("delete: going to execute: %s: flags (0x%04x) : %s\n", + debug_shfileops_action(nFileOp.wFunc & FO_MASK), nFileOp.fFlags, + debug_shfileops_flags(nFileOp.fFlags) ); + + retCode = SHFileOperationW(&nFileOp); + TRACE("returned: %d\n",retCode); + */ + retCode = shfileops_delete_file(&wfd,(nFileOp.fFlags & FOF_NOCONFIRMATION) == 0,from.file,from.temp); + } + + return retCode; +} + +static int shfileop_copy_unmasked(SHFILEOPSTRUCTW nFileOp,WIN32_FIND_DATAW wfd,struct fileops_file_data to,struct fileops_file_data from) +{ + int retCode = 0; + BOOL not_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) || (nFileOp.fFlags & FOF_RENAMEONCOLLISION)); + BOOL ask_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) && !(nFileOp.fFlags & FOF_RENAMEONCOLLISION)); + + if (SHFileStrICmpW(from.temp, to.temp, NULL, NULL)) + { /* target is the same as source ? */ + /* we still need the value for the returncode, we assume 0x71 */ + retCode = 0x71; + return retCode; + } + if (IsAttribDir((to.attr & wfd.dwFileAttributes))) + { + if (IsAttribDir(to.attr) || !SHNotifyCreateDirectoryW(to.temp, NULL)) + { + /* FIXME: copying directory contents into the other one: + * - path\ -> path\* + * COPY + * - loop over files in path\*, eg path\file + * COPY + * + * is this really necessary? why not a dedicated recursive + * (light-weight) function? + */ + + /* ??? nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES); */ + SHFileStrCpyCatW(from.temp, NULL, wWildcardFile); + TRACE("recursive copy\n"); + retCode = SHFileOperationW(&nFileOp); + } + else + { + retCode = 0x750;/* value unknown */ + return retCode; + } + } + else + { + if (!(ask_overwrite && SHELL_ConfirmDialogW(ASK_OVERWRITE_FILE, to.temp)) + && (not_overwrite)) + { + /* we still need the value for the returncode, we use the mostly assumed */ + retCode = 0x73; + return retCode; + } + if (SHNotifyCopyFileW(from.temp, to.temp, TRUE) != ERROR_SUCCESS) + { + retCode = 0x77; /* value unknown */ + return retCode; + } + } + return retCode; +} + /************************************************************************* * SHFileOperationW [SHELL32.@] *