shell32: SHCreateDirectoryEx; implement recursive directory creation (patch3)

Rolf Kalbermatter rolf.kalbermatter at citeng.com
Wed Oct 20 17:47:26 CDT 2004


Changelog
  dlls/shell32/shlfileop.c
    - SHCreateDirectory should create intermediate directories if necessary
    - Remove extra boolean parameter in SHNotifyMoveFile as it is not used
    - Use in SHFileOperation the function SHNotifyCreateDirectory instead of SHCreateDirectoryEx
      as it does not anymore what is needed here
    - Fix several unsigned/signed mismatch warnings

License: X11/LGPL

Rolf Kalbermatter

Index: shlfileop.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlfileop.c,v
retrieving revision 1.45
diff -u -r1.45 shlfileop.c
--- shlfileop.c	18 Oct 2004 21:45:16 -0000	1.45
+++ shlfileop.c	20 Oct 2004 22:36:12 -0000
@@ -3,8 +3,8 @@
  *
  * Copyright 2000 Juergen Schmied
  * Copyright 2002 Andriy Palamarchuk
- * Copyright 2002 Dietrich Teickner (from Odin)
- * Copyright 2002 Rolf Kalbermatter
+ * Copyright 2004 Dietrich Teickner (from Odin)
+ * Copyright 2004 Rolf Kalbermatter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,8 +19,10 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * !!! shlfileop.c is shared source between wine and odin, do not remove
+ * #ifdef __WIN32OS2__ .. lines
  */
-
 #include "config.h"
 #include "wine/port.h"
 
@@ -56,15 +58,16 @@
 static const WCHAR wWildcardChars[] = {'*','?',0};
 static const WCHAR wBackslash[] = {'\\',0};
 
-static BOOL SHELL_DeleteDirectoryW(LPCWSTR pszDir, BOOL bShowUI);
+static BOOL SHELL_DeleteDirectoryW(LPCWSTR path, BOOL bShowUI);
 static DWORD SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec);
 static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec);
 static DWORD SHNotifyRemoveDirectoryA(LPCSTR path);
 static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path);
 static DWORD SHNotifyDeleteFileA(LPCSTR path);
 static DWORD SHNotifyDeleteFileW(LPCWSTR path);
-static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest, BOOL bRenameIfExists);
-static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bRenameIfExists);
+static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest);
+static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists);
+static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly);
 
 typedef struct
 {
@@ -152,9 +155,10 @@
 }
 
 /**************************************************************************
- * SHELL_DeleteDirectoryA()  [internal]
+ * SHELL_DeleteDirectory()  [internal]
  *
- * like rm -r
+ * Asks for confirmation when bShowUI is true and deletes the directory and
+ * all its subdirectories and files if necessary.
  */
 BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
 {
@@ -254,8 +258,6 @@
 	return retCode;
 }
 
-/**********************************************************************/
-
 static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
 {
 	TRACE("(%s, %p)\n", debugstr_w(path), sec);
@@ -268,8 +270,6 @@
 	return GetLastError();
 }
 
-/**********************************************************************/
-
 BOOL WINAPI Win32CreateDirectoryAW(LPCVOID path, LPSECURITY_ATTRIBUTES sec)
 {
 	if (SHELL_OsIsUnicode())
@@ -292,7 +292,6 @@
  *  Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI.
  *  This is Unicode on NT/2000
  */
-
 static DWORD SHNotifyRemoveDirectoryA(LPCSTR path)
 {
 	LPWSTR wPath;
@@ -309,8 +308,6 @@
 	return retCode;
 }
 
-/***********************************************************************/
-
 static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path)
 {
 	BOOL ret;
@@ -333,8 +330,6 @@
 	return GetLastError();
 }
 
