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