SHFileOperationW split
Joris Huizer
jorishuizer at planet.nl
Fri Dec 16 11:39:55 CST 2005
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)
If we want that, recursion still needs to be fixed in the non-obvious
cases - probably with functions especially written for that;
Are there existing funtions in wine that are able to move/copy contents
of directories and subdirectories into a target directory?
I renamed the old SHFileOperationW into SHFileOperationW0 as the patch
became unreadable otherwise; will send another patch removing that one
if this one is accepted
+ changed indenting to four spaces (though I could change that in case
you really prefer indenting by tabs like most of that file does?)
-------------- next part --------------
? .shlfileop.c.swp
? added
? shell32.dll.dbg.c
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 17:20:31 -0000
@@ -866,9 +866,68 @@ 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 +943,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));
@@ -1006,7 +1057,7 @@ static DWORD shfileops_get_parent_attr(L
*
* See SHFileOperationA.
*/
-int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
+int WINAPI SHFileOperationW0(LPSHFILEOPSTRUCTW lpFileOp)
{
SHFILEOPSTRUCTW nFileOp = *(lpFileOp);
@@ -1051,7 +1102,7 @@ int WINAPI SHFileOperationW(LPSHFILEOPST
TRACE("%s: flags (0x%04x) : %s\n",
debug_shfileops_action(FuncSwitch), nFileOp.fFlags,
debug_shfileops_flags(nFileOp.fFlags) );
-
+
/* establish when pTo is interpreted as the name of the destination file
* or the directory where the Fromfile should be copied to.
* This depends on:
@@ -1389,6 +1440,600 @@ shfileop_end:
return retCode;
}
+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;
+}
+
+static int shfileop_copy(SHFILEOPSTRUCTW nFileOp,struct fileops_file_data from,struct fileops_file_data to)
+{
+ WIN32_FIND_DATAW wfd;
+ HANDLE hFind = FindFirstFileW(from.name, &wfd);
+ int retCode = 0;
+
+ BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES);
+ BOOL b_SameRoot;
+ BOOL b_SameTailName;
+ BOOL b_Mask = (NULL != StrPBrkW(&from.file[1], wWildcardChars));
+
+ /* to.name must be always valid */
+
+ if (INVALID_HANDLE_VALUE == hFind)
+ {
+ /* root (without mask) is also not allowed as source, tested in W98 */
+ return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
+ }
+
+ b_SameRoot = (toupperW(from.temp[0]) == toupperW(to.temp[0]));
+ b_SameTailName = SHFileStrICmpW(to.file, from.file, NULL, NULL);
+
+ to.pathAttr = to.attr = GetFileAttributesW(to.temp);
+ if (!b_Mask && (to.attr == INVALID_FILE_ATTRIBUTES) && (to.file))
+ {
+ to.pathAttr = shfileops_get_parent_attr(to.file,to.temp);
+ }
+
+
+ to.valid = ((b_SameTailName && b_SameRoot) ||
+ (b_SameTailName && !b_SameRoot) || (to.invalidTail));
+
+ /* handle mask in source */
+ if (b_Mask)
+ {
+ if (!IsAttribDir(to.attr))
+ {
+ retCode = 0x75;
+ goto shfileop_end;
+ }
+ to.file = SHFileStrCpyCatW(to.temp, NULL, wBackslash);
+ nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES);
+ do
+ {
+ /* should be possible to call shfileop_unmasked_setup & shfileop_copy_unmasked here... */
+ retCode = shfileops_do_operation(wfd,&nFileOp,to.file,from.file);
+ } while(!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd));
+ }
+ FindClose(hFind);
+ hFind = INVALID_HANDLE_VALUE;
+
+ if (!b_Mask)
+ {
+ retCode = shfileop_unmasked_setup(wfd,&to,&from,b_Multi,FO_COPY);
+ if (retCode == 0)
+ retCode = shfileop_copy_unmasked(nFileOp,wfd,to,from);
+ }
+
+shfileop_end:
+
+ if (hFind != INVALID_HANDLE_VALUE)
+ FindClose(hFind);
+ return retCode;
+}
+
+static int shfileop_delete(SHFILEOPSTRUCTW nFileOp,struct fileops_file_data from,struct fileops_file_data to)
+{
+ int retCode = 0;
+ WIN32_FIND_DATAW wfd;
+ HANDLE hFind = FindFirstFileW(from.name, &wfd);
+ BOOL b_Mask = (NULL != StrPBrkW(&from.file[1], wWildcardChars));
+
+ if (INVALID_HANDLE_VALUE == hFind)
+ {
+ /* root (without mask) is also not allowed as source, tested in W98 */
+ if (!((b_Mask) && IsAttribDir(shfileops_get_parent_attr(from.file,from.temp))))
+ return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
+ else
+ return 0;
+ }
+ else if (to.name)
+ FIXME("FO_DELETE with lpFileOp->pTo unequal to NULL, ignoring\n");
+ else
+ {
+ do
+ {
+ LPWSTR lpFileName = wfd.cAlternateFileName;
+ if (!lpFileName[0])
+ lpFileName = wfd.cFileName;
+ if (IsDotDir(lpFileName) ||
+ ((b_Mask) && IsAttribDir(wfd.dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
+ continue;
+ retCode = shfileops_delete_file(&wfd,(nFileOp.fFlags & FOF_NOCONFIRMATION) == 0,from.file,from.temp);
+ if (retCode)
+ break;
+ }
+ while (FindNextFileW(hFind,&wfd));
+ }
+
+ FindClose(hFind);
+ return retCode;
+}
+
+static int shfileop_move(SHFILEOPSTRUCTW nFileOp,struct fileops_file_data from,struct fileops_file_data to)
+{
+ WIN32_FIND_DATAW wfd;
+ HANDLE hFind = FindFirstFileW(from.name, &wfd);
+ int retCode = 0;
+
+ BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES);
+ BOOL b_SameRoot;
+ BOOL b_SameTailName;
+ BOOL b_Mask = (NULL != StrPBrkW(&from.file[1], wWildcardChars));
+
+ /* to.name must be always valid */
+
+ if (INVALID_HANDLE_VALUE == hFind)
+ {
+ /* root (without mask) is also not allowed as source, tested in W98 */
+ return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
+ }
+
+ b_SameRoot = (toupperW(from.temp[0]) == toupperW(to.temp[0]));
+ b_SameTailName = SHFileStrICmpW(to.file, from.file, NULL, NULL);
+
+ to.pathAttr = to.attr = GetFileAttributesW(to.temp);
+ if (!b_Mask && (to.attr == INVALID_FILE_ATTRIBUTES) && (to.file))
+ {
+ to.pathAttr = shfileops_get_parent_attr(to.file,to.temp);
+ }
+
+ /* W98 Bug with FO_MOVE different from FO_COPY, better the same as FO_COPY */
+ to.valid = ((b_SameTailName && !b_SameRoot) || (to.invalidTail));
+
+ /* handle mask in source */
+ if (b_Mask)
+ {
+ if (!IsAttribDir(to.attr))
+ {
+ retCode = (to.invalidTail/* && b_SameTailName*/)
+ ? 0x2 : 0x75;
+ goto shfileop_end;
+ }
+ to.file = SHFileStrCpyCatW(to.temp, NULL, wBackslash);
+ nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES);
+ do
+ {
+ /* should be possible to call shfileop_move_unmasked & shfileop_move_unmasked here... */
+ retCode = shfileops_do_operation(wfd,&nFileOp,to.file,from.file);
+ } while(!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd));
+ }
+ FindClose(hFind);
+ hFind = INVALID_HANDLE_VALUE;
+
+ if (!b_Mask)
+ {
+ retCode = shfileop_unmasked_setup(wfd,&to,&from,b_Multi,FO_MOVE);
+ if (retCode == 0)
+ retCode = shfileop_move_unmasked(nFileOp,wfd,to,from);
+ }
+
+shfileop_end:
+
+ if (hFind != INVALID_HANDLE_VALUE)
+ FindClose(hFind);
+ return retCode;
+}
+
+static int shfileop_rename(SHFILEOPSTRUCTW nFileOp,struct fileops_file_data from,struct fileops_file_data to)
+{
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAW wfd;
+ int retCode = 0;
+
+ BOOL b_SameRoot = (toupperW(from.temp[0]) == toupperW(to.temp[0]));
+ BOOL b_Mask = (NULL != StrPBrkW(&from.file[1], wWildcardChars));
+
+ /* to.name must be always valid */
+
+ if (to.multi || from.multi || (b_Mask && !to.invalidTail))
+ {
+ /* W2K ERROR_GEN_FAILURE, W98 returns no error */
+ return ERROR_GEN_FAILURE;
+ }
+
+ hFind = FindFirstFileW(from.name, &wfd);
+ if (INVALID_HANDLE_VALUE == hFind)
+ {
+ /* root (without mask) is also not allowed as source, tested in W98 */
+ return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
+ }
+
+ to.pathAttr = to.attr = GetFileAttributesW(to.temp);
+ if (!b_Mask && (to.attr == INVALID_FILE_ATTRIBUTES) && (to.file))
+ {
+ to.pathAttr = shfileops_get_parent_attr(to.file,to.temp);
+ }
+
+ if (!b_SameRoot || b_Mask /* FO_RENAME works not with Mask */
+ || !SHFileStrICmpW(from.temp, to.temp, from.file, NULL)
+ || (SHFileStrICmpW(from.temp, to.temp, from.file, HIGH_ADR) && !to.tailSlash))
+ {
+ retCode = 0x73;
+ }
+ else if (to.invalidTail)
+ {
+ retCode=0x2;
+ }
+ else if (INVALID_FILE_ATTRIBUTES == to.pathAttr)
+ {
+ retCode = 0x75;
+ }
+ else if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(to.attr))
+ {
+ retCode = (to.tailSlash) ? 0xb7 : 0x7b;
+ }
+ /* we use SHNotifyMoveFile() instead MoveFileW */
+ else if (SHNotifyMoveFileW(from.temp, to.temp) != ERROR_SUCCESS)
+ {
+ /* we need still the value for the returncode, we use the mostly assumed */
+ retCode = 0xb7;
+ }
+
+ FindClose(hFind);
+ return retCode;
+}
+
+/*************************************************************************
+ * SHFileOperationW [SHELL32.@]
+ *
+ * See SHFileOperationA.
+ */
+int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
+{
+ SHFILEOPSTRUCTW nFileOp = *(lpFileOp);
+
+ struct fileops_file_data from;
+ struct fileops_file_data to;
+
+ int retCode = 0;
+ BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES);
+ BOOL b_MultiPaired = (FO_DELETE == (lpFileOp->wFunc & FO_MASK));
+ long FuncSwitch = (nFileOp.wFunc & FO_MASK);
+ long level= nFileOp.wFunc>>4;
+
+
+ /* init helper structures */
+ from.next = nFileOp.pFrom;
+ from.name = from.next;
+ from.temp = NULL;
+ from.multi = FALSE;
+
+ to.next = nFileOp.pTo;
+ to.name = NULL;
+ to.temp = NULL;
+ to.file = NULL;
+ to.multi = (FO_DELETE != (lpFileOp->wFunc & FO_MASK));
+ to.invalidTail = FALSE;
+ to.tailSlash = FALSE;
+
+ /* default no error */
+ nFileOp.fAnyOperationsAborted = FALSE;
+
+ if ((FuncSwitch < FO_MOVE) || (FuncSwitch > FO_RENAME))
+ goto shfileop_end; /* no valid FunctionCode */
+
+ if (level == 0)
+ TRACE("%s: flags (0x%04x) : %s\n",
+ debug_shfileops_action(FuncSwitch), nFileOp.fFlags,
+ debug_shfileops_flags(nFileOp.fFlags) );
+
+ /* establish when pTo is interpreted as the name of the destination file
+ * or the directory where the Fromfile should be copied to.
+ * This depends on:
+ * (1) pTo points to the name of an existing directory;
+ * (2) the flag FOF_MULTIDESTFILES is present;
+ * (3) whether pFrom point to multiple filenames.
+ *
+ * Some experiments:
+ *
+ * destisdir 1 1 1 1 0 0 0 0
+ * FOF_MULTIDESTFILES 1 1 0 0 1 1 0 0
+ * multiple from filenames 1 0 1 0 1 0 1 0
+ * ---------------
+ * copy files to dir 1 0 1 1 0 0 1 0
+ * create dir 0 0 0 0 0 0 1 0
+ */
+
+ retCode = shfileops_check_flags(nFileOp);
+ if (retCode)
+ goto shfileop_end;
+
+ if ((from.next) && (!(to.multi) || (to.next)))
+ {
+ nFileOp.pFrom = from.temp = HeapAlloc(GetProcessHeap(), 0, ((1 + 2 * (to.multi)) * MAX_PATH + 6) * sizeof(WCHAR));
+ if (!from.temp)
+ {
+ retCode = ERROR_OUTOFMEMORY;
+ SetLastError(retCode);
+ goto shfileop_end;
+ }
+ if (to.multi)
+ to.temp = &from.temp[MAX_PATH + 4];
+ nFileOp.pTo = to.temp;
+ }
+ else
+ {
+ retCode = ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
+ goto shfileop_end;
+ }
+ /* need break at error before change sourcepointer */
+ while(!nFileOp.fAnyOperationsAborted && (from.next[0]))
+ {
+ nFileOp.wFunc = ((level + 1) << 4) + FuncSwitch;
+ nFileOp.fFlags = lpFileOp->fFlags;
+
+ if (to.multi)
+ {
+ to.name = to.next;
+ to.next = &to.next[lstrlenW(to.name)+1];
+ to.multi = (b_Multi && to.next[0]);
+ }
+
+ from.name = from.next;
+ from.next = &from.next[lstrlenW(from.next)+1];
+ if (!from.multi && !to.multi)
+ from.multi = (from.next[0]);
+
+ from.file = SHFileStrCpyCatW(from.temp, from.name, NULL);
+
+ if (to.name)
+ {
+ to.file = SHFileStrCpyCatW(to.temp, to.name, NULL);
+ }
+ if (!b_MultiPaired)
+ {
+ b_MultiPaired =
+ SHELL_FileNamesMatch(lpFileOp->pFrom, lpFileOp->pTo, (!b_Multi || from.multi));
+ }
+ if (!(b_MultiPaired) || !(from.file) || !(from.file[1]) || ((to.name) && !(to.file)))
+ {
+ retCode = ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
+ break;
+ }
+ if (to.name)
+ {
+ to.tailSlash = (!to.file[1]);
+ if (to.tailSlash)
+ {
+ to.file[0] = '\0';
+ if (StrChrW(to.temp,'\\'))
+ {
+ to.file = SHFileStrCpyCatW(to.temp, NULL, NULL);
+ }
+ }
+ to.invalidTail = (NULL != StrPBrkW(&to.file[1], wWildcardChars));
+ }
+
+ switch(FuncSwitch)
+ {
+ case FO_COPY:
+ retCode = shfileop_copy(nFileOp,from,to);
+ break;
+ case FO_DELETE:
+ retCode = shfileop_delete(nFileOp,from,to);
+ break;
+ case FO_MOVE:
+ retCode = shfileop_move(nFileOp,from,to);
+ break;
+ case FO_RENAME:
+ retCode = shfileop_rename(nFileOp,from,to);
+ break;
+ }
+ if (retCode)
+ break;
+ }
+
+shfileop_end:
+ HeapFree(GetProcessHeap(), 0, from.temp);
+ if (retCode)
+ nFileOp.fAnyOperationsAborted = TRUE;
+ TRACE("%s level=%ld AnyOpsAborted=%s ret=0x%x, with %s %s%s\n",
+ debug_shfileops_action(FuncSwitch), level,
+ nFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
+ retCode, debugstr_w(from.name), to.name ? "-> ":"", debugstr_w(to.name));
+
+ lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
+ return retCode;
+}
+
#define SHDSA_GetItemCount(hdsa) (*(int*)(hdsa))
/*************************************************************************
More information about the wine-patches
mailing list