Changeset 10162 for trunk/src


Ignore:
Timestamp:
Jul 11, 2003, 5:38:31 PM (22 years ago)
Author:
sandervl
Message:

DT: Shell folder updates

Location:
trunk/src/shell32
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/shell32/shell32_main.h

    r9885 r10162  
    179179#define ASK_DELETE_FOLDER        2
    180180#define ASK_DELETE_MULTIPLE_ITEM 3
    181 #ifdef __WIN32OS2__
    182 #define ASK_CREATE FOLDER        4
     181#define ASK_CREATE_FOLDER        4
    183182#define ASK_OVERWRITE_FILE       5
    184 #endif
    185183
    186184BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI);
  • trunk/src/shell32/shlfileop.c

    r9959 r10162  
    2020 * License along with this library; if not, write to the Free Software
    2121 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     22 *
     23 * !!! shlfileop.c is shared source between wine and odin, do not remove
     24 * #ifdef __win32os2__ .. lines
    2225 */
    2326
     
    3235#include "shlobj.h"
    3336#include "shresdef.h"
     37#define NO_SHLWAPI_STREAM
     38#include "shlwapi.h"
    3439#include "shell32_main.h"
    3540#include "undocshell.h"
    36 #include "shlwapi.h"
     41#include "wine/unicode.h"
    3742#include "wine/debug.h"
    3843
    39 #define IsAttribFile(x) (!(x == -1) && !(x & FILE_ATTRIBUTE_DIRECTORY))
     44WINE_DEFAULT_DEBUG_CHANNEL(shell);
     45
     46#define W98_FO_FUNCTION /* makes shlfileop W98-like */
     47#undef W98_FO_FUNCTION /* makes shlfileop W2K-like */
     48#define W98_FO_FUNCTION /* makes shlfileop W98-like */
     49
     50#define IsAttribFile(x) (!(x & FILE_ATTRIBUTE_DIRECTORY))
    4051#define IsAttribDir(x)  (!(x == -1) && (x & FILE_ATTRIBUTE_DIRECTORY))
    4152
    4253#define IsDotDir(x)     ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
    4354
    44 WINE_DEFAULT_DEBUG_CHANNEL(shell);
     55#define FO_MASK         0xFF
     56#define FO_LevelShift   8
     57#define HIGH_ADR (LPWSTR)0xffffffff
    4558
    4659CHAR aWildcardFile[] = {'*','.','*',0};
    47 WCHAR wWildcardFile[] = {'*','.','*',0};
    48 WCHAR wWildcardChars[] = {'*','?',0};
     60WCHAR wWildcardChars[] = {'?','*',0};
     61#define wWildcardFile &wWildcardChars[1]
    4962WCHAR wBackslash[] = {'\\',0};
    5063
     
    5568static BOOL SHNotifyDeleteFileA(LPCSTR path);
    5669static BOOL SHNotifyDeleteFileW(LPCWSTR path);
     70static BOOL SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest);
     71static BOOL SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bRenameIfExists);
    5772
    5873typedef struct
     
    121136
    122137/**************************************************************************
    123  *  SHELL_DeleteDirectoryA()
     138 * SHELL_DeleteDirectoryA()  [internal]
    124139 *
    125140 * like rm -r
     
    196211
    197212/**************************************************************************
    198  *  SHELL_DeleteFileA()
     213 *  SHELL_DeleteFileA()      [internal]
    199214 */
    200215BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
     
    215230
    216231/**************************************************************************
    217  * Win32CreateDirectory      (SHELL32_93)   [SHELL32.93]
     232 * Win32CreateDirectory      [SHELL32.93]
    218233 *
    219234 * Creates a directory. Also triggers a change notify if one exists.
     235 *
     236 * PARAMS
     237 *  path       [I]   path to directory to create
     238 *
     239 * RETURNS
     240 *  TRUE if successful, FALSE otherwise
     241 *
     242 * NOTES:
     243 *  Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI.
     244 *  This is Unicode on NT/2000
    220245 */
    221246static BOOL SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec)
     
    253278
    254279/************************************************************************
    255  * Win32RemoveDirectory      (SHELL32_94)   [SHELL32.94]
     280 * Win32RemoveDirectory      [SHELL32.94]
    256281 *
    257282 * Deletes a directory. Also triggers a change notify if one exists.
     283 *
     284 * PARAMS
     285 *  path       [I]   path to directory to delete
     286 *
     287 * RETURNS
     288 *  TRUE if successful, FALSE otherwise
     289 *
     290 * NOTES:
     291 *  Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI.
     292 *  This is Unicode on NT/2000
    258293 */
    259294static BOOL SHNotifyRemoveDirectoryA(LPCSTR path)
     
    303338
    304339/************************************************************************
    305  * Win32DeleteFile           (SHELL32_164)  [SHELL32.164]
     340 * Win32DeleteFile           [SHELL32.164]
    306341 *
    307342 * Deletes a file. Also triggers a change notify if one exists.
     343 *
     344 * PARAMS
     345 *  path       [I]   path to file to delete
     346 *
     347 * RETURNS
     348 *  TRUE if successful, FALSE otherwise
    308349 *
    309350 * NOTES:
     
    358399}
    359400
    360 /*************************************************************************
    361  * SHCreateDirectory                       [SHELL32.165]
     401/************************************************************************
     402 * SHNotifyMoveFile          [internal]
     403 *
     404 * Moves a file. Also triggers a change notify if one exists.
     405 *
     406 * PARAMS
     407 *  src        [I]   path to source file to move
     408 *  dest       [I]   path to target file to move to
     409 *
     410 * RETURNS
     411 *  TRUE if successful, FALSE otherwise
     412 */
     413static BOOL SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest)
     414{
     415        BOOL ret;
     416
     417        TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest));
     418
     419        ret = MoveFileW(src, dest);
     420        if (!ret)
     421        {
     422          /* Source file may be write protected or a system file */
     423          DWORD dwAttr = GetFileAttributesW(src);
     424          if ((dwAttr != -1) && (dwAttr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
     425            if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
     426              ret = MoveFileW(src, dest);
     427        }
     428        if (ret)
     429          SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATHW, src, dest);
     430        return ret;
     431}
     432
     433/************************************************************************
     434 * SHNotifyCopyFile          [internal]
     435 *
     436 * Copies a file. Also triggers a change notify if one exists.
     437 *
     438 * PARAMS
     439 *  src        [I]   path to source file to move
     440 *  dest       [I]   path to target file to move to
     441 *  bRename    [I]   if TRUE, the target file will be renamed if a
     442 *                   file with this name already exists
     443 *
     444 * RETURNS
     445 *  TRUE if successful, FALSE otherwise
     446 */
     447static BOOL SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bRename)
     448{
     449        BOOL ret;
     450
     451        TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bRename ? "renameIfExists" : "");
     452
     453        ret = CopyFileW(src, dest, TRUE);
     454        if (!ret && bRename)
     455        {
     456          /* Destination file probably exists */
     457          DWORD dwAttr = GetFileAttributesW(dest);
     458          if (dwAttr != -1)
     459          {
     460            FIXME("Rename on copy to existing file not implemented!");
     461          }
     462        }
     463        if (ret)
     464          SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
     465        return ret;
     466}
     467
     468/*************************************************************************
     469 * SHCreateDirectory         [SHELL32.165]
     470 *
     471 * Create a directory at the specified location
     472 *
     473 * PARAMS
     474 *  hWnd       [I]
     475 *  path       [I]   path of directory to create
     476 *
     477 * RETURNS
     478 *  ERRROR_SUCCESS or one of the following values:
     479 *  ERROR_BAD_PATHNAME if the path is relative
     480 *  ERROR_FILE_EXISTS when a file with that name exists
     481 *  ERROR_ALREADY_EXISTS when the directory already exists
     482 *  ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
    362483 *
    363484 * NOTES
    364485 *  exported by ordinal
     486 *  Win9x exports ANSI
    365487 *  WinNT/2000 exports Unicode
    366488 */
     
    373495
    374496/*************************************************************************
    375  * SHCreateDirectoryExA                     [SHELL32.@]
     497 * SHCreateDirectoryExA      [SHELL32.@]
     498 *
     499 * Create a directory at the specified location
     500 *
     501 * PARAMS
     502 *  hWnd       [I]
     503 *  path       [I]   path of directory to create
     504 *  sec        [I]   security attributes to use or NULL
     505 *
     506 * RETURNS
     507 *  ERRROR_SUCCESS or one of the following values:
     508 *  ERROR_BAD_PATHNAME if the path is relative
     509 *  ERROR_FILE_EXISTS when a file with that name exists
     510 *  ERROR_ALREADY_EXISTS when the directory already exists
     511 *  ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
    376512 */
    377513DWORD WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec)
     
    385521
    386522/*************************************************************************
    387  * SHCreateDirectoryExW                     [SHELL32.@]
     523 * SHTryFind      [intern]
     524 * Try for existing names
     525 */
     526DWORD SHTryFindW(LPCWSTR pName)
     527{
     528        WCHAR szName [MAX_PATH + 4];
     529        DWORD retCode = ERROR_FILE_NOT_FOUND;
     530        WIN32_FIND_DATAW wfd;
     531        HANDLE  hFind;
     532        LPCWSTR pFileName = StrRChrW(pName,NULL,'\\');
     533        if ((!pFileName) || \
     534          /* we must isolate the part befor '\' */
     535          (lstrcpynW(&szName[0],pName,(pFileName-pName)),
     536           NULL != StrPBrkW(&szName[0], wWildcardChars)))
     537        {
     538          return ERROR_INVALID_NAME;
     539        }
     540        hFind = FindFirstFileW(pName, &wfd);
     541        if (INVALID_HANDLE_VALUE != hFind)
     542        {
     543          FindClose(hFind);
     544          retCode = ERROR_ALREADY_EXISTS;
     545        }
     546        return retCode;
     547}
     548/*************************************************************************
     549 * SHCreateDirectoryExW      [SHELL32.@]
    388550 */
    389551DWORD WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
    390552{
    391         DWORD ret = ERROR_SUCCESS;
     553        DWORD ret = SHTryFindW(path);
    392554        TRACE("(%p, %s, %p)\n",hWnd, debugstr_w(path), sec);
    393555
    394         if (PathIsRelativeW(path))
    395         {
    396           ret = ERROR_BAD_PATHNAME;
    397           SetLastError(ERROR_BAD_PATHNAME);
    398         }
    399         else
     556        if (ERROR_FILE_NOT_FOUND == ret)
     557        {
     558          ret = ERROR_SUCCESS;
     559          if (PathIsRelativeW(path))
     560          {
     561            ret = ERROR_BAD_PATHNAME;
     562          }
     563        }
     564        SetLastError(ret);
     565        if (ERROR_SUCCESS == ret)
    400566        {
    401567          if (!SHNotifyCreateDirectoryW(path, sec))
     
    406572                ret != ERROR_FILENAME_EXCED_RANGE)
    407573            {
    408             /*lstrcpynW(pathName, path, MAX_PATH);
     574            /* handling network file names?
     575              lstrcpynW(pathName, path, MAX_PATH);
    409576              lpStr = PathAddBackslashW(pathName);*/
    410577              FIXME("Semi-stub, non zero hWnd should be used somehow?");
     
    496663 *
    497664 * Accepts two \0 delimited lists of the file names. Checks whether number of
    498  * files in the both lists is the same,
    499  * and checks also if source-name exists.
    500  */
    501 BOOL SHELL_FileNamesMatch(LPCWSTR pszFiles1, LPCWSTR pszFiles2, BOOL B_OnlyFrom)
    502 {
    503         while (              (pszFiles1[0] != '\0') &&
    504              (B_OnlyFrom || (pszFiles2[0] != '\0')))
    505         {
    506           if (NULL == StrPBrkW(pszFiles1, wWildcardChars))
     665 * files in both lists is the same, and checks also if source-name exists.
     666 */
     667BOOL SHELL_FileNamesMatch(LPCWSTR pszFiles1, LPCWSTR pszFiles2, BOOL bOnlySrc)
     668{
     669        LPWSTR pszTemp;
     670        while ((pszFiles1[0] != '\0') &&
     671               (bOnlySrc || (pszFiles2[0] != '\0')))
     672        {
     673          pszTemp = StrChrW(pszFiles1,'\\');
     674          /* root (without mask/name) is also not allowed as source, tested in W98 */
     675          if (!pszTemp || !pszTemp[1])
     676            return FALSE;
     677          pszTemp = StrPBrkW(pszFiles1, wWildcardChars);
     678          if (pszTemp)
     679          {
     680            WCHAR szMask [MAX_PATH + 4];
     681            strncpyW(&szMask[0],pszFiles1,(pszTemp - pszFiles1));
     682            pszTemp = StrRChrW(&szMask[0],NULL,'\\');
     683            if (!pszTemp)
     684              return FALSE;
     685            pszTemp[0] = '\0';
     686        /* we will check the root of the mask as valid dir */
     687            if (!IsAttribDir(GetFileAttributesW(&szMask[0])))
     688              return FALSE;
     689          }
     690          else
    507691          {
    508692            if (-1 == GetFileAttributesW(pszFiles1))
     
    510694          }
    511695          pszFiles1 += lstrlenW(pszFiles1) + 1;
    512           if (!B_OnlyFrom)
     696          if (!bOnlySrc)
    513697            pszFiles2 += lstrlenW(pszFiles2) + 1;
    514698        }
    515         return
    516           (              (pszFiles1[0] == '\0') &&
    517           (B_OnlyFrom || (pszFiles2[0] == '\0')));
    518 }
    519 
    520 /*************************************************************************
    521  *
    522  * SHName(s)Translate HelperFunction for SHFileOperationA
    523  *
     699        return ((pszFiles1[0] == '\0') && (bOnlySrc || (pszFiles2[0] == '\0')));
     700}
     701
     702/*************************************************************************
     703 *
     704 * SHName(s)Translate HelperFunction for SHFileOperationW
     705 *
     706 * Translates a list of 0 terminated ASCI strings into Unicode. If *wString
     707 * is NULL, only the necessary size of the string is determined and returned,
     708 * otherwise the ASCII strings are copied into it and the buffer is increased
     709 * to point to the location after the final 0 termination char.
    524710 */
    525711DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more)
    526712{
    527         DWORD retSize = 0, size;
    528         LPCSTR aString = (LPSTR)pWToFrom[0];
    529         if (pWToFrom[0])
    530         {
    531           if (wString[0]) /* only in the second loop */
    532             pWToFrom[0] = wString[0];
     713        DWORD size = 0, aSize = 0;
     714        LPCSTR aString = (LPCSTR)*pWToFrom;
     715
     716        if (aString)
     717        {
    533718          do
    534719          {
    535720            size = lstrlenA(aString) + 1;
    536             if (wString[0]) /* only in the second loop */
    537             {
    538               MultiByteToWideChar(CP_ACP, 0, aString, size, wString[0], size);
    539               wString[0] += size;
    540             }
     721            aSize += size;
    541722            aString += size;
    542             retSize += size;
    543           } while ((size != 1) & more);
    544           retSize = ((retSize+0x7) & -8);
    545         }
    546 return retSize;
    547 }
    548 /*************************************************************************
    549  * SHFileOperationA        [SHELL32.@]
     723          } while ((size != 1) && more);
     724          /* The two sizes might be different in the case of multibyte chars */
     725          size = MultiByteToWideChar(CP_ACP, 0, aString, aSize, *wString, 0);
     726          if (*wString) /* only in the second loop */
     727          {
     728            MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, size);
     729            *pWToFrom = *wString;
     730            *wString += size;
     731          }
     732        }
     733        return size;
     734}
     735/*************************************************************************
     736 * SHFileOperationA          [SHELL32.@]
     737 *
     738 * Function to copy, move, delete and create one or more files with optional
     739 * user prompts.
     740 *
     741 * PARAMS
     742 *  lpFileOp   [I/O] pointer to a structure containing all the necessary information
    550743 *
    551744 * NOTES
    552  *     exported by name
     745 *  exported by name
    553746 */
    554747DWORD WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
    555748{
    556749        SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp);
    557         DWORD retCode = 0, size = 0;
    558         LPWSTR wString = NULL; /* we change this in SHNameTranlate */
    559         LPWSTR ForFree = NULL;
    560 
     750        DWORD retCode = 0, size;
     751        LPWSTR ForFree = NULL, /* we change wString in SHNameTranslate and can't use it for freeing */
     752               wString = NULL; /* we change this in SHNameTranslate */
     753
     754#ifdef __WIN32OS2__
    561755        TRACE("SHFileOperationA");
    562         if (FO_DELETE == (nFileOp.wFunc & 0xf))
     756#else
     757        TRACE("\n");
     758#endif
     759        if (FO_DELETE == (nFileOp.wFunc & FO_MASK))
    563760          nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */
    564761        if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS))
    565762          nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */
    566         do
    567         {
    568           if (size)
    569           {
    570             ForFree = wString =  HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
    571             if (!wString)
    572             {
    573               retCode = ERROR_OUTOFMEMORY;
    574               SetLastError(retCode);
    575               goto shfileop_error;
    576             }
    577           }
     763        while (1) /* every loop calculate size, second translate also, if we have storage for this */
     764        {
    578765          size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */
    579766          size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */
    580767          size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */
    581            /* first loop only for calculate size, no translation, we hav a NULL-pointer */
    582         } while (!ForFree); /* second loop calculate size, also translation. We have a valid pointer */
    583 
    584         retCode = SHFileOperationW(&nFileOp);
    585 
    586 shfileop_error:
    587         if (ForFree)
    588           HeapFree(GetProcessHeap(), 0, ForFree);
    589 
    590         if (retCode)
    591         {
    592           nFileOp.fAnyOperationsAborted = TRUE;
    593         }
    594         lpFileOp->hNameMappings = nFileOp.hNameMappings;
    595         lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
     768
     769          if (ForFree)
     770          {
     771            retCode = SHFileOperationW(&nFileOp);
     772            HeapFree(GetProcessHeap(), 0, ForFree); /* we can not use wString, it was changed */
     773            lpFileOp->hNameMappings         = nFileOp.hNameMappings;
     774            lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
     775            return retCode;
     776          }
     777          else
     778          {
     779            wString = ForFree = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
     780            if (ForFree) continue;
     781            retCode = ERROR_OUTOFMEMORY;
     782            SetLastError(retCode);
     783            return retCode;
     784          }
     785        }
     786}
     787/*************************************************************************
     788 * SHFileOperationCheck
     789 */
     790DWORD SHFileOperationCheck(LPSHFILEOPSTRUCTW lpFileOp, LPCSTR* cFO_Name)
     791{
     792        FILEOP_FLAGS OFl = (FILEOP_FLAGS)lpFileOp->fFlags;
     793        LPCSTR cFO_Temp [] = {"FO_????","FO_MOVE","FO_COPY","FO_DELETE","FO_RENAME"};
     794        long retCode = NO_ERROR;
     795        long FuncSwitch = (lpFileOp->wFunc & FO_MASK);
     796
     797        /*  default no error */
     798
     799        if ((FuncSwitch < FO_MOVE) || (FuncSwitch > FO_RENAME))
     800        {
     801          FuncSwitch = 0;
     802          retCode = ERROR_INVALID_PARAMETER;
     803        }
     804        cFO_Name[0] = cFO_Temp [FuncSwitch];
     805
     806        if (!(~FO_MASK & lpFileOp->wFunc)) /* ? Level == 0 */
     807        {
     808          lpFileOp->fAnyOperationsAborted = FALSE;
     809          TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s%s \n",cFO_Name[0], OFl,
     810                      OFl & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
     811                      OFl & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
     812                      OFl & FOF_SILENT ? "FOF_SILENT " : "",
     813                      OFl & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
     814                      OFl & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
     815                      OFl & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
     816                      OFl & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
     817                      OFl & FOF_FILESONLY ? "FOF_FILESONLY " : "",
     818                      OFl & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
     819                      OFl & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
     820                      OFl & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
     821                      OFl & FOF_NOCOPYSECURITYATTRIBS ? "FOF_NOCOPYSECURITYATTRIBS" : "",
     822                      OFl & 0xf000 ? "MORE-UNKNOWN-Flags" : "");
     823          OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY));  /* implemented */
     824          OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOF_NOCOPYSECURITYATTRIBS); /* ignored, if one */
     825          OFl &= (~FOF_SIMPLEPROGRESS);                      /* ignored, only with FOF_SILENT */
     826          if (OFl)
     827          {
     828            if (OFl & (~(FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION |
     829                         FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOF_NOCOPYSECURITYATTRIBS)))
     830            {
     831                    TRACE("%s lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", cFO_Name[0], OFl);
     832              retCode = ERROR_INVALID_PARAMETER;
     833            }
     834            else
     835            {
     836                    TRACE("%s lpFileOp->fFlags=0x%x not fully implemented, stub\n", cFO_Name[0], OFl);
     837            } /* endif */
     838          } /* endif */
     839        }
    596840        return retCode;
    597841}
    598 
    599 /*************************************************************************
    600  * SHFileOperationW        [SHELL32.@]
    601  *
    602  * NOTES
    603  *     exported by name
    604  */
    605 
    606 /* in w98 brings shell32_test.exe this 4 failures
    607 shlfileop.c:177: Test failed: Can't rename many files
    608  * W98 return 0 without action
    609 shlfileop.c:185: Test failed: Can't rename many files
    610  * W98 return 0 without action
    611 shlfileop.c:286: Test failed: Files are copied to other directory
    612 shlfileop.c:287: Test failed: The file is copied
    613  * This two messages are in W98 / W2K also
    614 shlfileop: 121 tests executed, 0 marked as todo, 4 failures.
    615  * this implementation has only the last 2 messages (W2K lyke)
    616 */
    617 
     842/*************************************************************************
     843 *
     844 * SHFileOperationMove HelperFunction for SHFileOperationW
     845 *
     846 * Contains the common part of FO_MOVE/FO_RENAME.
     847 * It is not with recursive call solvable.
     848 * We have both tryed FO_RENAME contains not FO_MOVE and
     849 * also FO_RENAME does not contains FO_MOVE, only common Parts.
     850 */
     851DWORD SHFileOperationMove(LPSHFILEOPSTRUCTW lpFileOp)
     852{
     853        DWORD retCode;
     854        WCHAR szToName [MAX_PATH + 4];
     855        LPWSTR pToFile;
     856        if (NULL != StrPBrkW(lpFileOp->pTo, wWildcardChars))
     857        {
     858#ifdef W98_FO_FUNCTION /* W98 */
     859          return ERROR_FILE_NOT_FOUND;
     860#else
     861          return ERROR_INVALID_NAME;
     862#endif
     863        }
     864        retCode = SHTryFindW(lpFileOp->pTo);
     865        /* FOF_NOCONFIRMATION, FOF_RENAMEONCOLLISION ? */
     866        if (retCode != ERROR_FILE_NOT_FOUND)
     867        {
     868          return retCode;
     869        }
     870        lstrcpyW(&szToName[0],lpFileOp->pTo);
     871        pToFile = StrRChrW(&szToName[0],NULL,'\\');
     872        if (!pToFile[1])
     873        {
     874          pToFile[0] = '\0';
     875        }
     876        /* we use SHNotifyMoveFile() instead MoveFileW */
     877        if (!SHNotifyMoveFileW(lpFileOp->pFrom, &szToName[0]))
     878        {
     879          /* we need still the value for the returncode */
     880          return GetLastError();
     881        }
     882        return ERROR_SUCCESS;
     883}
     884/*************************************************************************
     885 * SHFileOperationW          [SHELL32.@]
     886 *
     887 * See SHFileOperationA
     888 */
    618889DWORD WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
    619890{
    620         SHFILEOPSTRUCTW nFileOp = *(lpFileOp);
     891        SHFILEOPSTRUCTW nFileOp = lpFileOp ? *(lpFileOp):nFileOp;
    621892
    622893        LPCWSTR pNextFrom = nFileOp.pFrom;
     
    624895        LPCWSTR pFrom = pNextFrom;
    625896        LPCWSTR pTo = NULL;
    626         LPCSTR Debug_pFrom;
    627         LPCSTR Debug_pTo;
     897#ifdef __WIN32OS2__
     898#ifdef DEBUG
     899#define _SHFO_DEBUGSTR_
     900#ifdef _SHFO_DEBUGSTR_
     901        CHAR Debug_pFrom [MAX_PATH + 4];
     902        CHAR Debug_pTo [MAX_PATH + 4];
     903#endif
     904#endif
     905#endif
    628906        HANDLE hFind = INVALID_HANDLE_VALUE;
    629907        WIN32_FIND_DATAW wfd;
     
    631909        LPWSTR pTempTo = NULL;
    632910        LPWSTR pFromFile;
    633         LPWSTR pToFile;
    634         LPWSTR lpFileName;
    635         long retCode = 0;
     911        LPWSTR pToFile = NULL;
     912        LPWSTR pToTailSlash; /* points also to ToMask, we know not what is this */
     913        LPWSTR lpFileName; /* temporary for pFromFile,pToFile,pToTailSlash */
    636914        DWORD ToAttr;
    637915        DWORD ToPathAttr;
     916        DWORD FromAttr;
    638917        DWORD FromPathAttr;
    639         FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
    640 
     918       
    641919        BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES);
    642920
    643         BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & 0xf));
    644         BOOL b_MultiPaired = (!b_MultiTo);
     921        BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & FO_MASK));
     922        BOOL b_MultiPaired = FALSE;
    645923        BOOL b_MultiFrom = FALSE;
    646924        BOOL not_overwrite;
    647925        BOOL ask_overwrite;
    648926        BOOL b_SameRoot;
    649         BOOL b_SameTailName;
    650         BOOL b_ToInvalidTail;
    651         BOOL b_ToValid; /* for W98-Bug for FO_MOVE with source and taget in same rootdrive */
    652         BOOL b_Mask; /* wird als Schalter benutzt, vieleicht finde ich die richtige bitposition */
    653         BOOL b_ToTailSlash;
    654         LPCSTR cFO_Name [] = {"FO_????","FO_MOVE","FO_COPY","FO_DELETE","FO_RENAME"};
    655 
    656         long FuncSwitch = (nFileOp.wFunc & 0xf);
    657         long level= nFileOp.wFunc>>4;
    658 
    659 /*  default no error */
    660         nFileOp.fAnyOperationsAborted = FALSE;
    661 
    662         if ((FuncSwitch < FO_MOVE) || (FuncSwitch > FO_RENAME))
    663           goto shfileop_normal; /* no valid FunctionCode */
    664 
    665         cFO_Name[0] = cFO_Name [FuncSwitch];
    666         if (level == 0)
    667           TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n",cFO_Name[0], nFileOp.fFlags,
    668                       nFileOp.fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
    669                       nFileOp.fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
    670                       nFileOp.fFlags & FOF_SILENT ? "FOF_SILENT " : "",
    671                       nFileOp.fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
    672                       nFileOp.fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
    673                       nFileOp.fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
    674                       nFileOp.fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
    675                       nFileOp.fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
    676                       nFileOp.fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
    677                       nFileOp.fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
    678                       nFileOp.fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
    679                       nFileOp.fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
    680         ;
    681         {
    682                       /* establish when pTo is interpreted as the name of the destination file
    683                        * or the directory where the Fromfile should be copied to.
    684                        * This depends on:
    685                        * (1) pTo points to the name of an existing directory;
    686                        * (2) the flag FOF_MULTIDESTFILES is present;
    687                        * (3) whether pFrom point to multiple filenames.
    688                        *
    689                        * Some experiments:
    690                        *
    691                        * destisdir               1 1 1 1 0 0 0 0
    692                        * FOF_MULTIDESTFILES      1 1 0 0 1 1 0 0
    693                        * multiple from filenames 1 0 1 0 1 0 1 0
    694                        *                         ---------------
    695                        * copy files to dir       1 0 1 1 0 0 1 0
    696                        * create dir              0 0 0 0 0 0 1 0
    697                        */
     927        BOOL b_SameRoot_MOVE;
     928        BOOL b_ToMask = FALSE;
     929        BOOL b_FromMask;
     930
     931        long FuncSwitch = (nFileOp.wFunc & FO_MASK);
     932        long level= nFileOp.wFunc>>FO_LevelShift;
     933
     934        LPCSTR cFO_Name;
     935        long retCode = SHFileOperationCheck(&nFileOp,&cFO_Name);
     936
     937        if (retCode)
     938        {
     939#ifdef W98_FO_FUNCTION /* W98 returns NO_ERROR */
     940          if ('?' == cFO_Name[3])
     941            retCode = NO_ERROR;
     942#endif
     943          goto shfileop_exit; /* no valid FunctionCode */
     944        }
     945
     946        /* establish when pTo is interpreted as the name of the destination file
     947         * or the directory where the Fromfile should be copied to.
     948         * This depends on:
     949         * (1) pTo points to the name of an existing directory;
     950         * (2) the flag FOF_MULTIDESTFILES is present;
     951         * (3) whether pFrom point to multiple filenames.
     952         *
     953         * Some experiments:
     954         *
     955         * destisdir               1 1 1 1 0 0 0 0
     956         * FOF_MULTIDESTFILES      1 1 0 0 1 1 0 0
     957         * multiple from filenames 1 0 1 0 1 0 1 0
     958         *                         ---------------
     959         * copy files to dir       1 0 1 1 0 0 1 0
     960         * create dir              0 0 0 0 0 0 1 0
     961         */
    698962/*
    699  * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY          are    implemented
    700  * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS    are not implemented and ignored
    701  * FOF_RENAMEONCOLLISION                             are    implemented partially and breaks if file exist
    702  * FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE                    are not implemented and breaks
     963 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY  are implemented
     964 * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR,
     965 *       FOF_SIMPLEPROGRESS, FOF_NOCOPYSECURITYATTRIBS    are not implemented and ignored
     966 * FOF_RENAMEONCOLLISION                                  are implemented partially and breaks if file exist
     967 * FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE                   are not implemented and breaks
    703968 * if any other flag set, an error occurs
    704969 */
    705           TRACE(" %s level=%d nFileOp.fFlags=0x%x\n", cFO_Name[0], level, lpFileOp->fFlags);
    706 
    707 /*    OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY)); */
    708 /*    OFl ^= (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR); */
    709           OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY));  /* implemented */
    710           OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI); /* ignored, if one */
    711           OFl &= (~FOF_SIMPLEPROGRESS);                      /* ignored, only with FOF_SILENT */
    712           if (OFl)
    713           {
    714             if (OFl & ( ~ (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI)))
    715             {
    716               TRACE("%s level=%d lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", cFO_Name[0], level, OFl);
    717               retCode = 0x403; /* 1027, we need a extension of shlfileop */
    718               goto shfileop_error;
    719             }
    720             else
    721             {
    722               TRACE("%s level=%d lpFileOp->fFlags=0x%x not full implemented ,stub\n", cFO_Name[0], level, OFl);
    723             } /* endif */
    724           } /* endif */
     970          TRACE(" %s level=%ld nFileOp.fFlags=0x%x\n", cFO_Name, level, nFileOp.fFlags);
    725971
    726972          if ((pNextFrom) && (!(b_MultiTo) || (pNextTo)))
     
    731977              retCode = ERROR_OUTOFMEMORY;
    732978              SetLastError(retCode);
    733               goto shfileop_error;
     979              goto shfileop_exit;
    734980            }
    735981            if (b_MultiTo)
     
    742988          {
    743989            retCode = 0x402;      /* 1026 */
    744             goto shfileop_error;
     990            goto shfileop_exit;
    745991          }
    746 /* need break at error before change sourcepointer */
    747           while(!nFileOp.fAnyOperationsAborted && (pNextFrom[0]))
    748           {
    749             nFileOp.wFunc =  ((level + 1) << 4) + FuncSwitch;
     992          /* need break at error before change sourcepointer */
     993          while(!retCode && (pNextFrom[0]))
     994          {
     995            nFileOp.wFunc =  ((level + 1) << FO_LevelShift) + FuncSwitch;
    750996            nFileOp.fFlags = lpFileOp->fFlags;
    751997
     
    7581004
    7591005            pFrom = pNextFrom;
     1006#ifdef _SHFO_DEBUGSTR_
     1007            /* for seeing in debugger outside from TRACE */
     1008            strcpy(&Debug_pFrom[0],debugstr_w(pFrom));
     1009            strcpy(&Debug_pTo[0],debugstr_w(pTo));
     1010            TRACE("%s level=%ld with %s %s%s\n",
     1011              cFO_Name, level, &Debug_pFrom[0], pTo ? "-> ":"", &Debug_pTo[0]);
     1012#endif
    7601013            pNextFrom = &pNextFrom[lstrlenW(pNextFrom)+1];
    7611014            if (!b_MultiFrom && !b_MultiTo)
     
    7631016
    7641017            pFromFile = SHFileStrCpyCatW(pTempFrom, pFrom, NULL);
    765 
    766 /* for seeing in debugger outside from TRACE */
    767             Debug_pFrom = debugstr_w(pFrom);
    768             Debug_pTo = debugstr_w(pTo);
    769             TRACE("%s level=%d with %s %s%s\n",
    770               cFO_Name[0], level, Debug_pFrom, pTo ? "-> ":"", Debug_pTo);
     1018            b_FromMask = (pFromFile && (NULL != StrPBrkW(&pFromFile[1], wWildcardChars)));
    7711019
    7721020            if (pTo)
    7731021            {
    7741022              pToFile = SHFileStrCpyCatW(pTempTo, pTo, NULL);
     1023              b_ToMask = (NULL != StrPBrkW(pTempTo, wWildcardChars));
    7751024            }
     1025
     1026            if (FO_RENAME == FuncSwitch)
     1027            {
     1028              if (b_MultiTo || b_MultiFrom || (b_FromMask && !b_ToMask))
     1029              {
     1030#define retCodeIsInvalid 0x075 /* W98 */
     1031#ifndef W98_FO_FUNCTION /* is W2K */
     1032#undef retCodeIsInvalid
     1033#define retCodeIsInvalid 0x4c7 /* W2K */
     1034                retCode = 0x1f;    /* value 31 in W2K, W98 no work, only RC=0 */
     1035#endif
     1036                goto shfileop_exit;
     1037              }
     1038            }
     1039
    7761040            if (!b_MultiPaired)
    7771041            {
    7781042              b_MultiPaired =
    779                 SHELL_FileNamesMatch(lpFileOp->pFrom, lpFileOp->pTo, (!b_Multi || b_MultiFrom));
     1043                SHELL_FileNamesMatch(lpFileOp->pFrom,
     1044                      lpFileOp->pTo, ((FO_DELETE == FuncSwitch) || !b_Multi || b_MultiFrom));
    7801045            } /* endif */
    7811046            if (!(b_MultiPaired) || !(pFromFile) || !(pFromFile[1]) || ((pTo) && !(pToFile)))
    7821047            {
    7831048              retCode = 0x402;      /* 1026 */
    784               goto shfileop_error;
     1049              goto shfileop_exit;
    7851050            }
    786             if (pTo)
    787             {
    788               b_ToTailSlash = (!pToFile[1]);
    789               if (b_ToTailSlash)
    790               {
    791                 pToFile[0] = '\0';
    792                 if (StrChrW(pTempTo,'\\'))
    793                 {
    794                   pToFile = SHFileStrCpyCatW(pTempTo, NULL, NULL);
    795                 }
    796               }
    797               b_ToInvalidTail = (NULL != StrPBrkW(&pToFile[1], wWildcardChars));
    798             }
    799 
    800             /* for all */
    801             b_Mask = (NULL != StrPBrkW(&pFromFile[1], wWildcardChars));
    802             if (FO_RENAME == FuncSwitch)
    803             {
    804               /* temporary only for FO_RENAME */
    805 /* ???  b_Mask = (NULL != strrbrk(pFrom,"*?")); */
    806               if (b_MultiTo || b_MultiFrom || (b_Mask && !b_ToInvalidTail))
    807               {
    808                 /* no work, only RC=0 */
    809 /* ???    nFileOp.fAnyOperationsAborted = TRUE; */
    810 //#define W98_FO_RENEME
    811 #ifdef W98_FO_RENEME
    812                 goto shfileop_normal;
    813 #endif
    814                 retCode = 0x1;      /* 1 value unknown, W98 returns no error */
    815                 goto shfileop_error;
    816               }
    817             }
    818 
    819             hFind = FindFirstFileW(pFrom, &wfd);
    820             if (INVALID_HANDLE_VALUE == hFind)
    821             {
    822                if ((FO_DELETE == FuncSwitch) && (b_Mask))
    823               {
    824                 pFromFile[0] = '\0';
    825                 FromPathAttr = GetFileAttributesW(pTempFrom);
    826                 pFromFile[0] = '\\';
    827                 if (IsAttribDir(FromPathAttr))
    828                 {
    829                 /* FO_DELETE with mask and without found is valid */
    830                   goto shfileop_normal;
    831                  } /* endif */
    832                } /* endif */
    833               /* root (without mask) is also not allowed as source, tested in W98 */
    834               retCode = 0x402;   /* 1026 */
    835               goto shfileop_error;
    836             } /* endif */
    837 
    838 /* for all */
    839 #define HIGH_ADR (LPWSTR)0xffffffff
    840 
    841 /* ??? b_Mask = (!SHFileStrICmpA(&pFromFile[1], &wfd.cFileName[0], HIGH_ADR, HIGH_ADR)); */
    842 
    843             if (!pTo) /* FO_DELETE */
    844             {
     1051
     1052            if (FO_DELETE == FuncSwitch)
     1053            {
     1054              hFind = FindFirstFileW(pFrom, &wfd);
     1055              if (INVALID_HANDLE_VALUE == hFind)
     1056                /* no problem for FO_DELETE */
     1057                continue;
    8451058              do
    8461059              {
    847                  lpFileName = wfd.cAlternateFileName;
    848                  if (!lpFileName[0])
     1060                lpFileName = wfd.cAlternateFileName;
     1061                if (!lpFileName[0])
    8491062                   lpFileName = wfd.cFileName;
    8501063                if (IsDotDir(lpFileName) ||
    851                     ((b_Mask) && IsAttribDir(wfd.dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
    852                   continue; /* next name in pTempFrom(dir) */
     1064                    ((b_FromMask) && IsAttribDir(wfd.dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
     1065                  continue;
    8531066                SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
    8541067                /* TODO: Check the SHELL_DeleteFileOrDirectoryW() function in shell32.dll */
    8551068                if (IsAttribFile(wfd.dwFileAttributes))
    8561069                {
    857                   nFileOp.fAnyOperationsAborted = (!SHNotifyDeleteFileW(pTempFrom));
    858                   retCode = 0x78; /* value unknown */
     1070                  if (!SHNotifyDeleteFileW(pTempFrom))
     1071                    retCode = 0x78; /* value unknown */
    8591072                }
    8601073                else
    8611074                {
    862                   nFileOp.fAnyOperationsAborted = (!SHELL_DeleteDirectoryW(pTempFrom, (!(nFileOp.fFlags & FOF_NOCONFIRMATION))));
    863                   retCode = 0x79; /* value unknown */
     1075                  if (!SHELL_DeleteDirectoryW(pTempFrom, (!(nFileOp.fFlags & FOF_NOCONFIRMATION))))
     1076                    retCode = 0x79; /* value unknown */
    8641077                }
    865               } while (!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd));
     1078              } while (!retCode && FindNextFileW(hFind, &wfd));
    8661079              FindClose(hFind);
    867               hFind = INVALID_HANDLE_VALUE;
    868               if (nFileOp.fAnyOperationsAborted)
    869               {
    870                 goto shfileop_error;
    871               }
    8721080              continue;
    8731081            } /* FO_DELETE ends, pTo must be always valid from here */
    8741082
    875             b_SameRoot = (towupper(pTempFrom[0]) == towupper(pTempTo[0]));
    876             b_SameTailName = SHFileStrICmpW(pToFile, pFromFile, NULL, NULL);
    877 
     1083            pToTailSlash = NULL;
     1084            if ((pToFile) && !(pToFile[1]))
     1085            {
     1086              pToFile[0] = '\0';
     1087              lpFileName = StrRChrW(pTempTo,NULL,'\\');
     1088              if (lpFileName)
     1089              {
     1090                pToTailSlash = pToFile;
     1091                pToFile = lpFileName;
     1092              }
     1093            }
    8781094            ToPathAttr = ToAttr = GetFileAttributesW(pTempTo);
    879             if (!b_Mask && (ToAttr -1) && (pToFile))
     1095            FromAttr = GetFileAttributesW(pTempFrom);
     1096            b_SameRoot = (toupperW(pTempFrom[0]) == toupperW(pTempTo[0]));
     1097            b_SameRoot_MOVE = (b_SameRoot && (FO_MOVE == FuncSwitch));
     1098            if ((pToFile) && !IsAttribDir(ToAttr))
    8801099            {
    8811100              pToFile[0] = '\0';
     
    8831102              pToFile[0] = '\\';
    8841103            }
    885 
     1104            if (pToTailSlash)
     1105            {
     1106              pToTailSlash[0] = '\\';
     1107            }
     1108            if (!b_FromMask && b_SameRoot && \
     1109              SHFileStrICmpW(pTempFrom, pTempTo, NULL, NULL))
     1110            { /* target is the same as source ? W98 has 0x71, W2K also */
     1111              retCode = 0x71; /* is no error with FOF_RENAMEONCOLLISION */
     1112              goto shfileop_exit;
     1113            } /* endif */
     1114            /* FO_RENAME is not only a Filter for FO_MOVE */
    8861115            if (FO_RENAME == FuncSwitch)
    8871116            {
    888               if (!b_SameRoot || b_Mask /* FO_RENAME works not with Mask */
    889                || !SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL)
    890                || (SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, HIGH_ADR) && !b_ToTailSlash))
     1117              if (b_FromMask || !b_SameRoot || \
     1118                !SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL) || \
     1119                 SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, HIGH_ADR))
    8911120              {
    892                 retCode = 0x73;
    893                 goto shfileop_error;
     1121                retCode = 0x73; /* must be here or before, not later */
     1122                goto shfileop_exit;
    8941123              }
    895               if (b_ToInvalidTail)
     1124#ifdef W98_FO_FUNCTION /* not in W2K, later in SHFileOperationMove */
     1125              if (!pToTailSlash && IsAttribDir(ToAttr))
    8961126              {
    897                 retCode=0x2;
    898                 goto shfileop_error;
     1127                retCode = ERROR_INVALID_NAME; /* FOF_NOCONFIRMATION, FOF_RENAMEONCOLLISION ? */
     1128                goto shfileop_exit;
    8991129              }
    900               if (-1 == ToPathAttr)
     1130              if (-1 != ToPathAttr || b_ToMask)
     1131#else
     1132              if (-1 != ToPathAttr)
     1133#endif
    9011134              {
    902                 retCode = 0x75;
    903                 goto shfileop_error;
     1135                retCode = SHFileOperationMove(&nFileOp);
     1136                goto shfileop_exit;
    9041137              }
    905               if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(ToAttr))
     1138            }
     1139            else \
     1140            if (!b_FromMask)
     1141            {
     1142              if (IsAttribDir(ToPathAttr))
    9061143              {
    907                 retCode = (b_ToTailSlash) ? 0xb7 : 0x7b;
    908                 goto shfileop_error;
    909               } /* endif */
    910               /* TODO: use SHNotifyMoveFile() instead ?? */
    911               if (!MoveFileW(pTempFrom, pTempTo))
     1144            /* Analycing for moving SourceName to as TargetName */
     1145                if (!b_MultiTo && IsAttribDir(ToAttr) && (b_MultiFrom || !b_Multi))
     1146                {
     1147                  SHFileStrCpyCatW(pTempTo, NULL, pFromFile);
     1148                  /* without FOF_MULTIDESTFILES shlfileop will create dir's recursive */
     1149                  nFileOp.fFlags |= FOF_MULTIDESTFILES;
     1150                  retCode = SHFileOperationW(&nFileOp);
     1151                  continue;
     1152                }
     1153              }
     1154              /* What can we do with one pair and FO_MOVE/FO_COPY ? */
     1155#ifndef W98_FO_FUNCTION /* W2K */
     1156              if (!b_SameRoot_MOVE || IsAttribDir(ToPathAttr))
     1157#endif
     1158              if (!b_MultiFrom)
     1159//            if ((!b_MultiFrom) && (!b_SameRoot_MOVE || IsAttribDir(ToPathAttr) || b_ToMask))
     1160
    9121161              {
    913                 /* we need still the value for the returncode, we use the mostly assumed */
    914                 retCode = 0xb7;
    915                 goto shfileop_error;
     1162                if (IsAttribFile(FromAttr))
     1163                {
     1164                  if (b_SameRoot_MOVE \
     1165               /* IsAttribDir(ToPathAttr) && !pToTailSlash && (bug) */
     1166               /* windos-bug, MOVE for File also with pToTailSlash, COPY not for this */
     1167//                    && IsAttribDir(ToPathAttr))
     1168                      && (IsAttribDir(ToPathAttr) || b_ToMask))
     1169                  {
     1170               /* At the same drive, we can move for FO_MOVE, dir to dir was solved later */
     1171                    retCode = SHFileOperationMove(&nFileOp);
     1172                    continue;
     1173                  } /* endif */
     1174                  if (IsAttribDir(ToPathAttr) && !pToTailSlash && !IsAttribDir(ToAttr))
     1175                  {
     1176                    if (IsAttribFile(ToAttr) && not_overwrite)
     1177                    {
     1178                      /* Rename on Collision ? */
     1179                      if (!ask_overwrite)
     1180                      {
     1181                        /* the retcode for this case is unknown */
     1182                        retCode = 0x10008;
     1183                        goto shfileop_exit;
     1184                      }
     1185                      /* we must change the dialog in the future for return 3-4 cases,
     1186                       * 'Yes','No','Yes for all','Never ?' */
     1187                      if (!SHELL_ConfirmDialogW(ASK_OVERWRITE_FILE, pTempTo))
     1188                      {
     1189                        nFileOp.fAnyOperationsAborted = TRUE;
     1190                        continue;
     1191                      }
     1192                    }
     1193                    if (!(SHNotifyCopyFileW(pTempFrom, pTempTo, nFileOp.fFlags & FOF_RENAMEONCOLLISION)))
     1194                    {
     1195                    /* the retcode for this case is unknown */
     1196                      retCode = 0x10009;
     1197                    }
     1198                    if ((FO_COPY == FuncSwitch) || retCode)
     1199                      continue;
     1200                    nFileOp.wFunc =  ((level+1) << FO_LevelShift) + FO_DELETE;
     1201                    retCode = SHFileOperationW(&nFileOp);
     1202                    continue;
     1203                  }
     1204                }
     1205                if (IsAttribDir(FromAttr))
     1206                {
     1207#ifdef W98_FO_FUNCTION /* not in W2K, -> retCode = retCodeIsInvalid */
     1208                  if ((-1 == ToAttr) && (!b_SameRoot_MOVE || IsAttribDir(ToPathAttr) || b_ToMask))
     1209                  {
     1210                    if (-1 == ToPathAttr)
     1211                    {
     1212                      pToFile[0] = '\0';
     1213                      retCode = SHCreateDirectoryExW(NULL,pTempTo, NULL);
     1214                      ToPathAttr = GetFileAttributesW(pTempTo);
     1215                      pToFile[0] = '\\';
     1216                      if (retCode)
     1217                        goto shfileop_exit;
     1218                    }
     1219#else
     1220                  if (-1 == ToAttr)
     1221                  {
     1222#endif
     1223                    if (IsAttribDir(ToPathAttr))
     1224                    {
     1225                      if (pToTailSlash)
     1226                            pToTailSlash[0] = '\0';
     1227                      retCode = SHCreateDirectoryExW(NULL,pTempTo, NULL);
     1228                      ToAttr = GetFileAttributesW(pTempTo); /* for continuing */
     1229                      if (pToTailSlash)
     1230                            pToTailSlash[0] = '\\';
     1231#ifndef W98_FO_FUNCTION /* W2k */
     1232                        if (retCode)
     1233                          goto shfileop_exit;
     1234#endif
     1235                    }
     1236                    if (-1 == ToAttr)
     1237                    {
     1238                      retCode = 0x10003;
     1239                      goto shfileop_exit;
     1240                    }
     1241                  }
     1242                  if (IsAttribDir(ToAttr))
     1243                  {
     1244                    /* both are existing dirs, we (FO_)MOVE/COPY the contence */
     1245                    pToFile = SHFileStrCpyCatW(pTempFrom, NULL, wWildcardFile);
     1246                    nFileOp.fFlags &= ~FOF_MULTIDESTFILES;
     1247                    retCode = SHFileOperationW(&nFileOp);
     1248                    if ((FO_COPY == FuncSwitch) || retCode)
     1249                      continue;
     1250                    ((DWORD*)pToFile)[0] = '\0';
     1251                    nFileOp.wFunc =  ((level+1) << FO_LevelShift) + FO_DELETE;
     1252                    retCode = SHFileOperationW(&nFileOp);
     1253                    continue;
     1254                  }
     1255                }
     1256              } /* end-!b_MultiFrom */
     1257            }
     1258
     1259#ifdef W98_FO_FUNCTION /* not in W2K, -> retCode = retCodeIsInvalid */
     1260            if (b_FromMask && \
     1261            /* we do not know, why (b_SameRoot_MOVE && b_ToMask && (-1 != ToPathAttr)) */
     1262                (IsAttribDir(ToAttr) || (b_SameRoot_MOVE && b_ToMask)))
     1263#else
     1264            if (b_FromMask && (-1 != ToPathAttr) && \
     1265            /* we do not know, why (b_SameRoot_MOVE && b_ToMask && (-1 != ToPathAttr)) */
     1266                (IsAttribDir(ToAttr) || (b_SameRoot_MOVE && b_ToMask)))
     1267#endif
     1268            {
     1269              /* FO_COPY/FO_MOVE with mask, FO_DELETE are solved lang before */
     1270              hFind = FindFirstFileW(pFrom, &wfd);
     1271              if (INVALID_HANDLE_VALUE == hFind)
     1272              {
     1273                /* the retcode for this case is unknown */
     1274                retCode = 0x10007;
     1275                goto shfileop_exit;
    9161276              }
    917               goto shfileop_normal;
    918             }
    919 
    920             /* W98 Bug with FO_MOVE different to FO_COPY, better the same as FO_COPY */
    921             b_ToValid = ((b_SameTailName &&  b_SameRoot && (FO_COPY == FuncSwitch)) ||
    922                       (b_SameTailName && !b_SameRoot) || (b_ToInvalidTail));
    923 
    924             /* handle mask in source */
    925             if (b_Mask)
    926             {
    927               if (!IsAttribDir(ToAttr))
    928               {
    929                 retCode = (b_ToInvalidTail &&/* b_SameTailName &&*/ (FO_MOVE == FuncSwitch)) \
    930                   ? 0x2 : 0x75;
    931                 goto shfileop_error;
    932               }
     1277              nFileOp.fFlags &= ~FOF_MULTIDESTFILES;
    9331278              pToFile = SHFileStrCpyCatW(pTempTo, NULL, wBackslash);
    934               nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES);
    9351279              do
    9361280              {
    937                  lpFileName = wfd.cAlternateFileName;
    938                  if (!lpFileName[0])
    939                    lpFileName = wfd.cFileName;
     1281                lpFileName = wfd.cAlternateFileName;
     1282                if (!lpFileName[0])
     1283                  lpFileName = wfd.cFileName;
    9401284                if (IsDotDir(lpFileName) ||
    9411285                    (IsAttribDir(wfd.dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
    9421286                  continue; /* next name in pTempFrom(dir) */
    943                 SHFileStrCpyCatW(&pToFile[1], lpFileName, NULL);
    9441287                SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
    9451288                retCode = SHFileOperationW (&nFileOp);
    946               } while(!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd));
     1289              } while(!retCode && FindNextFileW(hFind, &wfd));
     1290              FindClose(hFind);
     1291              continue;
    9471292            }
    948             FindClose(hFind);
    949             hFind = INVALID_HANDLE_VALUE;
    950             /* FO_COPY/FO_MOVE with mask, FO_DELETE and FO_RENAME are solved */
    951             if (b_Mask)
    952               continue;
    953 
    954             /* only FO_COPY/FO_MOVE without mask, all others are (must be) solved */
    955             if (IsAttribDir(wfd.dwFileAttributes) && (ToAttr -1))
    956             {
    957               if (pToFile)
    958               {
    959                 pToFile[0] = '\0';
    960                 ToPathAttr = GetFileAttributesW(pTempTo);
    961                 if ((ToPathAttr == -1) && b_ToValid)
    962                 {
    963                   /* create dir must be here, sample target D:\y\ *.* create with RC=10003 */
    964                   if (SHCreateDirectoryExW(NULL, pTempTo, NULL))
    965                   {
    966                     retCode = 0x73;/* value unknown */
    967                     goto shfileop_error;
    968                   }
    969                   ToPathAttr = GetFileAttributesW(pTempTo);
    970                 }
    971                 pToFile[0] = '\\';
    972                 if (b_ToInvalidTail)
    973                 {
    974                   retCode = 0x10003;
    975                   goto shfileop_error;
    976                 }
    977               }
    978             }
    979 
    980             /* trailing BackSlash is ever removed and pToFile points to BackSlash before */
    981             if (!b_MultiTo && (b_MultiFrom || (!(b_Multi) && IsAttribDir(ToAttr))))
    982             {
    983               if ((FO_MOVE == FuncSwitch) && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
    984               {
    985                 if (b_Multi)
    986                 {
    987                   retCode = 0x73; /* !b_Multi = 0x8 ?? */
    988                   goto shfileop_error;
    989                 }
    990               }
    991               pToFile = SHFileStrCpyCatW(pTempTo, NULL, wfd.cFileName);
    992               ToAttr = GetFileAttributesW(pTempTo);
    993             }
    994 
    995             if (IsAttribDir(ToAttr))
    996             {
    997               if (IsAttribFile(wfd.dwFileAttributes))
    998               {
    999                 retCode = (FO_COPY == FuncSwitch) ? 0x75 : 0xb7;
    1000                 goto shfileop_error;
    1001               }
    1002             }
    1003             else
    1004             {
    1005               pToFile[0] = '\0';
    1006               ToPathAttr = GetFileAttributesW(pTempTo);
    1007               pToFile[0] = '\\';
    1008               if (IsAttribFile(ToPathAttr))
    1009               {
    1010                 /* error, is this tested ? */
    1011                 retCode = 0x777402;
    1012                 goto shfileop_error;
    1013               } /* endif */
    1014             }
    1015 
    1016             /* singlesource + no mask */
    1017             if (-1 == (ToAttr & ToPathAttr))
    1018             {
    1019               /* Target-dir does not exist, and cannot be created */
    1020               retCode=0x75;
    1021               goto shfileop_error;
    1022             }
    1023 
    1024             switch(FuncSwitch)
    1025             {
    1026             case FO_MOVE:
    1027               pToFile = NULL;
    1028               if ((ToAttr == -1) && SHFileStrICmpW(pTempFrom, pTempTo, pFromFile, NULL))
    1029               {
    1030                 nFileOp.wFunc =  ((level+1)<<4) + FO_RENAME;
    1031               }
    1032               else
    1033               {
    1034                 if (b_SameRoot && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
    1035                 {
    1036                   /* we need pToFile for FO_DELETE after FO_MOVE contence */
    1037                   pToFile = SHFileStrCpyCatW(pTempFrom, NULL, wWildcardFile);
    1038                 }
    1039                 else
    1040                 {
    1041                   nFileOp.wFunc =  ((level+1)<<4) + FO_COPY;
    1042                 }
    1043               }
    1044               retCode = SHFileOperationW(&nFileOp);
    1045               if (pToFile)
    1046                 ((DWORD*)pToFile)[0] = '\0';
    1047               if (!nFileOp.fAnyOperationsAborted && (FO_RENAME != (nFileOp.wFunc & 0xf)))
    1048               {
    1049                 nFileOp.wFunc =  ((level+1)<<4) + FO_DELETE;
    1050                 retCode = SHFileOperationW(&nFileOp);
    1051               }
    1052               continue;
    1053             case FO_COPY:
    1054               if (SHFileStrICmpW(pTempFrom, pTempTo, NULL, NULL))
    1055               { /* target is the same as source ? */
    1056                 /* we still need the value for the returncode, we assume 0x71 */
    1057                 retCode = 0x71;
    1058                 goto shfileop_error;
    1059               } /* endif */
    1060               if (IsAttribDir((ToAttr & wfd.dwFileAttributes)))
    1061               {
    1062                 if (IsAttribDir(ToAttr) || !SHCreateDirectoryExW(NULL,pTempTo, NULL))
    1063                 {
    1064 /* ???      nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES); */
    1065                   SHFileStrCpyCatW(pTempFrom, NULL, wWildcardFile);
    1066                   retCode = SHFileOperationW(&nFileOp);
    1067                 }
    1068                 else
    1069                 {
    1070                   retCode = 0x750;/* value unknown */
    1071                   goto shfileop_error;
    1072                 }
    1073               }
    1074               else
    1075               {
    1076                 if (!(ask_overwrite && SHELL_ConfirmDialogW(ASK_OVERWRITE_FILE, pTempTo))
    1077                 && (not_overwrite))
    1078                 {
    1079                   /* we still need the value for the returncode, we use the mostly assumed */
    1080                   retCode = 0x73;
    1081                   goto shfileop_error;
    1082                 }
    1083                 /* TODO: use SHNotifyCopyFile() */
    1084                 if (!(CopyFileW(pTempFrom, pTempTo, FALSE)))
    1085                 {
    1086                   retCode = 0x77; /* value unknown */
    1087                   goto shfileop_error;
    1088                 }
    1089               }
    1090             } /* end-switch */
     1293            /* W98 returns 0x75, W2K 0x4c7 */
     1294            retCode = retCodeIsInvalid;
     1295            break;
     1296
    10911297          } /* end-while */
    1092         }
    1093 shfileop_normal:
    1094         if (!(nFileOp.fAnyOperationsAborted))
    1095           retCode = 0;
    1096 shfileop_error:
    1097         if (hFind != INVALID_HANDLE_VALUE)
    1098           FindClose(hFind);
    1099         hFind = INVALID_HANDLE_VALUE;
     1298
     1299shfileop_exit:
    11001300        if (pTempFrom)
    11011301          HeapFree(GetProcessHeap(), 0, pTempFrom);
    1102         if (retCode)
    1103         {
    1104           nFileOp.fAnyOperationsAborted = TRUE;
    1105         }
    1106         TRACE("%s level=%d AnyOpsAborted=%s ret=0x%x, with %s %s%s\n",
    1107               cFO_Name[0], level, nFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
     1302        TRACE("%s level=%ld AnyOpsAborted=%s ret=0x%lx, with %s %s%s\n",
     1303              cFO_Name, level, nFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
    11081304              retCode, debugstr_w(pFrom), pTo ? "-> ":"", debugstr_w(pTo));
    11091305
     1306        lpFileOp->hNameMappings         = nFileOp.hNameMappings;
    11101307        lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
    11111308        return retCode;
     
    11521349}
    11531350
    1154 
    1155 
    1156 
    1157 
Note: See TracChangeset for help on using the changeset viewer.