shell32:SHFileOperationA reimplementation
Rolf Kalbermatter
rolf.kalbermatter at citeng.com
Thu Feb 6 16:22:06 CST 2003
Changelog
* dlls/shell32/shlfileop.c
- Reimplement SHFileOperationA to be more complete. This code comes from
Dietrich Teickner [Dietrich_Teickner at t-online.de] from Odin who did most
of the work. The Unicode version is going to follow.
- Fix Win32DeleteFile to retry to delete the file on initial error after
removing the write protection and system flag and also return a success
status rather than always TRUE. Verified in Win2000 to work in this way.
License: X11/LGPL
Rolf Kalbermatter
Index: dlls/shell32/shlfileop.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlfileop.c,v
retrieving revision 1.24
diff -u -r1.24 shlfileop.c
--- dlls/shell32/shlfileop.c 1 Feb 2003 00:41:30 -0000 1.24
+++ dlls/shell32/shlfileop.c 6 Feb 2003 22:18:27 -0000
@@ -3,6 +3,8 @@
*
* Copyright 2000 Juergen Schmied
* Copyright 2002 Andriy Palamarchuk
+ * Copyright 2002 Dietrich Teickner (from Odin)
+ * Copyright 2002 Rolf Kalbermatter
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -77,7 +79,6 @@
*
* like rm -r
*/
-
BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
{
BOOL ret = FALSE;
@@ -92,27 +93,25 @@
if (bShowUI && !SHELL_ConfirmDialog(ASK_DELETE_FOLDER, pszDir))
return FALSE;
- if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(szTemp, &wfd)))
+ if (INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(szTemp, &wfd)))
{
do
{
- if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
+ if (strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
{
strcpy(szTemp, pszDir);
PathAddBackslashA(szTemp);
strcat(szTemp, wfd.cFileName);
- if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
+ if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
SHELL_DeleteDirectoryA(szTemp, FALSE);
else
DeleteFileA(szTemp);
}
} while(FindNextFileA(hFind, &wfd));
-
FindClose(hFind);
ret = RemoveDirectoryA(pszDir);
}
-
return ret;
}
@@ -123,9 +122,8 @@
BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
{
if (bShowUI && !SHELL_ConfirmDialog(ASK_DELETE_FILE, pszFile))
- return FALSE;
-
- return DeleteFileA(pszFile);
+ return FALSE;
+ return DeleteFileA(pszFile);
}
/*************************************************************************
@@ -185,23 +183,41 @@
*/
static BOOL Win32DeleteFileA(LPCSTR fName)
{
+ DWORD ret;
TRACE("%p(%s)\n", fName, fName);
- DeleteFileA(fName);
- SHChangeNotify(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
- return TRUE;
+ if (!(ret = DeleteFileA(fName)))
+ {
+ /* File may be write protected or a system file */
+ DWORD dwAttr = GetFileAttributesA(fName);
+ if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
+ if (SetFileAttributesA(fName, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
+ ret = DeleteFileA(fName);
+ }
+ if (ret)
+ SHChangeNotify(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
+ return ret;
}
static BOOL Win32DeleteFileW(LPCWSTR fName)
{
+ BOOL ret;
TRACE("%p(%s)\n", fName, debugstr_w(fName));
- DeleteFileW(fName);
- SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, fName, NULL);
- return TRUE;
+ if (!(ret = DeleteFileW(fName)))
+ {
+ /* File may be write protected or a system file */
+ DWORD dwAttr = GetFileAttributesW(fName);
+ if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
+ if (SetFileAttributesW(fName, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
+ ret = DeleteFileW(fName);
+ }
+ if (ret)
+ SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, fName, NULL);
+ return ret;
}
-DWORD WINAPI Win32DeleteFileAW(LPCVOID fName)
+BOOL WINAPI Win32DeleteFileAW(LPCVOID fName)
{
if (SHELL_OsIsUnicode())
return Win32DeleteFileW(fName);
@@ -209,27 +225,82 @@
}
/**************************************************************************
- * SHELL_FileNamesMatch()
*
- * Accepts two \0 delimited lists of the file names. Checks whether number of
- * files in the both lists is the same.
+ * SHFileStrCpyCatA HelperFunction for SHFileOperationA
+ *
+ */
+LPSTR SHFileStrCpyCatA(LPSTR pTo, LPCSTR pFrom, LPCSTR pCatStr)
+{
+ LPSTR pToFile = NULL;
+ int i_len;
+
+ if (pTo)
+ {
+ if (pFrom)
+ lstrcpyA(pTo, pFrom);
+ if (pCatStr) /* lstrcatA(pTo, pCatStr); ?? */
+ {
+ i_len = lstrlenA(pTo);
+ if ((i_len) && (pCatStr[0] == '\\') && (pTo[--i_len] == '\\'))
+ pTo[i_len] = '\0';
+ lstrcatA(pTo, pCatStr);
+ }
+ pToFile = strrchr(pTo, '\\');
+ /* !! termination of the new string-group */
+ pTo[(lstrlenA(pTo)) + 1] = '\0';
+ }
+ return pToFile;
+}
+
+/*************************************************************************
+ *
+ * SHFileStrICmpA HelperFunction for SHFileOperationA
+ *
*/
-BOOL SHELL_FileNamesMatch(LPCSTR pszFiles1, LPCSTR pszFiles2)
+BOOL SHFileStrICmpA(LPSTR p1,LPSTR p2, LPSTR p1End, LPSTR p2End)
{
- while ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
- (pszFiles2[strlen(pszFiles2) + 1] != '\0'))
- {
- pszFiles1 += strlen(pszFiles1) + 1;
- pszFiles2 += strlen(pszFiles2) + 1;
- }
-
- return
- ((pszFiles1[strlen(pszFiles1) + 1] == '\0') &&
- (pszFiles2[strlen(pszFiles2) + 1] == '\0')) ||
- ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
- (pszFiles2[strlen(pszFiles2) + 1] != '\0'));
+ CHAR C1 = '\0';
+ CHAR C2 = '\0';
+ int i_Temp = -1;
+ int i_len1 = lstrlenA(p1);
+ int i_len2 = lstrlenA(p2);
+
+ if (p1End && (&p1[i_len1] >= p1End) && ('\\' == p1End[0]))
+ {
+ C1 = p1End[0];
+ p1End[0] = '\0';
+ i_len1 = lstrlenA(p1);
+ }
+ if (p2End)
+ {
+ if ((&p2[i_len2] >= p2End) && ('\\' == p2End[0]))
+ {
+ C2 = p2End[0];
+ if (C2)
+ p2End[0] = '\0';
+ }
+ }
+ else
+ {
+ if ((i_len1 <= i_len2) && ('\\' == p2[i_len1]))
+ {
+ C2 = p2[i_len1];
+ if (C2)
+ p2[i_len1] = '\0';
+ }
+ }
+ i_len2 = lstrlenA(p2);
+ if (i_len1 == i_len2)
+ i_Temp = lstrcmpiA(p1,p2);
+ if (C1)
+ p1[i_len1] = C1;
+ if (C2)
+ p2[i_len2] = C2;
+ return !(i_Temp);
}
+#define IsAttribFile(x) (!(x == -1) && !(x & FILE_ATTRIBUTE_DIRECTORY))
+#define IsAttribDir(x) (!(x == -1) && (x & FILE_ATTRIBUTE_DIRECTORY))
/*************************************************************************
* SHFileOperationA [SHELL32.@]
*
@@ -238,242 +309,499 @@
*/
DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
{
- LPSTR pFrom = (LPSTR)lpFileOp->pFrom;
- LPSTR pTo = (LPSTR)lpFileOp->pTo;
- LPSTR pTempTo;
- TRACE("flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n", lpFileOp->fFlags,
- lpFileOp->fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
- lpFileOp->fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
- lpFileOp->fFlags & FOF_SILENT ? "FOF_SILENT " : "",
- lpFileOp->fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
- lpFileOp->fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
- lpFileOp->fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
- lpFileOp->fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
- lpFileOp->fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
- lpFileOp->fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
- lpFileOp->fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
- lpFileOp->fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
- lpFileOp->fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
- switch(lpFileOp->wFunc) {
- case FO_COPY:
- case FO_MOVE:
- {
- /* 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
- */
- int multifrom = pFrom[strlen(pFrom) + 1] != '\0';
- int destisdir = PathIsDirectoryA( pTo );
- int todir = 0;
-
- if (lpFileOp->wFunc == FO_COPY)
- TRACE("File Copy:\n");
- else
- TRACE("File Move:\n");
-
- if( destisdir ) {
- if ( !((lpFileOp->fFlags & FOF_MULTIDESTFILES) && !multifrom))
- todir = 1;
- } else {
- if ( !(lpFileOp->fFlags & FOF_MULTIDESTFILES) && multifrom)
- todir = 1;
- }
-
- if ((pTo[strlen(pTo) + 1] != '\0') &&
- !(lpFileOp->fFlags & FOF_MULTIDESTFILES))
- {
- WARN("Attempt to use multiple file names as a destination "
- "without specifying FOF_MULTIDESTFILES\n");
- return 1;
- }
-
- if ((lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
- !SHELL_FileNamesMatch(pTo, pFrom))
- {
- WARN("Attempt to use multiple file names as a destination "
- "with mismatching number of files in the source and "
- "destination lists\n");
- return 1;
- }
-
- if ( todir ) {
- char szTempFrom[MAX_PATH];
- char *fromfile;
- int lenPTo;
- if ( ! destisdir) {
- TRACE(" creating directory %s\n",pTo);
- SHCreateDirectoryExA(NULL, pTo, NULL);
- }
- lenPTo = strlen(pTo);
- while(1) {
- HANDLE hFind;
- WIN32_FIND_DATAA wfd;
-
- if(!pFrom[0]) break;
- TRACE(" From Pattern='%s'\n", pFrom);
- if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
- {
- do
- {
- if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
- {
- strcpy(szTempFrom, pFrom);
-
- pTempTo = HeapAlloc(GetProcessHeap(), 0,
- lenPTo + strlen(wfd.cFileName) + 5);
- if (pTempTo) {
- strcpy(pTempTo,pTo);
- PathAddBackslashA(pTempTo);
- strcat(pTempTo,wfd.cFileName);
-
- fromfile = PathFindFileNameA(szTempFrom);
- fromfile[0] = '\0';
- PathAddBackslashA(szTempFrom);
- strcat(szTempFrom, wfd.cFileName);
- TRACE(" From='%s' To='%s'\n", szTempFrom, pTempTo);
- if(lpFileOp->wFunc == FO_COPY)
- {
- if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
- {
- /* copy recursively */
- if(!(lpFileOp->fFlags & FOF_FILESONLY))
- {
- SHFILEOPSTRUCTA shfo;
-
- SHCreateDirectoryExA(NULL, pTempTo, NULL);
- PathAddBackslashA(szTempFrom);
- strcat(szTempFrom, "*.*");
- szTempFrom[strlen(szTempFrom) + 1] = '\0';
- pTempTo[strlen(pTempTo) + 1] = '\0';
- memcpy(&shfo, lpFileOp, sizeof(shfo));
- shfo.pFrom = szTempFrom;
- shfo.pTo = pTempTo;
- SHFileOperationA(&shfo);
-
- szTempFrom[strlen(szTempFrom) - 4] = '\0';
- }
- }
- else
- CopyFileA(szTempFrom, pTempTo, FALSE);
- }
- else
- {
- /* move file/directory */
- MoveFileA(szTempFrom, pTempTo);
- }
- HeapFree(GetProcessHeap(), 0, pTempTo);
- }
- }
- } while(FindNextFileA(hFind, &wfd));
- FindClose(hFind);
- }
- else
- {
- /* can't find file with specified name */
- break;
- }
- pFrom += strlen(pFrom) + 1;
- }
- } else {
- while (1) {
- if(!pFrom[0]) break;
- if(!pTo[0]) break;
- TRACE(" From='%s' To='%s'\n", pFrom, pTo);
-
- pTempTo = HeapAlloc(GetProcessHeap(), 0, strlen(pTo)+1);
- if (pTempTo)
- {
- strcpy( pTempTo, pTo );
- PathRemoveFileSpecA(pTempTo);
- TRACE(" Creating Directory '%s'\n", pTempTo);
- SHCreateDirectoryExA(NULL, pTempTo, NULL);
- HeapFree(GetProcessHeap(), 0, pTempTo);
- }
- if (lpFileOp->wFunc == FO_COPY)
- CopyFileA(pFrom, pTo, FALSE);
- else
- MoveFileA(pFrom, pTo);
-
- pFrom += strlen(pFrom) + 1;
- pTo += strlen(pTo) + 1;
- }
- }
- TRACE("Setting AnyOpsAborted=FALSE\n");
- lpFileOp->fAnyOperationsAborted=FALSE;
- return 0;
- }
-
- case FO_DELETE:
- {
- HANDLE hFind;
- WIN32_FIND_DATAA wfd;
- char szTemp[MAX_PATH];
- char *file_name;
-
- TRACE("File Delete:\n");
- while(1) {
- if(!pFrom[0]) break;
- TRACE(" Pattern='%s'\n", pFrom);
- if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
- {
- do
- {
- if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
- {
- strcpy(szTemp, pFrom);
- file_name = PathFindFileNameA(szTemp);
- file_name[0] = '\0';
- PathAddBackslashA(szTemp);
- strcat(szTemp, wfd.cFileName);
-
- TRACE(" File='%s'\n", szTemp);
- if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
- {
- if(!(lpFileOp->fFlags & FOF_FILESONLY))
- SHELL_DeleteDirectoryA(szTemp, FALSE);
- }
- else
- DeleteFileA(szTemp);
- }
- } while(FindNextFileA(hFind, &wfd));
-
- FindClose(hFind);
- }
- pFrom += strlen(pFrom) + 1;
- }
- TRACE("Setting AnyOpsAborted=FALSE\n");
- lpFileOp->fAnyOperationsAborted=FALSE;
- return 0;
- }
-
- case FO_RENAME:
- TRACE("File Rename:\n");
- if (pFrom[strlen(pFrom) + 1] != '\0')
- {
- WARN("Attempt to rename more than one file\n");
- return 1;
- }
- lpFileOp->fAnyOperationsAborted = FALSE;
- TRACE("From %s, To %s\n", pFrom, pTo);
- return !MoveFileA(pFrom, pTo);
+ SHFILEOPSTRUCTA nlpFileOp = *(lpFileOp);
- default:
- FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc);
+ LPCSTR pNextFrom = nlpFileOp.pFrom;
+ LPCSTR pNextTo = nlpFileOp.pTo;
+ LPCSTR pFrom = pNextFrom;
+ LPCSTR pTo = NULL;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA wfd;
+ LPSTR pTempFrom = NULL;
+ LPSTR pTempTo = NULL;
+ LPSTR pFromFile;
+ LPSTR pToFile;
+ long retCode = 0;
+ DWORD ToAttr;
+ DWORD ToPathAttr;
+ FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
+
+ BOOL b_Multi = (nlpFileOp.fFlags & FOF_MULTIDESTFILES);
+
+ BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & 0xf));
+ BOOL b_MultiFrom = FALSE;
+ BOOL not_overwrite;
+ BOOL ask_overwrite;
+ BOOL b_SameRoot;
+ BOOL b_SameTailName;
+ BOOL b_ToInvalidTail;
+ BOOL b_ToValid; /* for W98-Bug ? for FO_MOVE with source and target in same rootdrive */
+ BOOL b_Mask; /* wird als Schalter benutzt, vieleicht finde ich die richtige bitposition */
+ BOOL b_ToTailSlash;
+ LPSTR pToFuncTXT;
+
+ long FuncSwitch = (nlpFileOp.wFunc & 0xf);
+ long level= nlpFileOp.wFunc>>4;
+
+/* default no error */
+ nlpFileOp.fAnyOperationsAborted=FALSE;
+
+ switch(FuncSwitch)
+ {
+ case FO_MOVE:
+ pToFuncTXT = "FO_MOVE";break;
+ case FO_COPY:
+ pToFuncTXT = "FO_COPY";break;
+ case FO_DELETE:
+ pToFuncTXT = "FO_DELETE";break;
+ case FO_RENAME:
+ pToFuncTXT = "FO_RENAME";break;
+ default:
+ pToFuncTXT = "FO_????";
+ goto shfileop_normal;
}
- return 1;
+ if (level == 0)
+ TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n", pToFuncTXT, nlpFileOp.fFlags,
+ nlpFileOp.fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
+ nlpFileOp.fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
+ nlpFileOp.fFlags & FOF_SILENT ? "FOF_SILENT " : "",
+ nlpFileOp.fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
+ nlpFileOp.fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
+ nlpFileOp.fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
+ nlpFileOp.fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
+ nlpFileOp.fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
+ nlpFileOp.fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
+ nlpFileOp.fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
+ nlpFileOp.fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
+ nlpFileOp.fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
+ ;
+ /* 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
+ */
+ /*
+ * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY are implemented
+ * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS are not implemented and ignored
+ * FOF_RENAMEONCOLLISION are implemented partially and breaks if file exist
+ * FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE are not implemented and breaks
+ * if any other flag set, an error occurs
+ */
+ TRACE("%s level=%d nlpFileOp.fFlags=0x%x\n", pToFuncTXT, level, lpFileOp->fFlags);
+
+ /* OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY));
+ /* OFl ^= (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR);*/
+ OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY)); /* implemented */
+ OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR); /* ignored, if one */
+ OFl &= (~FOF_SIMPLEPROGRESS); /* ignored, only wit FOF_SILEN */
+ if (OFl)
+ {
+ if (OFl & (~ (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR)))
+ {
+ TRACE("%s level=%d lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", pToFuncTXT, level, OFl);
+ retCode = 0x403; /* we need a extension of shlfileop */
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ }
+ else
+ {
+ TRACE("%s level=%d lpFileOp->fFlags=0x%x not full implemented ,stub\n", pToFuncTXT, level, OFl);
+ } /* endif */
+ } /* endif */
+
+ if ((pNextFrom) && (!(b_MultiTo) || (pNextTo)))
+ {
+ nlpFileOp.pFrom = pTempFrom = HeapAlloc(GetProcessHeap(), 0, (1 + 2 * (b_MultiTo)) * MAX_PATH + 6);
+ if (b_MultiTo) pTempTo = &pTempFrom[MAX_PATH+4];
+ nlpFileOp.pTo = pTempTo;
+ ask_overwrite = (!(nlpFileOp.fFlags & FOF_NOCONFIRMATION) && !(nlpFileOp.fFlags & FOF_RENAMEONCOLLISION));
+ not_overwrite = (!(nlpFileOp.fFlags & FOF_NOCONFIRMATION) || (nlpFileOp.fFlags & FOF_RENAMEONCOLLISION));
+ }
+ else
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x402;
+ goto shfileop_error;
+ }
+ /* need break at error before change sourcepointer */
+ while(!nlpFileOp.fAnyOperationsAborted && (pNextFrom[0]))
+ {
+ nlpFileOp.wFunc = ((level+1)<<4) + FuncSwitch;
+ nlpFileOp.fFlags = lpFileOp->fFlags;
+
+ if (b_MultiTo)
+ {
+ pTo = pNextTo;
+ pNextTo = &pNextTo[lstrlenA(pTo)+1];
+ b_MultiTo = (b_Multi && pNextTo[0]);
+ }
+
+ pFrom = pNextFrom;
+ pNextFrom = &pNextFrom[lstrlenA(pNextFrom)+1];
+ if (!b_MultiFrom && !b_MultiTo)
+ b_MultiFrom = (pNextFrom[0]);
+
+ pFromFile = SHFileStrCpyCatA(pTempFrom, pFrom, NULL);
+
+ if (pTo)
+ {
+ pToFile = SHFileStrCpyCatA(pTempTo, pTo, NULL);
+ if (!(pToFile))
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x402;
+ goto shfileop_error;
+ } /* endif */
+ b_ToTailSlash = (!pToFile[1]);
+ if (b_ToTailSlash)
+ {
+ pToFile[0] = '\0';
+ if (strchr(pTempTo, '\\'))
+ {
+ pToFile = SHFileStrCpyCatA(pTempTo, NULL, NULL);
+ }
+ }
+ b_ToInvalidTail = (NULL != strpbrk(&pToFile[1], "*?"));
+ }
+
+ if (FO_RENAME == FuncSwitch)
+ {
+ /* temporary only for FO_RENAME */
+ b_Mask = (NULL != strpbrk(pFrom, "*?"));
+ if (b_MultiTo || (pNextFrom[0]) || (b_Mask && !b_ToInvalidTail))
+ {
+ /* no work, only RC=0 */
+ /* ???? nlpFileOp.fAnyOperationsAborted = TRUE; */
+ goto shfileop_normal;
+ }
+ }
+
+ hFind = (!(pFromFile) || !(pFromFile[1])) ? INVALID_HANDLE_VALUE : FindFirstFileA(pFrom, &wfd);
+ if (INVALID_HANDLE_VALUE == hFind)
+ {
+ /* root (without mask) is also not allowed as source, tested in W98 */
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x402;
+ goto shfileop_error;
+ } /* endif */
+
+ /* for all */
+ #define HIGH_ADR (LPSTR)0xffffffff
+ b_Mask = (!SHFileStrICmpA(&pFromFile[1], &wfd.cFileName[0], HIGH_ADR, HIGH_ADR));
+
+ if (!pTo) /* FO_DELETE */
+ {
+ do
+ {
+ if (wfd.cFileName[0] == '.')
+ {
+ if (wfd.cFileName[1] == '\0')
+ continue;
+ if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0')
+ continue;
+ }
+ SHFileStrCpyCatA(&pFromFile[1], &wfd.cFileName[0], NULL);
+ if (IsAttribFile(wfd.dwFileAttributes))
+ {
+ nlpFileOp.fAnyOperationsAborted = (!Win32DeleteFileA(pTempFrom));
+ retCode = 0x78; /* value unknown */
+ }
+ else
+ {
+ nlpFileOp.fAnyOperationsAborted = (!SHELL_DeleteDirectoryA(pTempFrom, FALSE));
+ retCode = 0x78; /* value unknown */
+ }
+ } while (!nlpFileOp.fAnyOperationsAborted && FindNextFileA(hFind, &wfd));
+ FindClose(hFind);
+ hFind = INVALID_HANDLE_VALUE;
+ if (nlpFileOp.fAnyOperationsAborted)
+ {
+ goto shfileop_error;
+ }
+ continue;
+ } /* FO_DELETE ends, pTo must be every valid from here */
+
+ b_SameRoot = (toupper(pTempFrom[0]) == toupper(pTempTo[0]));
+ b_SameTailName = SHFileStrICmpA(pToFile, pFromFile, NULL, NULL);
+
+ /* W98 Bug with FO_MOVE(/RENAME ?) different to FO_COPY, better the same as FO_COPY */
+
+ b_ToValid = ((b_SameTailName && b_SameRoot && (FO_COPY == FuncSwitch)) ||
+ (b_SameTailName && !b_SameRoot) || (b_ToInvalidTail));
+
+ ToPathAttr = ToAttr = GetFileAttributesA(pTempTo);
+ if (!b_Mask && /* IsAttribDir(wfd.dwFileAttributes) && */(ToAttr -1))
+ {
+ if (pToFile)
+ {
+ pToFile[0] = '\0';
+ ToPathAttr = GetFileAttributesA(pTempTo);
+ /* if (-1 != ToPathAttr) */ pToFile[0] = '\\';
+ }
+ }
+ if (FO_RENAME == FuncSwitch)
+ {
+ if (!b_SameRoot || b_Mask /* FO_RENAME works not with Mask */
+ || !SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, NULL)
+ || (SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, HIGH_ADR) && !b_ToTailSlash))
+ {
+ retCode = 0x73;
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ goto shfileop_error;
+ }
+ if (b_ToInvalidTail)
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode=0x2;
+ goto shfileop_error;
+ }
+ if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(ToAttr))
+ {
+ if (b_ToTailSlash)
+ {
+ retCode = 0xb7;
+ }
+ else
+ {
+ retCode = 0x7b;
+ }
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ goto shfileop_error;
+ }
+ if (-1 == ToPathAttr)
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x75;
+ goto shfileop_error;
+ } /* endif */
+ if (!MoveFileA(pTempFrom, pTempTo))
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ /* we need still the value for the returncode, we use the mostly assumed */
+ retCode = 0xb7;
+ goto shfileop_error;
+ }
+ goto shfileop_normal;
+ }
+
+ if (!b_Mask && IsAttribDir(wfd.dwFileAttributes) && (ToAttr -1))
+ {
+ if (pToFile)
+ {
+ pToFile[0] = '\0';
+ ToPathAttr = GetFileAttributesA(pTempTo);
+ if ((ToPathAttr == -1) && b_ToValid)
+ {
+ /* create dir could be used here, sample target D:\y\ *.* create with RC=10003 */
+ if(!SHCreateDirectory(NULL, pTempTo))
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x73;/* value unknown */
+ goto shfileop_error;
+ }
+ ToPathAttr = GetFileAttributesA(pTempTo);
+ }
+ pToFile[0] = '\\';
+ if (b_ToInvalidTail)
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode=0x10003;
+ goto shfileop_error;
+ }
+ }
+ }
+
+ /* handle mask in source */
+ if (b_Mask)
+ {
+ if (!IsAttribDir(ToAttr))
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ if (b_ToInvalidTail && b_SameTailName && (FO_MOVE == FuncSwitch))
+ {
+ retCode = 0x2;
+ }
+ else
+ {
+ retCode = 0x75;
+ }
+ goto shfileop_error;
+ }
+ pToFile = SHFileStrCpyCatA(pTempTo,NULL, "\\");
+ nlpFileOp.fFlags = (nlpFileOp.fFlags | FOF_MULTIDESTFILES);
+ do
+ {
+ if (wfd.cFileName[0] == '.')
+ {
+ if (wfd.cFileName[1] == '\0')
+ continue;
+ if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0') continue;
+ }
+ if (IsAttribDir(wfd.dwFileAttributes) && (nlpFileOp.fFlags & FOF_FILESONLY))
+ {
+ continue; /* next name in pTempFrom(dir) */
+ }
+ SHFileStrCpyCatA(&pToFile[1], &wfd.cFileName[0], NULL);
+ SHFileStrCpyCatA(&pFromFile[1], &wfd.cFileName[0], NULL);
+ retCode = SHFileOperationA (&nlpFileOp);
+ } while (!nlpFileOp.fAnyOperationsAborted && FindNextFileA(hFind, &wfd));
+ }
+ FindClose(hFind);
+ hFind = INVALID_HANDLE_VALUE;
+ /* only FO_COPY/FO_MOVE without mask, FO_DELETE and FO_RENAME are solved */
+ if (b_Mask)
+ continue;
+
+ /* tailling BackSlash is ever removed and pToFile points to BackSlash before */
+ if (!b_MultiTo && (b_MultiFrom || (!(b_Multi) && IsAttribDir(ToAttr))))
+ {
+ if ((FO_MOVE == FuncSwitch) && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
+ {
+ if (b_Multi)
+ {
+ retCode = 0x73; /* !b_Multi = 0x8 ?? */
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ goto shfileop_error;
+ }
+ }
+ pToFile = SHFileStrCpyCatA(&pTempTo[strlen(pTempTo)], "\\", wfd.cFileName);
+ ToAttr = GetFileAttributesA(pTempTo);
+ }
+
+ if (IsAttribDir(ToAttr))
+ {
+ if (IsAttribFile(wfd.dwFileAttributes))
+ {
+ if (FO_COPY == FuncSwitch)
+ {
+ retCode = 0x75;
+ }
+ else
+ {
+ retCode = 0xb7;
+ }
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ goto shfileop_error;
+ }
+ }
+ else
+ {
+ pToFile[0] = '\0';
+ ToPathAttr = GetFileAttributesA(pTempTo);
+ pToFile[0] = '\\';
+ if (IsAttribFile(ToPathAttr))
+ {
+ /* error, is this already tested? */
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x777402;
+ goto shfileop_error;
+ } /* endif */
+ }
+
+ /* singlesource + no mask */
+ if (-1 == (ToAttr & ToPathAttr))
+ {
+ /* Target-dir does not exist, and can not created */
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x75;
+ goto shfileop_error;
+ }
+
+ switch (FuncSwitch)
+ {
+ case FO_MOVE:
+ if ((ToAttr == -1) && SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, NULL))
+ {
+ nlpFileOp.wFunc = ((level + 1) << 4) + FO_RENAME;
+ retCode = SHFileOperationA(&nlpFileOp);
+ }
+ else
+ {
+ if (b_SameRoot && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
+ {
+ pToFile = SHFileStrCpyCatA(pTempFrom, NULL, "\\*.*");
+ retCode = SHFileOperationA(&nlpFileOp);
+ ((WORD*)pToFile)[0] = '\0';
+ }
+ else
+ {
+ nlpFileOp.wFunc = ((level + 1) << 4) + FO_COPY;
+ retCode = SHFileOperationA(&nlpFileOp);
+ } /* endif */
+ if (!nlpFileOp.fAnyOperationsAborted)
+ {
+ nlpFileOp.wFunc = ((level+1)<<4) + FO_DELETE;
+ retCode = SHFileOperationA(&nlpFileOp);
+ } /* endif */
+ }
+ continue;
+ case FO_COPY:
+ if (SHFileStrICmpA(pTempFrom, pTempTo, NULL, NULL))
+ { /* target is the same as source ? */
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ /* we need still the value for the returncode, we assume 0x71 */
+ retCode = 0x71;
+ goto shfileop_error;
+ } /* endif */
+ if (IsAttribDir((ToAttr & wfd.dwFileAttributes)))
+ {
+ if (IsAttribDir(ToAttr) || SHCreateDirectory(NULL, pTempTo))
+ {
+ /* ??? nlpFileOp.fFlags = (nlpFileOp.fFlags | FOF_MULTIDESTFILES); */
+ SHFileStrCpyCatA(pTempFrom, NULL, "\\*.*");
+ retCode = SHFileOperationA(&nlpFileOp);
+ }
+ else
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ retCode = 0x750;/* value unknown */
+ }
+ }
+ else
+ {
+ if (!(ask_overwrite && SHELL_ConfirmDialog (ASK_OVERWRITE_FILE, pTempTo))
+ && (not_overwrite))
+ {
+ nlpFileOp.fAnyOperationsAborted = TRUE;
+ /* we need still the value for the returncode, we use the mostly assumed */
+ retCode = 0x73;
+ goto shfileop_error;
+ }
+ if (!(CopyFileA(pTempFrom, pTempTo, FALSE)))
+ {
+ nlpFileOp.fAnyOperationsAborted=TRUE;
+ retCode = 0x77; /* value unknown */
+ }
+ }
+ } /* end-switch */
+ } /* end-while */
+shfileop_normal:
+ if (!(nlpFileOp.fAnyOperationsAborted))
+ retCode = 0;
+shfileop_error:
+ if (hFind != INVALID_HANDLE_VALUE)
+ FindClose(hFind);
+ hFind = INVALID_HANDLE_VALUE;
+ if (pTempFrom)
+ HeapFree(GetProcessHeap(), 0, pTempFrom);
+
+ TRACE("%s level=%d AnyOpsAborted=%s ret=0x%x, with %s%s%s\n",
+ pToFuncTXT, level, nlpFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
+ retCode, debugstr_a(pFrom), pTo ? " -> ":"", debugstr_a(pTo));
+
+ lpFileOp->fAnyOperationsAborted = nlpFileOp.fAnyOperationsAborted;
+ return retCode;
}
/*************************************************************************
More information about the wine-patches
mailing list