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.@]
*