-/***********************************************************************/
-
 BOOL WINAPI Win32RemoveDirectoryAW(LPCVOID path)
 {
 	if (SHELL_OsIsUnicode())
@@ -357,7 +352,6 @@
  *  Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI.
  *  This is Unicode on NT/2000
  */
-
 static DWORD SHNotifyDeleteFileA(LPCSTR path)
 {
 	LPWSTR wPath;
@@ -374,8 +368,6 @@
 	return retCode;
 }
 
-/***********************************************************************/
-
 static DWORD SHNotifyDeleteFileW(LPCWSTR path)
 {
 	BOOL ret;
@@ -399,8 +391,6 @@
 	return GetLastError();
 }
 
-/***********************************************************************/
-
 DWORD WINAPI Win32DeleteFileAW(LPCVOID path)
 {
 	if (SHELL_OsIsUnicode())
@@ -416,35 +406,29 @@
  * PARAMS
  *  src        [I]   path to source file to move
  *  dest       [I]   path to target file to move to
- *  bRename    [I]   if TRUE, the target file will be renamed if a
- *                   file with this name already exists
  *
  * RETURNS
  *  ERORR_SUCCESS if successful
  */
-static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest, BOOL bRename)
+static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest)
 {
 	BOOL ret;
 
-	TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bRename ? "renameIfExists" : "");
+	TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest));
 
 	ret = MoveFileW(src, dest);
 	if (!ret)
 	{
-	  /* Source file may be write protected or a system file */
-	  DWORD dwAttr = GetFileAttributesW(src);
-	  if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
-	    if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
-	      ret = MoveFileW(src, dest);
+	  DWORD dwAttr;
 
-	  if (!ret && bRename)
+	  dwAttr = SHFindAttrW(dest, FALSE);
+	  if (INVALID_FILE_ATTRIBUTES == dwAttr)
 	  {
-	    /* Destination file probably exists */
-	    dwAttr = GetFileAttributesW(dest);
-	    if (dwAttr != INVALID_FILE_ATTRIBUTES)
-	    {
-	      FIXME("Rename on move to existing file not implemented!\n");
-	    }
+	    /* Source file may be write protected or a system file */
+	    dwAttr = GetFileAttributesW(src);
+	    if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
+	      if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
+	        ret = MoveFileW(src, dest);
 	  }
 	}
 	if (ret)
@@ -461,30 +445,21 @@
  * Copies a file. Also triggers a change notify if one exists.
  *
  * PARAMS
- *  src        [I]   path to source file to move
- *  dest       [I]   path to target file to move to
- *  bRename    [I]   if TRUE, the target file will be renamed if a
- *                   file with this name already exists
+ *  src           [I]   path to source file to move
+ *  dest          [I]   path to target file to move to
+ *  bFailIfExists [I]   if TRUE, the target file will not be overwritten if
+ *                      a file with this name already exists
  *
  * RETURNS
  *  ERROR_SUCCESS if successful
  */
-static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bRename)
+static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists)
 {
 	BOOL ret;
 
-	TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bRename ? "renameIfExists" : "");
+	TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : "");
 
