- Timestamp:
- Jul 11, 2003, 5:38:31 PM (22 years ago)
- Location:
- trunk/src/shell32
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/shell32/shell32_main.h
r9885 r10162 179 179 #define ASK_DELETE_FOLDER 2 180 180 #define ASK_DELETE_MULTIPLE_ITEM 3 181 #ifdef __WIN32OS2__ 182 #define ASK_CREATE FOLDER 4 181 #define ASK_CREATE_FOLDER 4 183 182 #define ASK_OVERWRITE_FILE 5 184 #endif185 183 186 184 BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI); -
trunk/src/shell32/shlfileop.c
r9959 r10162 20 20 * License along with this library; if not, write to the Free Software 21 21 * 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 22 25 */ 23 26 … … 32 35 #include "shlobj.h" 33 36 #include "shresdef.h" 37 #define NO_SHLWAPI_STREAM 38 #include "shlwapi.h" 34 39 #include "shell32_main.h" 35 40 #include "undocshell.h" 36 #include " shlwapi.h"41 #include "wine/unicode.h" 37 42 #include "wine/debug.h" 38 43 39 #define IsAttribFile(x) (!(x == -1) && !(x & FILE_ATTRIBUTE_DIRECTORY)) 44 WINE_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)) 40 51 #define IsAttribDir(x) (!(x == -1) && (x & FILE_ATTRIBUTE_DIRECTORY)) 41 52 42 53 #define IsDotDir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) 43 54 44 WINE_DEFAULT_DEBUG_CHANNEL(shell); 55 #define FO_MASK 0xFF 56 #define FO_LevelShift 8 57 #define HIGH_ADR (LPWSTR)0xffffffff 45 58 46 59 CHAR aWildcardFile[] = {'*','.','*',0}; 47 WCHAR wWildcard File[] = {'*','.','*',0};48 WCHAR wWildcardChars[] = {'*','?',0}; 60 WCHAR wWildcardChars[] = {'?','*',0}; 61 #define wWildcardFile &wWildcardChars[1] 49 62 WCHAR wBackslash[] = {'\\',0}; 50 63 … … 55 68 static BOOL SHNotifyDeleteFileA(LPCSTR path); 56 69 static BOOL SHNotifyDeleteFileW(LPCWSTR path); 70 static BOOL SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest); 71 static BOOL SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bRenameIfExists); 57 72 58 73 typedef struct … … 121 136 122 137 /************************************************************************** 123 * SHELL_DeleteDirectoryA()138 * SHELL_DeleteDirectoryA() [internal] 124 139 * 125 140 * like rm -r … … 196 211 197 212 /************************************************************************** 198 * SHELL_DeleteFileA() 213 * SHELL_DeleteFileA() [internal] 199 214 */ 200 215 BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI) … … 215 230 216 231 /************************************************************************** 217 * Win32CreateDirectory (SHELL32_93)[SHELL32.93]232 * Win32CreateDirectory [SHELL32.93] 218 233 * 219 234 * 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 220 245 */ 221 246 static BOOL SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec) … … 253 278 254 279 /************************************************************************ 255 * Win32RemoveDirectory (SHELL32_94)[SHELL32.94]280 * Win32RemoveDirectory [SHELL32.94] 256 281 * 257 282 * 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 258 293 */ 259 294 static BOOL SHNotifyRemoveDirectoryA(LPCSTR path) … … 303 338 304 339 /************************************************************************ 305 * Win32DeleteFile (SHELL32_164)[SHELL32.164]340 * Win32DeleteFile [SHELL32.164] 306 341 * 307 342 * 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 308 349 * 309 350 * NOTES: … … 358 399 } 359 400 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 */ 413 static 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 */ 447 static 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 362 483 * 363 484 * NOTES 364 485 * exported by ordinal 486 * Win9x exports ANSI 365 487 * WinNT/2000 exports Unicode 366 488 */ … … 373 495 374 496 /************************************************************************* 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 376 512 */ 377 513 DWORD WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec) … … 385 521 386 522 /************************************************************************* 387 * SHCreateDirectoryExW [SHELL32.@] 523 * SHTryFind [intern] 524 * Try for existing names 525 */ 526 DWORD 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.@] 388 550 */ 389 551 DWORD WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec) 390 552 { 391 DWORD ret = ERROR_SUCCESS;553 DWORD ret = SHTryFindW(path); 392 554 TRACE("(%p, %s, %p)\n",hWnd, debugstr_w(path), sec); 393 555 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) 400 566 { 401 567 if (!SHNotifyCreateDirectoryW(path, sec)) … … 406 572 ret != ERROR_FILENAME_EXCED_RANGE) 407 573 { 408 /*lstrcpynW(pathName, path, MAX_PATH); 574 /* handling network file names? 575 lstrcpynW(pathName, path, MAX_PATH); 409 576 lpStr = PathAddBackslashW(pathName);*/ 410 577 FIXME("Semi-stub, non zero hWnd should be used somehow?"); … … 496 663 * 497 664 * 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 */ 667 BOOL 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 507 691 { 508 692 if (-1 == GetFileAttributesW(pszFiles1)) … … 510 694 } 511 695 pszFiles1 += lstrlenW(pszFiles1) + 1; 512 if (! B_OnlyFrom)696 if (!bOnlySrc) 513 697 pszFiles2 += lstrlenW(pszFiles2) + 1; 514 698 } 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. 524 710 */ 525 711 DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more) 526 712 { 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 { 533 718 do 534 719 { 535 720 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; 541 722 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 550 743 * 551 744 * NOTES 552 * 745 * exported by name 553 746 */ 554 747 DWORD WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp) 555 748 { 556 749 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__ 561 755 TRACE("SHFileOperationA"); 562 if (FO_DELETE == (nFileOp.wFunc & 0xf)) 756 #else 757 TRACE("\n"); 758 #endif 759 if (FO_DELETE == (nFileOp.wFunc & FO_MASK)) 563 760 nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */ 564 761 if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS)) 565 762 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 { 578 765 size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */ 579 766 size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */ 580 767 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 */ 790 DWORD 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 } 596 840 return retCode; 597 841 } 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 */ 851 DWORD 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 */ 618 889 DWORD WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) 619 890 { 620 SHFILEOPSTRUCTW nFileOp = *(lpFileOp);891 SHFILEOPSTRUCTW nFileOp = lpFileOp ? *(lpFileOp):nFileOp; 621 892 622 893 LPCWSTR pNextFrom = nFileOp.pFrom; … … 624 895 LPCWSTR pFrom = pNextFrom; 625 896 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 628 906 HANDLE hFind = INVALID_HANDLE_VALUE; 629 907 WIN32_FIND_DATAW wfd; … … 631 909 LPWSTR pTempTo = NULL; 632 910 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 */ 636 914 DWORD ToAttr; 637 915 DWORD ToPathAttr; 916 DWORD FromAttr; 638 917 DWORD FromPathAttr; 639 FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff); 640 918 641 919 BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES); 642 920 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; 645 923 BOOL b_MultiFrom = FALSE; 646 924 BOOL not_overwrite; 647 925 BOOL ask_overwrite; 648 926 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 */ 698 962 /* 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 703 968 * if any other flag set, an error occurs 704 969 */ 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); 725 971 726 972 if ((pNextFrom) && (!(b_MultiTo) || (pNextTo))) … … 731 977 retCode = ERROR_OUTOFMEMORY; 732 978 SetLastError(retCode); 733 goto shfileop_e rror;979 goto shfileop_exit; 734 980 } 735 981 if (b_MultiTo) … … 742 988 { 743 989 retCode = 0x402; /* 1026 */ 744 goto shfileop_e rror;990 goto shfileop_exit; 745 991 } 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; 750 996 nFileOp.fFlags = lpFileOp->fFlags; 751 997 … … 758 1004 759 1005 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 760 1013 pNextFrom = &pNextFrom[lstrlenW(pNextFrom)+1]; 761 1014 if (!b_MultiFrom && !b_MultiTo) … … 763 1016 764 1017 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))); 771 1019 772 1020 if (pTo) 773 1021 { 774 1022 pToFile = SHFileStrCpyCatW(pTempTo, pTo, NULL); 1023 b_ToMask = (NULL != StrPBrkW(pTempTo, wWildcardChars)); 775 1024 } 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 776 1040 if (!b_MultiPaired) 777 1041 { 778 1042 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)); 780 1045 } /* endif */ 781 1046 if (!(b_MultiPaired) || !(pFromFile) || !(pFromFile[1]) || ((pTo) && !(pToFile))) 782 1047 { 783 1048 retCode = 0x402; /* 1026 */ 784 goto shfileop_e rror;1049 goto shfileop_exit; 785 1050 } 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; 845 1058 do 846 1059 { 847 848 1060 lpFileName = wfd.cAlternateFileName; 1061 if (!lpFileName[0]) 849 1062 lpFileName = wfd.cFileName; 850 1063 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; 853 1066 SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL); 854 1067 /* TODO: Check the SHELL_DeleteFileOrDirectoryW() function in shell32.dll */ 855 1068 if (IsAttribFile(wfd.dwFileAttributes)) 856 1069 { 857 nFileOp.fAnyOperationsAborted = (!SHNotifyDeleteFileW(pTempFrom));858 retCode = 0x78; /* value unknown */1070 if (!SHNotifyDeleteFileW(pTempFrom)) 1071 retCode = 0x78; /* value unknown */ 859 1072 } 860 1073 else 861 1074 { 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 */ 864 1077 } 865 } while (! nFileOp.fAnyOperationsAborted&& FindNextFileW(hFind, &wfd));1078 } while (!retCode && FindNextFileW(hFind, &wfd)); 866 1079 FindClose(hFind); 867 hFind = INVALID_HANDLE_VALUE;868 if (nFileOp.fAnyOperationsAborted)869 {870 goto shfileop_error;871 }872 1080 continue; 873 1081 } /* FO_DELETE ends, pTo must be always valid from here */ 874 1082 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 } 878 1094 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)) 880 1099 { 881 1100 pToFile[0] = '\0'; … … 883 1102 pToFile[0] = '\\'; 884 1103 } 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 */ 886 1115 if (FO_RENAME == FuncSwitch) 887 1116 { 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)) 891 1120 { 892 retCode = 0x73; 893 goto shfileop_e rror;1121 retCode = 0x73; /* must be here or before, not later */ 1122 goto shfileop_exit; 894 1123 } 895 if (b_ToInvalidTail) 1124 #ifdef W98_FO_FUNCTION /* not in W2K, later in SHFileOperationMove */ 1125 if (!pToTailSlash && IsAttribDir(ToAttr)) 896 1126 { 897 retCode =0x2;898 goto shfileop_e rror;1127 retCode = ERROR_INVALID_NAME; /* FOF_NOCONFIRMATION, FOF_RENAMEONCOLLISION ? */ 1128 goto shfileop_exit; 899 1129 } 900 if (-1 == ToPathAttr) 1130 if (-1 != ToPathAttr || b_ToMask) 1131 #else 1132 if (-1 != ToPathAttr) 1133 #endif 901 1134 { 902 retCode = 0x75;903 goto shfileop_e rror;1135 retCode = SHFileOperationMove(&nFileOp); 1136 goto shfileop_exit; 904 1137 } 905 if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(ToAttr)) 1138 } 1139 else \ 1140 if (!b_FromMask) 1141 { 1142 if (IsAttribDir(ToPathAttr)) 906 1143 { 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 912 1161 { 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; 916 1276 } 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; 933 1278 pToFile = SHFileStrCpyCatW(pTempTo, NULL, wBackslash); 934 nFileOp.fFlags = (nFileOp.fFlags | FOF_MULTIDESTFILES);935 1279 do 936 1280 { 937 938 939 1281 lpFileName = wfd.cAlternateFileName; 1282 if (!lpFileName[0]) 1283 lpFileName = wfd.cFileName; 940 1284 if (IsDotDir(lpFileName) || 941 1285 (IsAttribDir(wfd.dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY))) 942 1286 continue; /* next name in pTempFrom(dir) */ 943 SHFileStrCpyCatW(&pToFile[1], lpFileName, NULL);944 1287 SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL); 945 1288 retCode = SHFileOperationW (&nFileOp); 946 } while(!nFileOp.fAnyOperationsAborted && FindNextFileW(hFind, &wfd)); 1289 } while(!retCode && FindNextFileW(hFind, &wfd)); 1290 FindClose(hFind); 1291 continue; 947 1292 } 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 1091 1297 } /* 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 1299 shfileop_exit: 1100 1300 if (pTempFrom) 1101 1301 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", 1108 1304 retCode, debugstr_w(pFrom), pTo ? "-> ":"", debugstr_w(pTo)); 1109 1305 1306 lpFileOp->hNameMappings = nFileOp.hNameMappings; 1110 1307 lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted; 1111 1308 return retCode; … … 1152 1349 } 1153 1350 1154 1155 1156 1157
Note:
See TracChangeset
for help on using the changeset viewer.