SHFileOperationW 1 : helper functions

Joris Huizer jorishuizer at planet.nl
Fri Dec 16 09:52:03 CST 2005


Oops, by mistake I send this one to wine-dev, sorry... now sending here

This patch adds a simple structure to contain commonly-requested file
properties (named `struct fileops_file_data`, wondering whether that
name should that change?)

Functions added:

-void printFileData():
debugging function, printing contents of a `struct fileops_file_data` thing;
-int shfileops_delete_file()
function to delete given file -- making sure to call the right functions
for either a regular file or a directory
-int shfileop_unmasked_setup()
the extracted code common for move and copy calls
-int shfileop_move_unmasked
the specific code on moving unmasked -- this one does a lot of recursion
on SHFileOperationW
-int shfileop_copy_unmasked
the specific code on copying unmasked -- this one does some recursion too

Further more, I seperated code of deleting, renaming, moving, and
copying, and the overall result is that code becomes simpler - though a
small amount of code is duplicated (mostly in move/copy operations,
that's why I split the largest part of common code in a separate function)

When this patch is accepted I'll submit the rest (that is, the code
using these functions)

-------------- next part --------------
Index: shlfileop.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlfileop.c,v
retrieving revision 1.56
diff -u -p -r1.56 shlfileop.c
--- shlfileop.c	10 Nov 2005 11:15:22 -0000	1.56
+++ shlfileop.c	16 Dec 2005 15:21:05 -0000
@@ -866,9 +866,69 @@ static const char * debug_shfileops_acti
     return wine_dbg_sprintf("%s", cFO_Name[ op ]);
 }
 
+struct fileops_file_data
+{
+  LPCWSTR next;
+  LPCWSTR name;
+  LPWSTR temp;
+  LPWSTR file;
+  DWORD attr;
+  DWORD pathAttr;
+  BOOL multi;
+  BOOL invalidTail;
+  BOOL valid;
+  BOOL tailSlash;
+};
+
+void printFileData(struct fileops_file_data *field)
+{
+
+  TRACE("data on %p:\n"
+      "next: %s\n"
+      "name: %s\n"
+      "temp: %s\n"
+      "file: %s\n"
+      "attr: %lx\n"
+      "pathAttr: %lx\n"
+      "multi: %d\n"
+      "invalidTail: %d\n"
+      "valid: %d\n"
+      "tailSlash: %d\n",
+      field,
+      debugstr_w(field->next),
+      debugstr_w(field->name),
+      debugstr_w(field->temp),
+      debugstr_w(field->file),
+      field->attr,
+      field->pathAttr,
+      field->multi,
+      field->invalidTail,
+      field->valid,
+      field->tailSlash
+      );
+}
+
 #define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026
 #define HIGH_ADR (LPWSTR)0xffffffff
 
+static int shfileops_delete_file(WIN32_FIND_DATAW *wfd,int confirm,LPWSTR pFromFile,LPWSTR pTempFrom)
+{
+  int retCode = 0;
+  LPWSTR lpFileName;
+  lpFileName = wfd->cAlternateFileName;
+  if (!lpFileName[0])
+    lpFileName = wfd->cFileName;
+  SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
+  if (IsAttribFile(wfd->dwFileAttributes))
+  {
+    if(SHNotifyDeleteFileW(pTempFrom) != ERROR_SUCCESS)
+      retCode = 0x78; /* value unknown */
+  }
+  else if(!SHELL_DeleteDirectoryW(pTempFrom,confirm))
+    retCode = 0x79; /* value unknown */
+  return retCode;
+}
+
 /* handle the complete deletion of `pTempFrom` */
 static int shfileops_delete(WIN32_FIND_DATAW *wfd,SHFILEOPSTRUCTW nFileOp, LPWSTR pFromFile,LPWSTR pTempFrom,HANDLE *hFind)
 
