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