-	ret = CopyFileW(src, dest, TRUE);
-	if (!ret && bRename)
-	{
-	  /* Destination file probably exists */
-	  DWORD dwAttr = GetFileAttributesW(dest);
-	  if (dwAttr != INVALID_FILE_ATTRIBUTES)
-	  {
-	    FIXME("Rename on copy to existing file not implemented!\n");
-	  }
-	}
+	ret = CopyFileW(src, dest, bFailIfExists);
 	if (ret)
 	{
 	  SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
@@ -546,7 +521,9 @@
  *  ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
  *
  *  FIXME: Not implemented yet;
- *  SHCreateDirectoryEx also verifies that the files will be visible. If not:
+ *  SHCreateDirectoryEx also verifies that the files in the directory will be visible
+ *  if the path is a network path to deal with network drivers which might have a limited
+ *  but unknown maximum path length. If not:
  *
  *  If hWnd is set to a valid window handle, a message box is displayed warning
  *  the user that the files may not be accessible. If the user chooses not to
@@ -591,16 +568,76 @@
 	      ret != ERROR_ALREADY_EXISTS &&
 	      ret != ERROR_FILENAME_EXCED_RANGE)
 	  {
-	  /* handling network file names?
-	    lstrcpynW(pathName, path, MAX_PATH);
-	    lpStr = PathAddBackslashW(pathName);*/
-	    FIXME("Semi-stub, non zero hWnd should be used somehow?\n");
+	    WCHAR *pEnd, *pSlash, szTemp[MAX_PATH + 1];  /* extra for PathAddBackslash() */
+
+	    lstrcpynW(szTemp, path, MAX_PATH);
+	    pEnd = PathAddBackslashW(szTemp);
+	    pSlash = szTemp + 3;
+
+	    while (*pSlash)
+	    {
+	      while (*pSlash && *pSlash != '\\')
+	        pSlash = CharNextW(pSlash);
+
+	      if (*pSlash)
+	      {
+	        *pSlash = 0;    /* terminate path at seperator */
+
+	        ret = SHNotifyCreateDirectoryW(szTemp, pSlash + 1 == pEnd ? sec : NULL);
+	      }
+	      *pSlash++ = '\\'; /* put the seperator back */
+	    }
+	  }
+
+	  if (ret && hWnd && (ERROR_CANCELLED != ret))
+	  {
+	    /* We failed and should show a dialog box */
+	    FIXME("Show system error message, creating path %s, failed with error %d\n", debugstr_w(path), ret);
+	    ret = ERROR_CANCELLED; /* Error has been already presented to user (not really yet!) */
 	  }
 	}
 	return ret;
 }
 
 /*************************************************************************
+ * SHFindAttrW      [internal]
+ *
+ * Get the Attributes for a file or directory. The difference to GetAttributes()
+ * is that this function will also work for paths containing wildcard characters
+ * in its filename.
+
+ * PARAMS
+ *  path       [I]   path of directory or file to check
+ *  fileOnly   [I]   TRUE if only files should be found
+ *
+ * RETURNS
+ *  INVALID_FILE_ATTRIBUTES if the path does not exist, the actual attributes of
+ *  the first file or directory found otherwise
+ */
+static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly)
+{
+	WIN32_FIND_DATAW wfd;
+	BOOL b_FileMask = fileOnly && (NULL != StrPBrkW(pName, wWildcardChars));
+	DWORD dwAttr = INVALID_FILE_ATTRIBUTES;
+	HANDLE hFind = FindFirstFileW(pName, &wfd);
+
+	TRACE("%s %d\n", debugstr_w(pName), fileOnly);
+	if (INVALID_HANDLE_VALUE != hFind)
+	{
+	  do
+	  {
+	    if (b_FileMask && IsAttribDir(wfd.dwFileAttributes))
+	       continue;
+	    dwAttr = wfd.dwFileAttributes;
+	    break;
+	  }
+	  while (FindNextFileW(hFind, &wfd));
+	  FindClose(hFind);
+	}
+	return dwAttr;
+}
+
+/*************************************************************************
  *
  * SHFileStrICmp HelperFunction for SHFileOperationW
  *
@@ -690,7 +727,7 @@
 	{
 	  if (NULL == StrPBrkW(pszFiles1, wWildcardChars))
 	  {
-	    if (-1 == GetFileAttributesW(pszFiles1))
+	    if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(pszFiles1))
 	      return FALSE;
 	  }
 	  pszFiles1 += lstrlenW(pszFiles1) + 1;
@@ -1070,7 +1107,7 @@
 	    b_SameTailName = SHFileStrICmpW(pToFile, pFromFile, NULL, NULL);
 
 	    ToPathAttr = ToAttr = GetFileAttributesW(pTempTo);
-	    if (!b_Mask && (ToAttr == -1) && (pToFile))
+	    if (!b_Mask && (ToAttr == INVALID_FILE_ATTRIBUTES) && (pToFile))
 	    {
                 pToFile[0] = '\0';
                 ToPathAttr = GetFileAttributesW(pTempTo);
@@ -1091,7 +1128,7 @@
                     retCode=0x2;
                     goto shfileop_end;
                 }
-                if (-1 == ToPathAttr)
+                if (INVALID_FILE_ATTRIBUTES == ToPathAttr)
                 {
                     retCode = 0x75;
                     goto shfileop_end;
@@ -1102,7 +1139,7 @@
                     goto shfileop_end;
                 }
                 /* we use SHNotifyMoveFile() instead MoveFileW */