@@ -884,20 +944,12 @@ static int shfileops_delete(WIN32_FIND_D
         if (IsDotDir(lpFileName) ||
                 ((b_Mask) && IsAttribDir(wfd->dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
             continue;
-        SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
-        /* TODO: Check the SHELL_DeleteFileOrDirectoryW() function in shell32.dll */
-        if (IsAttribFile(wfd->dwFileAttributes))
-        {
-            if(SHNotifyDeleteFileW(pTempFrom) != ERROR_SUCCESS)
-            {
-                nFileOp.fAnyOperationsAborted = TRUE;
-                retCode = 0x78; /* value unknown */
-            }
-        }
-        else if(!SHELL_DeleteDirectoryW(pTempFrom, (!(nFileOp.fFlags & FOF_NOCONFIRMATION))))
+
+        retCode = shfileops_delete_file(wfd,(nFileOp.fFlags & FOF_NOCONFIRMATION) == 0,pFromFile,pTempFrom);
+        if (retCode)
         {
-            nFileOp.fAnyOperationsAborted = TRUE;
-            retCode = 0x79; /* value unknown */
+          nFileOp.fAnyOperationsAborted = TRUE;
+          break;
         }
     }
     while (!nFileOp.fAnyOperationsAborted && FindNextFileW(*hFind,wfd));
@@ -1001,6 +1053,210 @@ static DWORD shfileops_get_parent_attr(L
     return PathAttr;
 }
 
+static int shfileop_unmasked_setup(WIN32_FIND_DATAW wfd, struct fileops_file_data *to,struct fileops_file_data *from,BOOL b_Multi,long FuncSwitch)
+{
+  int retCode = 0;
+
+  TRACE("b_Multi: %d\n",b_Multi);
+  TRACE("to:\n");
+  printFileData(to);
+  TRACE("from:\n");
+  printFileData(from);
+
+  if (IsAttribDir(wfd.dwFileAttributes) && (to->attr == INVALID_FILE_ATTRIBUTES))
+  {
+    if (to->file)
+    {
+      to->pathAttr = shfileops_get_parent_attr2(to->file,to->temp,to->valid,&retCode);
+      if (retCode)
+        return retCode;
+      if (to->invalidTail)
+      {
+        retCode = 0x10003;
+        return retCode;
+      }
+    }
+  }
+
+  /* trailing BackSlash is ever removed and to->file points to BackSlash before */
+  if (!to->multi && (from->multi || (!(b_Multi) && IsAttribDir(to->attr))))
+  {
+    if ((FO_MOVE == FuncSwitch) && IsAttribDir(to->attr) && IsAttribDir(wfd.dwFileAttributes))
+    {
+      if (b_Multi)
+      {
+        retCode = 0x73; /* !b_Multi = 0x8 ?? */
+        return retCode;
+      }
+    }
+    to->file = SHFileStrCpyCatW(to->temp, NULL, wfd.cFileName);
+    to->attr = GetFileAttributesW(to->temp);
+  }
+
+  if (IsAttribDir(to->attr))
+  {
+    if (IsAttribFile(wfd.dwFileAttributes))
+    {
+      retCode = (FO_COPY == FuncSwitch) ? 0x75 : 0xb7;
+      return retCode;
+    }
+  }
+  else
+  {
+    to->pathAttr = shfileops_get_parent_attr(to->file,to->temp);
+    if (IsAttribFile(to->pathAttr))
+    {
+      /* error, is this tested ? */
+      retCode = 0x777402;
+      return retCode;
+    }
+  }
+
+  /* singlesource + no mask */
+  if (INVALID_FILE_ATTRIBUTES == (to->attr & to->pathAttr))
+  {
+    /* Target-dir does not exist, and cannot be created */
+    retCode=0x75;
+    return retCode;
+  }
+
+  return retCode;
+}
+
+static int shfileop_move_unmasked( SHFILEOPSTRUCTW nFileOp,WIN32_FIND_DATAW wfd, struct fileops_file_data to, struct fileops_file_data from)
+{
+  int retCode = 0;
+  int level = nFileOp.wFunc >> 4;
+
+  BOOL b_SameRoot = (toupperW(from.temp[0]) == toupperW(to.temp[0]));
+
+  to.file = NULL;
+  if ((to.attr == INVALID_FILE_ATTRIBUTES) && SHFileStrICmpW(from.temp, to.temp, from.file, NULL))
+  {
+    nFileOp.wFunc =  ((level+1)<<4) + FO_RENAME;
+  }
+  else
+  {
+    if (b_SameRoot && IsAttribDir(to.attr) && IsAttribDir(wfd.dwFileAttributes))
+    {
+      /* FIXME: moving directory contents into the other one:
+       * - path\\ -> path\\*
+       *   MOVE
+       * - loop over files in path\\*, eg path\\file
+       *   MOVE
+       * - COPY, DELETE
+       *
+       * is this really necessary? why not a dedicated recursive
+       * (light-weight) function?
+       */
+      /* we need to.file for FO_DELETE after FO_MOVE contence */
+      to.file = SHFileStrCpyCatW(from.temp, NULL, wWildcardFile);
+    }
+    else
+    {
+      nFileOp.wFunc =  ((level+1)<<4) + FO_COPY;
+    }
+  }
+
+  switch(nFileOp.wFunc & FO_MASK)
+  {
+    case FO_MOVE:
+      retCode = SHFileOperationW(&nFileOp);
+      break;
+    case FO_RENAME:
+      /*
+         retCode = SHFileOperationW(&nFileOp);
+         */
+      if (SHNotifyMoveFileW(from.temp, to.temp) != ERROR_SUCCESS)
+      {
+        /* we need still the value for the returncode, we use the mostly assumed */
+        retCode = 0xb7;
+        nFileOp.fAnyOperationsAborted = TRUE;
+      }
+      break;
+    case FO_COPY:
+      retCode = SHFileOperationW(&nFileOp);
+      break;
+    default:
+      retCode = SHFileOperationW(&nFileOp);
+      break;
+  }
+
+  if (to.file)
+    ((DWORD*)to.file)[0] = '\0';
+  if (!nFileOp.fAnyOperationsAborted && (FO_RENAME != (nFileOp.wFunc & 0xf)))
+  {
+    /*
+    TRACE("preparing for delete\n");
+    nFileOp.wFunc =  ((level+1)<<4) + FO_DELETE;
+    TRACE("delete: going to execute: %s: flags (0x%04x) : %s\n",
+        debug_shfileops_action(nFileOp.wFunc & FO_MASK), nFileOp.fFlags,
+        debug_shfileops_flags(nFileOp.fFlags) );
+
+       retCode = SHFileOperationW(&nFileOp);
+    TRACE("returned: %d\n",retCode);
+       */
+    retCode = shfileops_delete_file(&wfd,(nFileOp.fFlags & FOF_NOCONFIRMATION) == 0,from.file,from.temp);
+  }
+
+  return retCode;
+}
+
+static int shfileop_copy_unmasked(SHFILEOPSTRUCTW nFileOp,WIN32_FIND_DATAW wfd,struct fileops_file_data to,struct fileops_file_data from)
+{
+  int retCode = 0;
+  BOOL not_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) ||  (nFileOp.fFlags & FOF_RENAMEONCOLLISION));
+  BOOL ask_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) && !(nFileOp.fFlags & FOF_RENAMEONCOLLISION));
+
+  if (SHFileStrICmpW(from.temp, to.temp, NULL, NULL))
+  { /* target is the same as source ? */
+    /* we still need the value for the returncode, we assume 0x71 */
+    retCode = 0x71;
+    return retCode;
+  }
+  if (IsAttribDir((to.attr & wfd.dwFileAttributes)))
+  {
+    if (IsAttribDir(to.attr) || !SHNotifyCreateDirectoryW(to.temp, NULL))
+    {
+      /* FIXME: copying directory contents into the other one:
+       * - path\\ -> path\\*
+       *   COPY
+       * - loop over files in path\\*, eg path\\file
+       *   COPY
+       *
+       * is this really necessary? why not a dedicated recursive
+       * (light-weight) function?
+       */
+      
+      /* ??? nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES); */
+      SHFileStrCpyCatW(from.temp, NULL, wWildcardFile);
+      TRACE("recursive copy\n");
+      retCode = SHFileOperationW(&nFileOp);
+    }
+    else
+    {
+      retCode = 0x750;/* value unknown */
+      return retCode;
+    }
+  }
+  else
+  {
+    if (!(ask_overwrite && SHELL_ConfirmDialogW(ASK_OVERWRITE_FILE, to.temp))
+        && (not_overwrite))
+    {
+      /* we still need the value for the returncode, we use the mostly assumed */
+      retCode = 0x73;
+      return retCode;
+    }
+    if (SHNotifyCopyFileW(from.temp, to.temp, TRUE) != ERROR_SUCCESS)
+    {
+      retCode = 0x77; /* value unknown */
+      return retCode;
+    }
+  }
+  return retCode;
+}
+
 /*************************************************************************
  * SHFileOperationW          [SHELL32.@]
  *



More information about the wine-patches mailing list