Changeset 9833 for trunk/src


Ignore:
Timestamp:
Feb 22, 2003, 10:45:14 AM (23 years ago)
Author:
sandervl
Message:

DT: Shell file operation updates

Location:
trunk/src/shell32
Files:
1 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/shell32/shlfileop.c

    r9808 r9833  
    1 
    21/*
    32 * SHFileOperation
     
    3837#include "wine/debug.h"
    3938
     39#define IsAttribFile(x) (!(x == -1) && !(x & FILE_ATTRIBUTE_DIRECTORY))
     40#define IsAttribDir(x)  (!(x == -1) && (x & FILE_ATTRIBUTE_DIRECTORY))
     41
     42#define IsDotDir(x)     ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
     43
    4044WINE_DEFAULT_DEBUG_CHANNEL(shell);
    4145
    42 BOOL SHELL_ConfirmDialog (int nKindOfDialog, LPCSTR szDir)
    43 {
    44         char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
     46CHAR aWildcardFile[] = {'*','.','*',0};
     47WCHAR wWildcardFile[] = {'*','.','*',0};
     48WCHAR wWildcardChars[] = {'*','?',0};
     49WCHAR wBackslash[] = {'\\',0};
     50
     51static BOOL SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec);
     52static BOOL SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec);
     53static BOOL SHNotifyRemoveDirectoryA(LPCSTR path);
     54static BOOL SHNotifyRemoveDirectoryW(LPCWSTR path);
     55static BOOL SHNotifyDeleteFileA(LPCSTR path);
     56static BOOL SHNotifyDeleteFileW(LPCWSTR path);
     57
     58typedef struct
     59{
    4560        UINT caption_resource_id, text_resource_id;
    46 
    47   switch(nKindOfDialog) {
    48 
    49   case ASK_DELETE_FILE:
    50     caption_resource_id  = IDS_DELETEITEM_CAPTION;
    51     text_resource_id  = IDS_DELETEITEM_TEXT;
    52     break;
    53   case ASK_DELETE_FOLDER:
    54     caption_resource_id  = IDS_DELETEFOLDER_CAPTION;
    55     text_resource_id  = IDS_DELETEITEM_TEXT;
    56     break;
    57   case ASK_DELETE_MULTIPLE_ITEM:
    58     caption_resource_id  = IDS_DELETEITEM_CAPTION;
    59     text_resource_id  = IDS_DELETEMULTIPLE_TEXT;
    60     break;
    61   case ASK_OVERWRITE_FILE:
    62     caption_resource_id  = IDS_OVERWRITEFILE_CAPTION;
    63     text_resource_id  = IDS_OVERWRITEFILE_TEXT;
    64     break;
    65   default:
    66     FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
    67     return FALSE;
    68   }
    69 
    70   LoadStringA(shell32_hInstance, caption_resource_id, szCaption, sizeof(szCaption));
    71   LoadStringA(shell32_hInstance, text_resource_id, szText, sizeof(szText));
    72 
    73   FormatMessageA(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
    74       szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
    75 
    76   return (IDOK == MessageBoxA(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
     61} SHELL_ConfirmIDstruc;
     62
     63static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids)
     64{
     65        switch (nKindOfDialog) {
     66          case ASK_DELETE_FILE:
     67            ids->caption_resource_id  = IDS_DELETEITEM_CAPTION;
     68            ids->text_resource_id  = IDS_DELETEITEM_TEXT;
     69            return TRUE;
     70          case ASK_DELETE_FOLDER:
     71            ids->caption_resource_id  = IDS_DELETEFOLDER_CAPTION;
     72            ids->text_resource_id  = IDS_DELETEITEM_TEXT;
     73            return TRUE;
     74          case ASK_DELETE_MULTIPLE_ITEM:
     75            ids->caption_resource_id  = IDS_DELETEITEM_CAPTION;
     76            ids->text_resource_id  = IDS_DELETEMULTIPLE_TEXT;
     77            return TRUE;
     78          case ASK_OVERWRITE_FILE:
     79            ids->caption_resource_id  = IDS_OVERWRITEFILE_CAPTION;
     80            ids->text_resource_id  = IDS_OVERWRITEFILE_TEXT;
     81            return TRUE;
     82          default:
     83            FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
     84        }
     85        return FALSE;
     86}
     87
     88BOOL SHELL_ConfirmDialog(int nKindOfDialog, LPCSTR szDir)
     89{
     90        CHAR szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
     91        SHELL_ConfirmIDstruc ids;
     92
     93        if (!SHELL_ConfirmIDs(nKindOfDialog, &ids))
     94          return FALSE;
     95
     96        LoadStringA(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption));
     97        LoadStringA(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText));
     98
     99        FormatMessageA(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
     100                       szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
     101
     102        return (IDOK == MessageBoxA(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
     103}
     104
     105BOOL SHELL_ConfirmDialogW(int nKindOfDialog, LPCWSTR szDir)
     106{
     107        WCHAR szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
     108        SHELL_ConfirmIDstruc ids;
     109
     110        if (!SHELL_ConfirmIDs(nKindOfDialog, &ids))
     111          return FALSE;
     112
     113        LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption));
     114        LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText));
     115
     116        FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
     117                       szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
     118
     119        return (IDOK == MessageBoxW(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
    77120}
    78121
     
    82125 * like rm -r
    83126 */
    84 
    85127BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
    86128{
    87   BOOL    ret = TRUE;
    88   HANDLE  hFind;
    89   WIN32_FIND_DATAA wfd;
    90         char            szTemp[MAX_PATH];
     129        BOOL    ret = TRUE;
     130        HANDLE  hFind;
     131        WIN32_FIND_DATAA wfd;
     132        char    szTemp[MAX_PATH];
    91133
    92134        /* Make sure the directory exists before eventually prompting the user */
    93         PathCombineA(szTemp, pszDir, "*.*");
    94   hFind = FindFirstFileA(szTemp, &wfd);
     135        PathCombineA(szTemp, pszDir, aWildcardFile);
     136        hFind = FindFirstFileA(szTemp, &wfd);
    95137        if (hFind == INVALID_HANDLE_VALUE)
    96138          return FALSE;
     
    100142          do
    101143          {
    102             if (lstrcmpA(wfd.cFileName, ".") && lstrcmpA(wfd.cFileName, ".."))
    103       {
    104               PathCombineA(szTemp, pszDir, wfd.cFileName);
    105               if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
    106                 ret = SHELL_DeleteDirectoryA(szTemp, FALSE);
    107               else
    108                 ret = DeleteFileA(szTemp);
    109             }
     144            LPSTR lp = wfd.cAlternateFileName;
     145            if (!lp[0])
     146              lp = wfd.cFileName;
     147            if (IsDotDir(lp))
     148              continue;
     149            PathCombineA(szTemp, pszDir, lp);
     150            if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
     151              ret = SHELL_DeleteDirectoryA(szTemp, FALSE);
     152            else
     153              ret = SHNotifyDeleteFileA(szTemp);
    110154          } while (ret && FindNextFileA(hFind, &wfd));
    111155        }
    112156        FindClose(hFind);
    113157        if (ret)
    114           ret = RemoveDirectoryA(pszDir);
     158          ret = SHNotifyRemoveDirectoryA(pszDir);
     159        return ret;
     160}
     161
     162BOOL SHELL_DeleteDirectoryW(LPCWSTR pszDir, BOOL bShowUI)
     163{
     164        BOOL    ret = TRUE;
     165        HANDLE  hFind;
     166        WIN32_FIND_DATAW wfd;
     167        WCHAR   szTemp[MAX_PATH];
     168
     169        /* Make sure the directory exists before eventually prompting the user */
     170        PathCombineW(szTemp, pszDir, wWildcardFile);
     171        hFind = FindFirstFileW(szTemp, &wfd);
     172        if (hFind == INVALID_HANDLE_VALUE)
     173          return FALSE;
     174
     175        if (!bShowUI || SHELL_ConfirmDialogW(ASK_DELETE_FOLDER, pszDir))
     176        {
     177          do
     178          {
     179            LPWSTR lp = wfd.cAlternateFileName;
     180            if (!lp[0])
     181              lp = wfd.cFileName;
     182            if (IsDotDir(lp))
     183              continue;
     184            PathCombineW(szTemp, pszDir, lp);
     185            if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
     186              ret = SHELL_DeleteDirectoryW(szTemp, FALSE);
     187            else
     188              ret = SHNotifyDeleteFileW(szTemp);
     189          } while (ret && FindNextFileW(hFind, &wfd));
     190        }
     191        FindClose(hFind);
     192        if (ret)
     193          ret = SHNotifyRemoveDirectoryW(pszDir);
    115194        return ret;
    116195}
     
    119198 *  SHELL_DeleteFileA()
    120199 */
    121 
    122200BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
    123201{
     
    125203          return FALSE;
    126204
    127         return DeleteFileA(pszFile);
     205        return SHNotifyDeleteFileA(pszFile);
     206}
     207
     208BOOL SHELL_DeleteFileW(LPCWSTR pszFile, BOOL bShowUI)
     209{
     210        if (bShowUI && !SHELL_ConfirmDialogW(ASK_DELETE_FILE, pszFile))
     211          return FALSE;
     212
     213        return SHNotifyDeleteFileW(pszFile);
    128214}
    129215
     
    133219 * Creates a directory. Also triggers a change notify if one exists.
    134220 */
    135 static BOOL Win32CreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec)
     221static BOOL SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec)
    136222{
    137223        BOOL ret;
    138         TRACE("(%%s, %p)\n", debugstr_a(path), sec);
     224        TRACE("(%s, %p)\n", debugstr_a(path), sec);
    139225
    140226        ret = CreateDirectoryA(path, sec);
     
    146232}
    147233
    148 static BOOL Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
     234static BOOL SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
    149235{
    150236        BOOL ret;
    151         TRACE("(%%s, %p)\n", debugstr_w(path), sec);
     237        TRACE("(%s, %p)\n", debugstr_w(path), sec);
    152238
    153239        ret = CreateDirectoryW(path, sec);
     
    159245}
    160246
    161 BOOL WINAPI Win32CreateirectoryAW(LPCVOID path, LPSECURITY_ATTRIBUTES sec)
     247BOOL WINAPI Win32CreateDirectoryAW(LPCVOID path, LPSECURITY_ATTRIBUTES sec)
    162248{
    163249        if (SHELL_OsIsUnicode())
    164           return Win32CreateDirectoryW(path, sec);
    165         return Win32CreateDirectoryA(path, sec);
     250          return SHNotifyCreateDirectoryW(path, sec);
     251        return SHNotifyCreateDirectoryA(path, sec);
    166252}
    167253
     
    171257 * Deletes a directory. Also triggers a change notify if one exists.
    172258 */
    173 static BOOL Win32RemoveDirectoryA(LPCSTR path)
    174 {
    175         DWORD attr;
     259static BOOL SHNotifyRemoveDirectoryA(LPCSTR path)
     260{
    176261        BOOL ret;
    177         TRACE("(%%s)\n", debugstr_a(path));
    178        
     262        TRACE("(%s)\n", debugstr_a(path));
     263
    179264        ret = RemoveDirectoryA(path);
    180265        if (!ret)
    181266        {
    182           attr = GetFileAttributesA(path);
    183           if (attr != -1 && attr & FILE_ATTRIBUTE_READONLY)
    184           {
    185             SetFileAttributesA(path, attr & ~FILE_ATTRIBUTE_READONLY);
    186             ret = RemoveDirectoryA(path);
    187           }
     267          /* Directory may be write protected */
     268          DWORD dwAttr = GetFileAttributesA(path);
     269          if (dwAttr != -1 && dwAttr & FILE_ATTRIBUTE_READONLY)
     270            if (SetFileAttributesA(path, dwAttr & ~FILE_ATTRIBUTE_READONLY))
     271              ret = RemoveDirectoryA(path);
    188272        }
    189273        if (ret)
    190         {
    191274          SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA, path, NULL);
    192         }
    193275        return ret;
    194276}
    195277
    196 static BOOL Win32RemoveDirectoryW(LPCWSTR path)
    197 {
    198         DWORD attr;
     278static BOOL SHNotifyRemoveDirectoryW(LPCWSTR path)
     279{
    199280        BOOL ret;
    200         TRACE("(%%s)\n", debugstr_w(path));
    201        
     281        TRACE("(%s)\n", debugstr_w(path));
     282
    202283        ret = RemoveDirectoryW(path);
    203284        if (!ret)
    204285        {
    205           attr = GetFileAttributesW(path);
    206           if (attr != -1 && attr & FILE_ATTRIBUTE_READONLY)
    207           {
    208             SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
    209             ret = RemoveDirectoryW(path);
    210           }
     286          /* Directory may be write protected */
     287          DWORD dwAttr = GetFileAttributesW(path);
     288          if (dwAttr != -1 && dwAttr & FILE_ATTRIBUTE_READONLY)
     289            if (SetFileAttributesW(path, dwAttr & ~FILE_ATTRIBUTE_READONLY))
     290              ret = RemoveDirectoryW(path);
    211291        }
    212292        if (ret)
    213         {
    214293          SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, path, NULL);
    215         }
    216294        return ret;
    217295}
     
    220298{
    221299        if (SHELL_OsIsUnicode())
    222           return Win32RemoveDirectoryW(path);
    223         return Win32RemoveDirectoryA(path);
     300          return SHNotifyRemoveDirectoryW(path);
     301        return SHNotifyRemoveDirectoryA(path);
    224302}
    225303
     
    233311 *  This is Unicode on NT/2000
    234312 */
    235 static BOOL Win32DeleteFileA(LPCSTR path)
     313static BOOL SHNotifyDeleteFileA(LPCSTR path)
    236314{
    237315        BOOL ret;
     
    244322          /* File may be write protected or a system file */
    245323          DWORD dwAttr = GetFileAttributesA(path);
    246           if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
     324          if ((dwAttr != -1) && (dwAttr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
    247325            if (SetFileAttributesA(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
    248326              ret = DeleteFileA(path);
     
    253331}
    254332
    255 static BOOL Win32DeleteFileW(LPCWSTR path)
     333static BOOL SHNotifyDeleteFileW(LPCWSTR path)
    256334{
    257335        BOOL ret;
    258        
     336
    259337        TRACE("(%s)\n", debugstr_w(path));
    260338
     
    264342          /* File may be write protected or a system file */
    265343          DWORD dwAttr = GetFileAttributesW(path);
    266           if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
     344          if ((dwAttr != -1) && (dwAttr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
    267345            if (SetFileAttributesW(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
    268346              ret = DeleteFileW(path);
     
    276354{
    277355        if (SHELL_OsIsUnicode())
    278           return Win32DeleteFileW(path);
    279         return Win32DeleteFileA(path);
     356          return SHNotifyDeleteFileW(path);
     357        return SHNotifyDeleteFileA(path);
    280358}
    281359
     
    321399        else
    322400        {
    323           if (!Win32CreateDirectoryW(path, sec))
     401          if (!SHNotifyCreateDirectoryW(path, sec))
    324402          {
    325403            ret = GetLastError();
     
    339417/*************************************************************************
    340418 *
    341  * SHFileStrICmp HelperFunction for SHFileOperationA
    342  *
    343  */
    344 BOOL SHFileStrICmpA(LPSTR p1,LPSTR p2, LPSTR p1End, LPSTR p2End)
    345 {
    346   CHAR C1 = '\0';
    347   CHAR C2 = '\0';
    348   int i_Temp = -1;
    349   int i_len1 = lstrlenA(p1);
    350   int i_len2 = lstrlenA(p2);
    351 
    352   if (p1End && (&p1[i_len1] >= p1End) && ('\\' == p1End[0]))
    353   {
    354      C1 = p1End[0];
    355     p1End[0] = '\0';
    356     i_len1 = lstrlenA(p1);
    357   }
    358   if (p2End)
    359   {
    360     if ((&p2[i_len2] >= p2End) && ('\\' == p2End[0]))
    361     {
    362       C2 = p2End[0];
    363       if (C2)
    364         p2End[0] = '\0';
    365     }
    366   }
    367   else
    368   {
    369     if ((i_len1 <= i_len2) && ('\\' == p2[i_len1]))
    370     {
    371       C2 = p2[i_len1];
    372       if (C2)
    373         p2[i_len1] = '\0';
    374     }
    375   }
    376   i_len2 = lstrlenA(p2);
    377   if (i_len1 == i_len2)
    378     i_Temp = lstrcmpiA(p1,p2);
    379   if (C1)
    380     p1[i_len1] = C1;
    381   if (C2)
    382     p2[i_len2] = C2;
    383   return !(i_Temp);
    384 }
    385 /*************************************************************************
    386  *
    387  * SHFileStrCpyCat HelperFunction for SHFileOperationA/W
    388  *
    389  */
    390 #define I_SHFileStrCpyCatA
    391 #include "shlfileop.h"
    392 #define I_SHFileStrCpyCatW
    393 #include "shlfileop.h"
    394 
     419 * SHFileStrICmp HelperFunction for SHFileOperationW
     420 *
     421 */
     422BOOL SHFileStrICmpW(LPWSTR p1, LPWSTR p2, LPWSTR p1End, LPWSTR p2End)
     423{
     424        WCHAR C1 = '\0';
     425        WCHAR C2 = '\0';
     426        int i_Temp = -1;
     427        int i_len1 = lstrlenW(p1);
     428        int i_len2 = lstrlenW(p2);
     429
     430        if (p1End && (&p1[i_len1] >= p1End) && ('\\' == p1End[0]))
     431        {
     432          C1 = p1End[0];
     433          p1End[0] = '\0';
     434          i_len1 = lstrlenW(p1);
     435        }
     436        if (p2End)
     437        {
     438          if ((&p2[i_len2] >= p2End) && ('\\' == p2End[0]))
     439          {
     440            C2 = p2End[0];
     441            if (C2)
     442              p2End[0] = '\0';
     443          }
     444        }
     445        else
     446        {
     447          if ((i_len1 <= i_len2) && ('\\' == p2[i_len1]))
     448          {
     449            C2 = p2[i_len1];
     450            if (C2)
     451              p2[i_len1] = '\0';
     452          }
     453        }
     454        i_len2 = lstrlenW(p2);
     455        if (i_len1 == i_len2)
     456          i_Temp = lstrcmpiW(p1,p2);
     457        if (C1)
     458          p1[i_len1] = C1;
     459        if (C2)
     460          p2[i_len2] = C2;
     461        return !(i_Temp);
     462}
     463
     464/*************************************************************************
     465 *
     466 * SHFileStrCpyCat HelperFunction for SHFileOperationW
     467 *
     468 */
     469LPWSTR SHFileStrCpyCatW(LPWSTR pTo, LPCWSTR pFrom, LPCWSTR pCatStr)
     470{
     471        LPWSTR pToFile = NULL;
     472        int  i_len;
     473        if (pTo)
     474        {
     475          if (pFrom)
     476            lstrcpyW(pTo, pFrom);
     477          if (pCatStr)
     478          {
     479            i_len = lstrlenW(pTo);
     480            if ((i_len) && (pTo[--i_len] != '\\'))
     481              i_len++;
     482            pTo[i_len] = '\\';
     483            if (pCatStr[0] == '\\')
     484              pCatStr++; \
     485            lstrcpyW(&pTo[i_len+1], pCatStr);
     486          }
     487          pToFile = StrRChrW(pTo,NULL,'\\');
     488/* !! termination of the new string-group */
     489          pTo[(lstrlenW(pTo)) + 1] = '\0';
     490        }
     491        return pToFile;
     492}
     493
     494/*************************************************************************
     495 *
     496 * SHName(s)Translate HelperFunction for SHFileOperationA
     497 *
     498 */
     499DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more)
     500{
     501        DWORD retSize = 0, size;
     502        LPCSTR aString = (LPSTR)pWToFrom[0];
     503        if (pWToFrom[0])
     504        {
     505          if (wString[0]) /* only in the second loop */
     506            pWToFrom[0] = wString[0];
     507          do
     508          {
     509            size = lstrlenA(aString) + 1;
     510            if (wString[0]) /* only in the second loop */
     511            {
     512              MultiByteToWideChar(CP_ACP, 0, aString, size, wString[0], size);
     513              wString[0] += size;
     514            }
     515            aString += size;
     516            retSize += size;
     517          } while ((size != 1) & more);
     518          retSize = ((retSize+0x7) & -8);
     519        }
     520return retSize;
     521}
    395522/*************************************************************************
    396523 * SHFileOperationA        [SHELL32.@]
     
    399526 *     exported by name
    400527 */
    401 DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
    402 {
    403   SHFILEOPSTRUCTA nlpFileOp = *(lpFileOp);
    404 
    405   LPCSTR pNextFrom = nlpFileOp.pFrom;
    406   LPCSTR pNextTo = nlpFileOp.pTo;
    407   LPCSTR pFrom = pNextFrom;
    408   LPCSTR pTo = NULL;
    409   HANDLE hFind = INVALID_HANDLE_VALUE;
    410   WIN32_FIND_DATAA wfd;
    411   LPSTR pTempFrom = NULL;
    412   LPSTR pTempTo = NULL;
    413   LPSTR pFromFile;
    414   LPSTR pToFile;
    415   long retCode = 0;
    416   DWORD ToAttr;
    417   DWORD ToPathAttr;
    418   FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
    419 
    420   BOOL b_Multi = (nlpFileOp.fFlags & FOF_MULTIDESTFILES);
    421 
    422   BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & 0xf));
    423   BOOL b_MultiFrom = FALSE;
    424   BOOL not_overwrite;
    425   BOOL ask_overwrite;
    426   BOOL b_SameRoot;
    427   BOOL b_SameTailName;
    428   BOOL b_ToInvalidTail;
    429   BOOL b_ToValid; /* for W98-Bug for FO_MOVE with source and taget in same rootdrive */
    430   BOOL b_Mask; /* wird als Schalter benutzt, vieleicht finde ich die richtige bitposition */
    431   BOOL b_ToTailSlash;
    432 
    433   LPCSTR cFO_Name [4] = { "FO_MOVE", "FO_COPY", "FO_DELETE", "FO_RENAME" };
    434   LPCSTR pToFuncTXT = "FO_????";
    435 
    436   long FuncSwitch = (nlpFileOp.wFunc & 0xf);
    437   long level= nlpFileOp.wFunc>>4;
     528DWORD WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
     529{
     530        SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp);
     531        DWORD retCode = 0, size = 0;
     532        LPWSTR wString = NULL; /* we change this in SHNameTranlate */
     533        LPWSTR ForFree = NULL;
     534
     535        TRACE("SHFileOperationA");
     536        if (FO_DELETE == (nFileOp.wFunc & 0xf))
     537          nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */
     538        if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS))
     539          nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */
     540        do
     541        {
     542          if (size)
     543          {
     544            ForFree = wString =  HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
     545            if (!wString)
     546            {
     547              retCode = ERROR_OUTOFMEMORY;
     548              goto shfileop_error;
     549            }
     550          }
     551          size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */
     552          size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */
     553          size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */
     554           /* first loop only for calculate size, no translation, we hav a NULL-pointer */
     555        } while (!ForFree); /* second loop calculate size, also translation. We have a valid pointer */
     556
     557        retCode = SHFileOperationW(&nFileOp);
     558
     559shfileop_error:
     560        if (ForFree)
     561          HeapFree(GetProcessHeap(), 0, ForFree);
     562
     563        if (retCode)
     564        {
     565          nFileOp.fAnyOperationsAborted = TRUE;
     566          SetLastError(retCode);
     567        }
     568        lpFileOp->hNameMappings = nFileOp.hNameMappings;
     569        lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
     570        return retCode;
     571}
     572
     573/*************************************************************************
     574 * SHFileOperationW        [SHELL32.@]
     575 *
     576 * NOTES
     577 *     exported by name
     578 */
     579DWORD WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
     580{
     581        SHFILEOPSTRUCTW nFileOp = *(lpFileOp);
     582
     583        LPCWSTR pNextFrom = nFileOp.pFrom;
     584        LPCWSTR pNextTo = nFileOp.pTo;
     585        LPCWSTR pFrom = pNextFrom;
     586        LPCWSTR pTo = NULL;
     587        HANDLE hFind = INVALID_HANDLE_VALUE;
     588        WIN32_FIND_DATAW wfd;
     589        LPWSTR pTempFrom = NULL;
     590        LPWSTR pTempTo = NULL;
     591        LPWSTR pFromFile;
     592        LPWSTR pToFile;
     593        LPWSTR lpFileName;
     594        long retCode = 0;
     595        DWORD ToAttr;
     596        DWORD ToPathAttr;
     597        FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
     598
     599        BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES);
     600
     601        BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & 0xf));
     602        BOOL b_MultiFrom = FALSE;
     603        BOOL not_overwrite;
     604        BOOL ask_overwrite;
     605        BOOL b_SameRoot;
     606        BOOL b_SameTailName;
     607        BOOL b_ToInvalidTail;
     608        BOOL b_ToValid; /* for W98-Bug for FO_MOVE with source and taget in same rootdrive */
     609        BOOL b_Mask; /* wird als Schalter benutzt, vieleicht finde ich die richtige bitposition */
     610        BOOL b_ToTailSlash;
     611        LPCSTR cFO_Name [] = {"FO_????","FO_MOVE","FO_COPY","FO_DELETE","FO_RENAME"};
     612
     613        long FuncSwitch = (nFileOp.wFunc & 0xf);
     614        long level= nFileOp.wFunc>>4;
    438615
    439616/*  default no error */
    440   nlpFileOp.fAnyOperationsAborted=FALSE;
    441 
    442   if (!(FuncSwitch) || (FO_RENAME < FuncSwitch))
    443     goto shfileop_normal;
    444 
    445   pToFuncTXT = cFO_Name [FuncSwitch-1];
    446   if (level == 0)
    447     TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n",pToFuncTXT, nlpFileOp.fFlags,
    448                 nlpFileOp.fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
    449                 nlpFileOp.fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
    450                 nlpFileOp.fFlags & FOF_SILENT ? "FOF_SILENT " : "",
    451                 nlpFileOp.fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
    452                 nlpFileOp.fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
    453                 nlpFileOp.fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
    454                 nlpFileOp.fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
    455                 nlpFileOp.fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
    456                 nlpFileOp.fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
    457                 nlpFileOp.fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
    458                 nlpFileOp.fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
    459                 nlpFileOp.fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
    460   ;
    461   {
    462                 /* establish when pTo is interpreted as the name of the destination file
    463                  * or the directory where the Fromfile should be copied to.
    464                  * This depends on:
    465                  * (1) pTo points to the name of an existing directory;
    466                  * (2) the flag FOF_MULTIDESTFILES is present;
    467                  * (3) whether pFrom point to multiple filenames.
    468                  *
    469                  * Some experiments:
    470                  *
    471                  * destisdir               1 1 1 1 0 0 0 0
    472                  * FOF_MULTIDESTFILES      1 1 0 0 1 1 0 0
    473                  * multiple from filenames 1 0 1 0 1 0 1 0
    474                  *                         ---------------
    475                  * copy files to dir       1 0 1 1 0 0 1 0
    476                  * create dir              0 0 0 0 0 0 1 0
    477                  */
     617        nFileOp.fAnyOperationsAborted = FALSE;
     618
     619        if ((FuncSwitch < FO_MOVE) || (FuncSwitch > FO_RENAME))
     620          goto shfileop_normal; /* no valid FunctionCode */
     621
     622        cFO_Name[0] = cFO_Name [FuncSwitch];
     623        if (level == 0)
     624          TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n",cFO_Name[0], nFileOp.fFlags,
     625                      nFileOp.fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
     626                      nFileOp.fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
     627                      nFileOp.fFlags & FOF_SILENT ? "FOF_SILENT " : "",
     628                      nFileOp.fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
     629                      nFileOp.fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
     630                      nFileOp.fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
     631                      nFileOp.fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
     632                      nFileOp.fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
     633                      nFileOp.fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
     634                      nFileOp.fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
     635                      nFileOp.fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
     636                      nFileOp.fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
     637        ;
     638        {
     639                      /* establish when pTo is interpreted as the name of the destination file
     640                       * or the directory where the Fromfile should be copied to.
     641                       * This depends on:
     642                       * (1) pTo points to the name of an existing directory;
     643                       * (2) the flag FOF_MULTIDESTFILES is present;
     644                       * (3) whether pFrom point to multiple filenames.
     645                       *
     646                       * Some experiments:
     647                       *
     648                       * destisdir               1 1 1 1 0 0 0 0
     649                       * FOF_MULTIDESTFILES      1 1 0 0 1 1 0 0
     650                       * multiple from filenames 1 0 1 0 1 0 1 0
     651                       *                         ---------------
     652                       * copy files to dir       1 0 1 1 0 0 1 0
     653                       * create dir              0 0 0 0 0 0 1 0
     654                       */
    478655/*
    479656 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY          are    implemented
     
    483660 * if any other flag set, an error occurs
    484661 */
    485     TRACE(__FUNCTION__" %s level=%d nlpFileOp.fFlags=0x%x\n", pToFuncTXT, level, lpFileOp->fFlags);
    486 
    487 /*    OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY));
     662          TRACE(" %s level=%d nFileOp.fFlags=0x%x\n", cFO_Name[0], level, lpFileOp->fFlags);
     663
     664/*    OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY)); */
    488665/*    OFl ^= (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR); */
    489     OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY));  /* implemented */
    490     OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR);                /* ignored, if one */
    491     OFl &= (~FOF_SIMPLEPROGRESS);                      /* ignored, only wit FOF_SILEN */
    492     if (OFl)
    493     {
    494       if (OFl & ( ~ (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR)))
    495       {
    496         TRACE("%s level=%d lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", pToFuncTXT, level, OFl);
    497         retCode = 0x403; /* 1027, we need a extension of shlfileop */
    498         goto shfileop_error;
    499       }
    500       else
    501       {
    502         TRACE("%s level=%d lpFileOp->fFlags=0x%x not full implemented ,stub\n", pToFuncTXT, level, OFl);
    503       } /* endif */
    504     } /* endif */
    505 
    506     if ((pNextFrom) && (!(b_MultiTo) || (pNextTo)))
    507     {
    508       nlpFileOp.pFrom = pTempFrom = HeapAlloc(GetProcessHeap(), 0, (1+2*(b_MultiTo)) * MAX_PATH+6);
    509       if (b_MultiTo) pTempTo = &pTempFrom[MAX_PATH+4];
    510       nlpFileOp.pTo   = pTempTo;
    511       ask_overwrite = (!(nlpFileOp.fFlags & FOF_NOCONFIRMATION) && !(nlpFileOp.fFlags & FOF_RENAMEONCOLLISION));
    512       not_overwrite = (!(nlpFileOp.fFlags & FOF_NOCONFIRMATION) ||  (nlpFileOp.fFlags & FOF_RENAMEONCOLLISION));
    513     }
    514     else
    515     {
    516       retCode = 0x402;      /* 1026 */
    517       goto shfileop_error;
    518     }
     666          OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY));  /* implemented */
     667          OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR);          /* ignored, if one */
     668          OFl &= (~FOF_SIMPLEPROGRESS);                      /* ignored, only with FOF_SILENT */
     669          if (OFl)
     670          {
     671            if (OFl & ( ~ (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR)))
     672            {
     673              TRACE("%s level=%d lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", cFO_Name[0], level, OFl);
     674              retCode = 0x403; /* 1027, we need a extension of shlfileop */
     675              goto shfileop_error;
     676            }
     677            else
     678            {
     679              TRACE("%s level=%d lpFileOp->fFlags=0x%x not full implemented ,stub\n", cFO_Name[0], level, OFl);
     680            } /* endif */
     681          } /* endif */
     682
     683          if ((pNextFrom) && (!(b_MultiTo) || (pNextTo)))
     684          {
     685            nFileOp.pFrom = pTempFrom = HeapAlloc(GetProcessHeap(), 0, ((1 + 2 * (b_MultiTo)) * MAX_PATH + 6) * sizeof(WCHAR));
     686            if (b_MultiTo)
     687              pTempTo = &pTempFrom[MAX_PATH + 4];
     688            nFileOp.pTo = pTempTo;
     689            ask_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) && !(nFileOp.fFlags & FOF_RENAMEONCOLLISION));
     690            not_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) ||  (nFileOp.fFlags & FOF_RENAMEONCOLLISION));
     691          }
     692          else
     693          {
     694            retCode = 0x402;      /* 1026 */
     695            goto shfileop_error;
     696          }
    519697/* need break at error before change sourcepointer */
    520     while(!nlpFileOp.fAnyOperationsAborted && (pNextFrom[0]))
    521     {
    522       nlpFileOp.wFunc =  ((level+1)<<4) + FuncSwitch;
    523       nlpFileOp.fFlags = lpFileOp->fFlags;
    524 
    525       if (b_MultiTo)
    526       {
    527         pTo = pNextTo;
    528         pNextTo = &pNextTo[lstrlenA(pTo)+1];
    529         b_MultiTo = (b_Multi && pNextTo[0]);
    530       }
    531 
    532       pFrom = pNextFrom;
    533       pNextFrom = &pNextFrom[lstrlenA(pNextFrom)+1];
    534       if (!b_MultiFrom && !b_MultiTo)
    535         b_MultiFrom = (pNextFrom[0]);
    536 
    537       pFromFile = SHFileStrCpyCatA(pTempFrom, pFrom, NULL);
    538 
    539       if (pTo)
    540       {
    541         pToFile = SHFileStrCpyCatA(pTempTo, pTo, NULL);
    542       }
    543       if (!(pFromFile) || !(pFromFile[1]) || ((pTo) && !(pToFile)))
    544       {
    545          retCode = 0x402;      /* 1026 */
    546          goto shfileop_error;
    547       }
    548       if (pTo)
    549       {
    550         b_ToTailSlash = (!pToFile[1]);
    551         if (b_ToTailSlash)
    552         {
    553           pToFile[0] = '\0';
    554           if (strchr(pTempTo,'\\'))
    555           {
    556             pToFile = SHFileStrCpyCatA(pTempTo, NULL, NULL);
    557           }
    558         }
    559         b_ToInvalidTail = (NULL != StrPBrkA(&pToFile[1],"*?"));
    560       }
    561 
    562       b_Mask = (NULL != StrPBrkA(&pFromFile[1],"*?"));
    563       if (FO_RENAME == FuncSwitch)
    564       {
    565 /* temporr only for FO_RENAME */
    566 //        b_Mask = (NULL != strpbrk(pFrom,"*?"));
    567         if (b_MultiTo || b_MultiFrom || (b_Mask && !b_ToInvalidTail))
    568         {
    569 /* no work, only RC=0 */
    570 // /* ???? */    nlpFileOp.fAnyOperationsAborted=TRUE;
    571           goto shfileop_normal;
    572         }
    573       }
    574 
    575       hFind = FindFirstFileA(pFrom, &wfd);
    576       if (INVALID_HANDLE_VALUE == hFind)
    577       {
    578 /* root (without mask) is also not allowed as source, tested in W98 */
    579         retCode = 0x402;   /* 1026 */
    580         goto shfileop_error;
    581       } /* endif */
     698          while(!nFileOp.fAnyOperationsAborted && (pNextFrom[0]))
     699          {
     700            nFileOp.wFunc =  ((level + 1) << 4) + FuncSwitch;
     701            nFileOp.fFlags = lpFileOp->fFlags;
     702
     703            if (b_MultiTo)
     704            {
     705              pTo = pNextTo;
     706              pNextTo = &pNextTo[lstrlenW(pTo)+1];
     707              b_MultiTo = (b_Multi && pNextTo[0]);
     708            }
     709
     710            pFrom = pNextFrom;
     711            pNextFrom = &pNextFrom[lstrlenW(pNextFrom)+1];
     712            if (!b_MultiFrom && !b_MultiTo)
     713              b_MultiFrom = (pNextFrom[0]);
     714
     715            pFromFile = SHFileStrCpyCatW(pTempFrom, pFrom, NULL);
     716
     717            if (pTo)
     718            {
     719              pToFile = SHFileStrCpyCatW(pTempTo, pTo, NULL);
     720            }
     721            if (!(pFromFile) || !(pFromFile[1]) || ((pTo) && !(pToFile)))
     722            {
     723              retCode = 0x402;      /* 1026 */
     724              goto shfileop_error;
     725            }
     726            if (pTo)
     727            {
     728              b_ToTailSlash = (!pToFile[1]);
     729              if (b_ToTailSlash)
     730              {
     731                pToFile[0] = '\0';
     732                if (StrChrW(pTempTo,'\\'))
     733                {
     734                  pToFile = SHFileStrCpyCatW(pTempTo, NULL, NULL);
     735                }
     736              }
     737              b_ToInvalidTail = (NULL != StrPBrkW(&pToFile[1], wWildcardChars));
     738            }
     739
     740            /* for all */
     741            b_Mask = (NULL != StrPBrkW(&pFromFile[1], wWildcardChars));
     742            if (FO_RENAME == FuncSwitch)
     743            {
     744              /* temporary only for FO_RENAME */
     745/* ???  b_Mask = (NULL != strrbrk(pFrom,"*?")); */
     746              if (b_MultiTo || b_MultiFrom || (b_Mask && !b_ToInvalidTail))
     747              {
     748                /* no work, only RC=0 */
     749/* ???    nFileOp.fAnyOperationsAborted = TRUE; */
     750                goto shfileop_normal;
     751              }
     752            }
     753
     754            hFind = FindFirstFileW(pFrom, &wfd);
     755            if (INVALID_HANDLE_VALUE == hFind)
     756            {
     757              /* root (without mask) is also not allowed as source, tested in W98 */
     758              retCode = 0x402;   /* 1026 */
     759              goto shfileop_error;
     760            } /* endif */
    582761
    583762/* for all */
    584 #define HIGH_ADR (LPSTR)0xffffffff
    585 //      b_Mask = (!SHFileStrICmpA(&pFromFile[1], &wfd.cFileName[0], HIGH_ADR, HIGH_ADR));
    586 
    587       if (!pTo) /* FO_DELETE */
    588       {
    589         do
    590         {
    591           if (wfd.cFileName[0] == '.')
    592           {
    593           if (wfd.cFileName[1] == '\0')
    594             continue;
    595           if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0')
    596             continue;
    597           }
    598           SHFileStrCpyCatA(&pFromFile[1], wfd.cFileName, NULL);
    599           if (IsAttribFile(wfd.dwFileAttributes))
    600           {
    601             nlpFileOp.fAnyOperationsAborted = (!Win32DeleteFileA(pTempFrom));
    602             retCode = 0x78; /* value unknown */
    603           }
    604           else
    605           {
    606             nlpFileOp.fAnyOperationsAborted = (!SHELL_DeleteDirectoryA(pTempFrom,(!(nlpFileOp.fFlags & FOF_NOCONFIRMATION))));
    607             retCode = 0x79; /* value unknown */
    608           }
    609         } while(!nlpFileOp.fAnyOperationsAborted && FindNextFileA(hFind, &wfd));
    610         FindClose(hFind);
    611         hFind = INVALID_HANDLE_VALUE;
    612         if (nlpFileOp.fAnyOperationsAborted)
    613         {
    614           goto shfileop_error;
    615         }
    616         continue;
    617       } /* FO_DELETE ends, pTo must be every valid from here */
    618 
    619       b_SameRoot = (toupper(pTempFrom[0]) == toupper(pTempTo[0]));
    620       b_SameTailName = SHFileStrICmpA(pToFile, pFromFile, NULL, NULL);
    621 
    622       ToPathAttr = ToAttr = GetFileAttributesA(pTempTo);
    623       if (!b_Mask && (ToAttr -1))
    624       {
    625         if (pToFile)
    626         {
    627           pToFile[0] = '\0';
    628           ToPathAttr = GetFileAttributesA(pTempTo);
    629           pToFile[0] = '\\';
    630         }
    631       }
    632 
    633       if (FO_RENAME == FuncSwitch)
    634       {
    635         if (!b_SameRoot || b_Mask /* FO_RENAME works not with Mask */
    636          || !SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, NULL)
    637          || (SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, HIGH_ADR) && !b_ToTailSlash))
    638         {
    639           retCode = 0x73;
    640           goto shfileop_error;
    641         }
    642         if (b_ToInvalidTail)
    643         {
    644           retCode=0x2;
    645           goto shfileop_error;
    646         }
    647         if (-1 == ToPathAttr)
    648         {
    649           retCode = 0x75;
    650           goto shfileop_error;
    651         }
    652         if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(ToAttr))
    653         {
    654           retCode = (b_ToTailSlash) ? 0xb7 : 0x7b;
    655           goto shfileop_error;
    656         } /* endif */
    657         if (!MoveFileA(pTempFrom, pTempTo))
    658         {
    659 /* we need still the value for the returncode, we use the mostly assumed */
    660           retCode = 0xb7;
    661           goto shfileop_error;
    662         }
    663         goto shfileop_normal;
    664       }
    665 
    666       /* W98 Bug with FO_MOVE(/RENAME ?) different to FO_COPY, better the same as FO_COPY */
    667 
    668       b_ToValid = ((b_SameTailName &&  b_SameRoot && (FO_COPY == FuncSwitch)) ||
    669                 (b_SameTailName && !b_SameRoot) || (b_ToInvalidTail));
    670 
    671 /* handle mask in source */
    672       if (b_Mask)
    673       {
    674         if (!IsAttribDir(ToAttr))
    675         {
    676           retCode = (b_ToInvalidTail &&/* b_SameTailName &&*/ (FO_MOVE == FuncSwitch)) \
    677             ? 0x2 : 0x75;
    678           goto shfileop_error;
    679         }
    680         pToFile = SHFileStrCpyCatA(pTempTo,NULL, "\\");
    681         nlpFileOp.fFlags = (nlpFileOp.fFlags | FOF_MULTIDESTFILES);
    682         do
    683         {
    684           if (wfd.cFileName[0] == '.')
    685           {
    686             if (wfd.cFileName[1] == '\0')
    687               continue;
    688             if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0') continue;
    689           }
    690           if (IsAttribDir(wfd.dwFileAttributes) && (nlpFileOp.fFlags & FOF_FILESONLY))
    691           {
    692             continue; /* next name in pTempFrom(dir) */
    693           }
    694           SHFileStrCpyCatA(&pToFile[1], wfd.cFileName, NULL);
    695           SHFileStrCpyCatA(&pFromFile[1], wfd.cFileName, NULL);
    696           retCode = SHFileOperationA (&nlpFileOp);
    697         } while(!nlpFileOp.fAnyOperationsAborted && FindNextFileA(hFind, &wfd));
    698       }
    699       FindClose(hFind);
    700       hFind = INVALID_HANDLE_VALUE;
    701       /* only FO_COPY/FO_MOVE without mask, FO_DELETE and FO_RENAME are solved */
    702       if (b_Mask)
    703         continue;
    704 
    705       if (IsAttribDir(wfd.dwFileAttributes) && (ToAttr -1))
    706       {
    707         if (pToFile)
    708         {
    709           pToFile[0] = '\0';
    710           ToPathAttr = GetFileAttributesA(pTempTo);
    711           if ((ToPathAttr == -1) && b_ToValid)
    712           {
    713 /* create dir must be here, sample target D:\y\ *.* create with RC=10003 */
    714             if(SHCreateDirectoryExA(NULL,pTempTo, NULL))
    715             {
    716               retCode = 0x73;/* value unknown */
    717               goto shfileop_error;
    718             }
    719             ToPathAttr = GetFileAttributesA(pTempTo);
    720           }
    721           pToFile[0] = '\\';
    722           if (b_ToInvalidTail)
    723           {
    724             retCode=0x10003;
    725             goto shfileop_error;
    726           }
    727         }
    728       }
    729 
    730 /* tailling BackSlash is ever removed and pToFile points to BackSlash before */
    731       if (!b_MultiTo && (b_MultiFrom || (!(b_Multi) && IsAttribDir(ToAttr))))
    732       {
    733         if ((FO_MOVE == FuncSwitch) && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
    734         {
    735           if (b_Multi)
    736           {
    737             retCode = 0x73; /* !b_Multi = 0x8 ?? */
    738             goto shfileop_error;
    739           }
    740         }
    741         pToFile = SHFileStrCpyCatA(pTempTo, NULL, wfd.cFileName);
    742         ToAttr = GetFileAttributesA(pTempTo);
    743       }
    744 
    745       if (IsAttribDir(ToAttr))
    746       {
    747         if (IsAttribFile(wfd.dwFileAttributes))
    748         {
    749           retCode = (FO_COPY == FuncSwitch) ? 0x75 : 0xb7;
    750           goto shfileop_error;
    751         }
    752       }
    753       else
    754       {
    755         pToFile[0] = '\0';
    756         ToPathAttr = GetFileAttributesA(pTempTo);
    757         pToFile[0] = '\\';
    758         if (IsAttribFile(ToPathAttr))
    759         {
    760 /* error, is this tested ? */
    761           retCode = 0x777402;
    762           goto shfileop_error;
    763         } /* endif */
    764       }
    765 
    766 /* singlesource + no mask */
    767       if (-1 == (ToAttr & ToPathAttr))
    768       {
    769 /* Target-dir does not exist, and can not created */
    770         retCode=0x75;
    771         goto shfileop_error;
    772       }
    773 
    774       switch(FuncSwitch)
    775       {
    776       case FO_MOVE:
    777         pToFile = NULL;
    778         if ((ToAttr == -1) && SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, NULL))
    779         {
    780           nlpFileOp.wFunc =  ((level+1)<<4) + FO_RENAME;
    781         }
    782         else
    783         {
    784           if (b_SameRoot && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
    785           {
    786             pToFile = SHFileStrCpyCatA(pTempFrom, NULL, "*.*");
    787             retCode = SHFileOperationA(&nlpFileOp);
    788           }
    789           else
    790           {
    791             nlpFileOp.wFunc =  ((level+1)<<4) + FO_COPY;
    792           } /* endif */
    793         }
    794         retCode = SHFileOperationA(&nlpFileOp);
    795         if (pToFile)
    796           ((WORD*)pToFile)[0] = '\0';
    797         if (!nlpFileOp.fAnyOperationsAborted && (FO_RENAME != (nlpFileOp.wFunc & 0xf)))
    798         {
    799           nlpFileOp.wFunc =  ((level+1)<<4) + FO_DELETE;
    800           retCode = SHFileOperationA(&nlpFileOp);
    801         } /* endif */
    802         continue;
    803       case FO_COPY:
    804         if (SHFileStrICmpA(pTempFrom, pTempTo, NULL, NULL))
    805         { /* target is the same as source ? */
    806 /* we need still the value for the returncode, we assume 0x71 */
    807           retCode = 0x71;
    808           goto shfileop_error;
    809         } /* endif */
    810         if (IsAttribDir((ToAttr & wfd.dwFileAttributes)))
    811         {
    812           if (IsAttribDir(ToAttr) || !SHCreateDirectoryExA(NULL,pTempTo, NULL))
    813           {
    814 /*  ??? nlpFileOp.fFlags = (nlpFileOp.fFlags | FOF_MULTIDESTFILES); */
    815             SHFileStrCpyCatA(pTempFrom, NULL, "*.*");
    816             retCode = SHFileOperationA(&nlpFileOp);
    817           }
    818           else
    819           {
    820             retCode = 0x750;/* value unknown */
    821             goto shfileop_error;
    822           }
    823         }
    824         else
    825         {
    826           if (!(ask_overwrite && SHELL_ConfirmDialog (ASK_OVERWRITE_FILE, pTempTo))
    827           && (not_overwrite))
    828           {
    829             /* we need still the value for the returncode, we use the mostly assumed */
    830             retCode = 0x73;
    831             goto shfileop_error;
    832           }
    833           if (!(CopyFileA(pTempFrom, pTempTo, FALSE)))
    834           {
    835             retCode = 0x77; /* value unknown */
    836             goto shfileop_error;
    837           }
    838         }
    839       } /* end-switch */
    840     } /* end-while */
    841   }
     763#define HIGH_ADR (LPWSTR)0xffffffff
     764
     765/* ??? b_Mask = (!SHFileStrICmpA(&pFromFile[1], &wfd.cFileName[0], HIGH_ADR, HIGH_ADR)); */
     766
     767            if (!pTo) /* FO_DELETE */
     768            {
     769              do
     770              {
     771                 lpFileName = wfd.cAlternateFileName;
     772                 if (!lpFileName[0])
     773                   lpFileName = wfd.cFileName;
     774                if (IsDotDir(lpFileName))
     775                  continue;
     776                SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
     777                /* TODO: Check the SHELL_DeleteFileOrDirectoryW() function in shell32.dll */
     778                if (IsAttribFile(wfd.dwFileAttributes))
     779                {
     780                  nFileOp.fAnyOperationsAborted = (!SHNotifyDeleteFileW(pTempFrom));
     781                  retCode = 0x78; /* value unknown */
     782                }
     783                else
     784                {
     785                  nFileOp.fAnyOperationsAborted = (!SHELL_DeleteDirectoryW(pTempFrom, (!(nFileOp.fFlags & FOF_NOCONFIRMATION))));
     786                  retCode = 0x79; /* value unknown */
     787                }
     788              } while (!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd));
     789              FindClose(hFind);
     790              hFind = INVALID_HANDLE_VALUE;
     791              if (nFileOp.fAnyOperationsAborted)
     792              {
     793                goto shfileop_error;
     794              }
     795              continue;
     796            } /* FO_DELETE ends, pTo must be always valid from here */
     797
     798            b_SameRoot = (towupper(pTempFrom[0]) == towupper(pTempTo[0]));
     799            b_SameTailName = SHFileStrICmpW(pToFile, pFromFile, NULL, NULL);
     800
     801            ToPathAttr = ToAttr = GetFileAttributesW(pTempTo);
     802            if (!b_Mask && (ToAttr -1) && (pToFile))
     803            {
     804              pToFile[0] = '\0';
     805              ToPathAttr = GetFileAttributesW(pTempTo);
     806              pToFile[0] = '\\';
     807            }
     808
     809            if (FO_RENAME == FuncSwitch)
     810            {
     811              if (!b_SameRoot || b_Mask /* FO_RENAME works not with Mask */
     812               || !SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL)
     813               || (SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, HIGH_ADR) && !b_ToTailSlash))
     814              {
     815                retCode = 0x73;
     816                goto shfileop_error;
     817              }
     818              if (b_ToInvalidTail)
     819              {
     820                retCode=0x2;
     821                goto shfileop_error;
     822              }
     823              if (-1 == ToPathAttr)
     824              {
     825                retCode = 0x75;
     826                goto shfileop_error;
     827              }
     828              if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(ToAttr))
     829              {
     830                retCode = (b_ToTailSlash) ? 0xb7 : 0x7b;
     831                goto shfileop_error;
     832              } /* endif */
     833              /* TODO: use SHNotifyMoveFile() instead ?? */
     834              if (!MoveFileW(pTempFrom, pTempTo))
     835              {
     836                /* we need still the value for the returncode, we use the mostly assumed */
     837                retCode = 0xb7;
     838                goto shfileop_error;
     839              }
     840              goto shfileop_normal;
     841            }
     842
     843            /* W98 Bug with FO_MOVE different to FO_COPY, better the same as FO_COPY */
     844            b_ToValid = ((b_SameTailName &&  b_SameRoot && (FO_COPY == FuncSwitch)) ||
     845                      (b_SameTailName && !b_SameRoot) || (b_ToInvalidTail));
     846
     847            /* handle mask in source */
     848            if (b_Mask)
     849            {
     850              if (!IsAttribDir(ToAttr))
     851              {
     852                retCode = (b_ToInvalidTail &&/* b_SameTailName &&*/ (FO_MOVE == FuncSwitch)) \
     853                  ? 0x2 : 0x75;
     854                goto shfileop_error;
     855              }
     856              pToFile = SHFileStrCpyCatW(pTempTo, NULL, wBackslash);
     857              nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES);
     858              do
     859              {
     860                 lpFileName = wfd.cAlternateFileName;
     861                 if (!lpFileName[0])
     862                   lpFileName = wfd.cFileName;
     863                if (IsDotDir(lpFileName) ||
     864                    (IsAttribDir(wfd.dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
     865                  continue; /* next name in pTempFrom(dir) */
     866                SHFileStrCpyCatW(&pToFile[1], lpFileName, NULL);
     867                SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
     868                retCode = SHFileOperationW (&nFileOp);
     869              } while(!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd));
     870            }
     871            FindClose(hFind);
     872            hFind = INVALID_HANDLE_VALUE;
     873            /* FO_COPY/FO_MOVE with mask, FO_DELETE and FO_RENAME are solved */
     874            if (b_Mask)
     875              continue;
     876
     877            /* only FO_COPY/FO_MOVE without mask, all others are (must be) solved */
     878            if (IsAttribDir(wfd.dwFileAttributes) && (ToAttr -1))
     879            {
     880              if (pToFile)
     881              {
     882                pToFile[0] = '\0';
     883                ToPathAttr = GetFileAttributesW(pTempTo);
     884                if ((ToPathAttr == -1) && b_ToValid)
     885                {
     886                  /* create dir must be here, sample target D:\y\ *.* create with RC=10003 */
     887                  if (SHCreateDirectoryExW(NULL, pTempTo, NULL))
     888                  {
     889                    retCode = 0x73;/* value unknown */
     890                    goto shfileop_error;
     891                  }
     892                  ToPathAttr = GetFileAttributesW(pTempTo);
     893                }
     894                pToFile[0] = '\\';
     895                if (b_ToInvalidTail)
     896                {
     897                  retCode = 0x10003;
     898                  goto shfileop_error;
     899                }
     900              }
     901            }
     902
     903            /* trailing BackSlash is ever removed and pToFile points to BackSlash before */
     904            if (!b_MultiTo && (b_MultiFrom || (!(b_Multi) && IsAttribDir(ToAttr))))
     905            {
     906              if ((FO_MOVE == FuncSwitch) && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
     907              {
     908                if (b_Multi)
     909                {
     910                  retCode = 0x73; /* !b_Multi = 0x8 ?? */
     911                  goto shfileop_error;
     912                }
     913              }
     914              pToFile = SHFileStrCpyCatW(pTempTo, NULL, wfd.cFileName);
     915              ToAttr = GetFileAttributesW(pTempTo);
     916            }
     917
     918            if (IsAttribDir(ToAttr))
     919            {
     920              if (IsAttribFile(wfd.dwFileAttributes))
     921              {
     922                retCode = (FO_COPY == FuncSwitch) ? 0x75 : 0xb7;
     923                goto shfileop_error;
     924              }
     925            }
     926            else
     927            {
     928              pToFile[0] = '\0';
     929              ToPathAttr = GetFileAttributesW(pTempTo);
     930              pToFile[0] = '\\';
     931              if (IsAttribFile(ToPathAttr))
     932              {
     933                /* error, is this tested ? */
     934                retCode = 0x777402;
     935                goto shfileop_error;
     936              } /* endif */
     937            }
     938
     939            /* singlesource + no mask */
     940            if (-1 == (ToAttr & ToPathAttr))
     941            {
     942              /* Target-dir does not exist, and cannot be created */
     943              retCode=0x75;
     944              goto shfileop_error;
     945            }
     946
     947            switch(FuncSwitch)
     948            {
     949            case FO_MOVE:
     950              pToFile = NULL;
     951              if ((ToAttr == -1) && SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL))
     952              {
     953                nFileOp.wFunc =  ((level+1)<<4) + FO_RENAME;
     954              }
     955              else
     956              {
     957                if (b_SameRoot && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
     958                {
     959                  /* we need pToFile for FO_DELETE after FO_MOVE contence */
     960                  pToFile = SHFileStrCpyCatW(pTempFrom, NULL, wWildcardFile);
     961                }
     962                else
     963                {
     964                  nFileOp.wFunc =  ((level+1)<<4) + FO_COPY;
     965                }
     966              }
     967              retCode = SHFileOperationW(&nFileOp);
     968              if (pToFile)
     969                ((DWORD*)pToFile)[0] = '\0';
     970              if (!nFileOp.fAnyOperationsAborted && (FO_RENAME != (nFileOp.wFunc & 0xf)))
     971              {
     972                nFileOp.wFunc =  ((level+1)<<4) + FO_DELETE;
     973                retCode = SHFileOperationW(&nFileOp);
     974              }
     975              continue;
     976            case FO_COPY:
     977              if (SHFileStrICmpW(pTempFrom, pTempTo, NULL, NULL))
     978              { /* target is the same as source ? */
     979                /* we still need the value for the returncode, we assume 0x71 */
     980                retCode = 0x71;
     981                goto shfileop_error;
     982              } /* endif */
     983              if (IsAttribDir((ToAttr & wfd.dwFileAttributes)))
     984              {
     985                if (IsAttribDir(ToAttr) || !SHCreateDirectoryExW(NULL,pTempTo, NULL))
     986                {
     987/* ???      nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES); */
     988                  SHFileStrCpyCatW(pTempFrom, NULL, wWildcardFile);
     989                  retCode = SHFileOperationW(&nFileOp);
     990                }
     991                else
     992                {
     993                  retCode = 0x750;/* value unknown */
     994                  goto shfileop_error;
     995                }
     996              }
     997              else
     998              {
     999                if (!(ask_overwrite && SHELL_ConfirmDialogW(ASK_OVERWRITE_FILE, pTempTo))
     1000                && (not_overwrite))
     1001                {
     1002                  /* we still need the value for the returncode, we use the mostly assumed */
     1003                  retCode = 0x73;
     1004                  goto shfileop_error;
     1005                }
     1006                /* TODO: use SHNotifyCopyFile() */
     1007                if (!(CopyFileW(pTempFrom, pTempTo, FALSE)))
     1008                {
     1009                  retCode = 0x77; /* value unknown */
     1010                  goto shfileop_error;
     1011                }
     1012              }
     1013            } /* end-switch */
     1014          } /* end-while */
     1015        }
    8421016shfileop_normal:
    843   if (!(nlpFileOp.fAnyOperationsAborted))
    844     retCode = 0;
     1017        if (!(nFileOp.fAnyOperationsAborted))
     1018          retCode = 0;
    8451019shfileop_error:
    846   if (retCode)
    847     nlpFileOp.fAnyOperationsAborted = TRUE;
    848   if (hFind != INVALID_HANDLE_VALUE)
    849     FindClose(hFind);
    850   hFind = INVALID_HANDLE_VALUE;
    851   if (pTempFrom)
    852     HeapFree(GetProcessHeap(), 0, pTempFrom);
    853 
    854   TRACE("%s level=%d AnyOpsAborted=%s ret=0x%x, with %s%s%s\n",
    855         pToFuncTXT, level, nlpFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
    856         retCode, debugstr_a(pFrom), pTo ? " -> ":"", debugstr_a(pTo));
    857 
    858   lpFileOp->fAnyOperationsAborted = nlpFileOp.fAnyOperationsAborted;
    859   return retCode;
    860 }
    861 
    862 /*************************************************************************
    863  * SHFileOperationW        [SHELL32.@]
    864  *
    865  * NOTES
    866  *     exported by name
    867  */
    868 DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
    869 {
    870   FIXME("(%p):stub.\n", lpFileOp);
    871   return 1;
     1020        if (hFind != INVALID_HANDLE_VALUE)
     1021          FindClose(hFind);
     1022        hFind = INVALID_HANDLE_VALUE;
     1023        if (pTempFrom)
     1024          HeapFree(GetProcessHeap(), 0, pTempFrom);
     1025        if (retCode)
     1026        {
     1027          nFileOp.fAnyOperationsAborted = TRUE;
     1028          SetLastError(retCode);
     1029        }
     1030        TRACE("%s level=%d AnyOpsAborted=%s ret=0x%x, with %s%s%s\n",
     1031              cFO_Name[0], level, nFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
     1032              retCode, debugstr_w(pFrom), pTo ? " -> ":"", debugstr_w(pTo));
     1033
     1034        lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
     1035        return retCode;
    8721036}
    8731037
     
    8781042DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
    8791043{
    880   if (SHELL_OsIsUnicode())
    881     return SHFileOperationW(lpFileOp);
    882   return SHFileOperationA(lpFileOp);
     1044        if (SHELL_OsIsUnicode())
     1045          return SHFileOperationW(lpFileOp);
     1046        return SHFileOperationA(lpFileOp);
    8831047}
    8841048
     
    8891053HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
    8901054{  FIXME("%p %p stub\n",u,v);
    891   return 0;
     1055        return 0;
    8921056}
    8931057
     
    9061070BOOL WINAPI IsNetDrive(DWORD drive)
    9071071{
    908   char root[4];
    909   strcpy(root, "A:\\");
    910   root[0] += (char)drive;
    911   return (GetDriveTypeA(root) == DRIVE_REMOTE);
    912 }
    913 
    914 
     1072        char root[4];
     1073        strcpy(root, "A:\\");
     1074        root[0] += (char)drive;
     1075        return (GetDriveTypeA(root) == DRIVE_REMOTE);
     1076}
     1077
     1078
     1079
     1080
Note: See TracChangeset for help on using the changeset viewer.