-                if (SHNotifyMoveFileW(pTempFrom, pTempTo, nFileOp.fFlags & FOF_RENAMEONCOLLISION) != ERROR_SUCCESS)
+                if (SHNotifyMoveFileW(pTempFrom, pTempTo) != ERROR_SUCCESS)
                 {
                     /* we need still the value for the returncode, we use the mostly assumed */
                     retCode = 0xb7;
@@ -1146,16 +1183,16 @@
                 continue;
 
 	    /* only FO_COPY/FO_MOVE without mask, all others are (must be) solved */
-	    if (IsAttribDir(wfd.dwFileAttributes) && (ToAttr == -1))
+	    if (IsAttribDir(wfd.dwFileAttributes) && (ToAttr == INVALID_FILE_ATTRIBUTES))
 	    {
                 if (pToFile)
                 {
                     pToFile[0] = '\0';
                     ToPathAttr = GetFileAttributesW(pTempTo);
-                    if ((ToPathAttr == -1) && b_ToValid)
+                    if ((ToPathAttr == INVALID_FILE_ATTRIBUTES) && b_ToValid)
                     {
                         /* create dir must be here, sample target D:\y\ *.* create with RC=10003 */
-                        if (SHCreateDirectoryExW(NULL, pTempTo, NULL))
+                        if (SHNotifyCreateDirectoryW(pTempTo, NULL))
                         {
                             retCode = 0x73;/* value unknown */
                             goto shfileop_end;
@@ -1208,7 +1245,7 @@
 	    }
 
 	    /* singlesource + no mask */
-	    if (-1 == (ToAttr & ToPathAttr))
+	    if (INVALID_FILE_ATTRIBUTES == (ToAttr & ToPathAttr))
 	    {
                 /* Target-dir does not exist, and cannot be created */
                 retCode=0x75;
@@ -1219,7 +1256,7 @@
 	    {
 	    case FO_MOVE:
                 pToFile = NULL;
-                if ((ToAttr == -1) && SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL))
+                if ((ToAttr == INVALID_FILE_ATTRIBUTES) && SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL))
                 {
                     nFileOp.wFunc =  ((level+1)<<4) + FO_RENAME;
                 }
@@ -1253,7 +1290,7 @@
                 }
                 if (IsAttribDir((ToAttr & wfd.dwFileAttributes)))
                 {
-                    if (IsAttribDir(ToAttr) || !SHCreateDirectoryExW(NULL,pTempTo, NULL))
+                    if (IsAttribDir(ToAttr) || !SHNotifyCreateDirectoryW(pTempTo, NULL))
                     {
                         /* ??? nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES); */
                         SHFileStrCpyCatW(pTempFrom, NULL, wWildcardFile);
@@ -1274,7 +1311,7 @@
                         retCode = 0x73;
                         goto shfileop_end;
                     }
-                    if (SHNotifyCopyFileW(pTempFrom, pTempTo, nFileOp.fFlags & FOF_RENAMEONCOLLISION) != ERROR_SUCCESS)
+                    if (SHNotifyCopyFileW(pTempFrom, pTempTo, TRUE) != ERROR_SUCCESS)
                     {
                         retCode = 0x77; /* value unknown */
                         goto shfileop_end;





More information about the wine-patches mailing list