source: trunk/src/shell32/shlfileop.c@ 9807

Last change on this file since 9807 was 9805, checked in by sandervl, 23 years ago

DT: Shell file operation updates

File size: 26.8 KB
Line 
1/*
2 * SHFileOperation
3 *
4 * Copyright 2000 Juergen Schmied
5 * Copyright 2002 Andriy Palamarchuk
6 * Copyright 2002 Dietrich Teickner (from Odin)
7 * Copyright 2002 Rolf Kalbermatter
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include "config.h"
25#include "wine/port.h"
26
27#include <string.h>
28#include <ctype.h>
29
30#include "winreg.h"
31#include "shellapi.h"
32#include "shlobj.h"
33#include "shresdef.h"
34#include "shell32_main.h"
35#include "undocshell.h"
36#include "shlwapi.h"
37#include "wine/debug.h"
38
39WINE_DEFAULT_DEBUG_CHANNEL(shell);
40
41BOOL SHELL_ConfirmDialog (int nKindOfDialog, LPCSTR szDir)
42{
43 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
44 UINT caption_resource_id, text_resource_id;
45
46 switch(nKindOfDialog) {
47
48 case ASK_DELETE_FILE:
49 caption_resource_id = IDS_DELETEITEM_CAPTION;
50 text_resource_id = IDS_DELETEITEM_TEXT;
51 break;
52 case ASK_DELETE_FOLDER:
53 caption_resource_id = IDS_DELETEFOLDER_CAPTION;
54 text_resource_id = IDS_DELETEITEM_TEXT;
55 break;
56 case ASK_DELETE_MULTIPLE_ITEM:
57 caption_resource_id = IDS_DELETEITEM_CAPTION;
58 text_resource_id = IDS_DELETEMULTIPLE_TEXT;
59 break;
60 case ASK_OVERWRITE_FILE:
61 caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
62 text_resource_id = IDS_OVERWRITEFILE_TEXT;
63 break;
64 default:
65 FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
66 return FALSE;
67 }
68
69 LoadStringA(shell32_hInstance, caption_resource_id, szCaption, sizeof(szCaption));
70 LoadStringA(shell32_hInstance, text_resource_id, szText, sizeof(szText));
71
72 FormatMessageA(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
73 szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
74
75 return (IDOK == MessageBoxA(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
76}
77
78/**************************************************************************
79 * SHELL_DeleteDirectoryA()
80 *
81 * like rm -r
82 */
83BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
84{
85 BOOL ret = FALSE;
86 HANDLE hFind;
87 WIN32_FIND_DATAA wfd;
88 char szTemp[MAX_PATH];
89
90 strcpy(szTemp, pszDir);
91 PathAddBackslashA(szTemp);
92 strcat(szTemp, "*.*");
93
94 hFind = FindFirstFileA(szTemp, &wfd);
95
96 ret = (INVALID_HANDLE_VALUE != hFind);
97
98 if (ret && (!bShowUI || SHELL_ConfirmDialog(ASK_DELETE_FOLDER, pszDir)))
99 {
100 do
101 {
102 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
103 {
104 strcpy(szTemp, pszDir);
105 PathAddBackslashA(szTemp);
106 strcat(szTemp, wfd.cFileName);
107
108 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
109 SHELL_DeleteDirectoryA(szTemp, FALSE);
110 else
111 DeleteFileA(szTemp);
112 }
113 } while(FindNextFileA(hFind, &wfd));
114 FindClose(hFind);
115 ret = RemoveDirectoryA(pszDir);
116 }
117 return ret;
118}
119
120/**************************************************************************
121 * SHELL_DeleteFileA()
122 */
123
124BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
125{
126 if (bShowUI && !SHELL_ConfirmDialog(ASK_DELETE_FILE, pszFile))
127 return FALSE;
128 return DeleteFileA(pszFile);
129}
130
131/*************************************************************************
132 * SHCreateDirectory [SHELL32.165]
133 *
134 * NOTES
135 * exported by ordinal
136 * WinNT/2000 exports Unicode
137 */
138DWORD WINAPI SHCreateDirectory(HWND hWnd, LPCVOID path)
139{
140 if (SHELL_OsIsUnicode())
141 return SHCreateDirectoryExW(hWnd, path, NULL);
142 return SHCreateDirectoryExA(hWnd, path, NULL);
143}
144
145/*************************************************************************
146 * SHCreateDirectoryExA [SHELL32.@]
147 */
148DWORD WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec)
149{
150 DWORD ret;
151 TRACE("(%p, %s, %p)\n",hWnd, path, sec);
152 ret = CreateDirectoryA(path, sec);
153 if (ret)
154 {
155 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA, path, NULL);
156 }
157 else if (hWnd)
158 FIXME("Semi-stub, non zero hWnd should be used as parent for error dialog!");
159 return ret;
160}
161
162/*************************************************************************
163 * SHCreateDirectoryExW [SHELL32.@]
164 */
165DWORD WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
166{
167 DWORD ret;
168 TRACE("(%p, %s, %p)\n",hWnd, debugstr_w(path), sec);
169 ret = CreateDirectoryW(path, sec);
170 if (ret)
171 {
172 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, path, NULL);
173 }
174 else if (hWnd)
175 FIXME("Semi-stub, non zero hWnd should be used as parent for error dialog!");
176 return ret;
177}
178
179/************************************************************************
180 * Win32DeleteFile [SHELL32.164]
181 *
182 * Deletes a file. Also triggers a change notify if one exists.
183 *
184 * NOTES:
185 * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI.
186 * This is Unicode on NT/2000
187 */
188static BOOL Win32DeleteFileA(LPCSTR fName)
189{
190 DWORD ret;
191 TRACE("%p(%s)\n", fName, fName);
192
193 if (!(ret = DeleteFileA(fName)))
194 {
195 /* File may be write protected or a system file */
196 DWORD dwAttr = GetFileAttributesA(fName);
197 if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
198 if (SetFileAttributesA(fName, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
199 ret = DeleteFileA(fName);
200 }
201 if (ret)
202 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
203 return ret;
204}
205
206static BOOL Win32DeleteFileW(LPCWSTR fName)
207{
208 BOOL ret;
209 TRACE("%p(%s)\n", fName, debugstr_w(fName));
210
211 if (!(ret = DeleteFileW(fName)))
212 {
213 /* File may be write protected or a system file */
214 DWORD dwAttr = GetFileAttributesW(fName);
215 if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
216 if (SetFileAttributesW(fName, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
217 ret = DeleteFileW(fName);
218 }
219 if (ret)
220 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, fName, NULL);
221 return ret;
222}
223
224BOOL WINAPI Win32DeleteFileAW(LPCVOID fName)
225{
226 if (SHELL_OsIsUnicode())
227 return Win32DeleteFileW(fName);
228 return Win32DeleteFileA(fName);
229}
230
231/*************************************************************************
232 *
233 * SHFileStrCpyCat HelperFunction for SHFileOperationA
234 *
235 */
236LPSTR SHFileStrCpyCatA(LPSTR pTo, LPCSTR pFrom, LPCSTR pCatStr)
237{
238 LPSTR pToFile = NULL;
239 int i_len;
240
241 if (pTo)
242 {
243 if (pFrom)
244 lstrcpyA(pTo, pFrom);
245 if (pCatStr) /* lstrcatA(pTo, pCatStr); ?? */
246 {
247 i_len = lstrlenA(pTo);
248 if ((i_len) && (pCatStr[0] == '\\') && (pTo[--i_len] == '\\'))
249 pTo[i_len] = '\0';
250 lstrcatA(pTo, pCatStr);
251 }
252 pToFile = strrchr(pTo,'\\');
253/* !! termination of the new string-group */
254 pTo[(lstrlenA(pTo)) + 1] = '\0';
255 }
256 return pToFile;
257}
258
259/*************************************************************************
260 *
261 * SHFileStrICmp HelperFunction for SHFileOperationA
262 *
263 */
264BOOL SHFileStrICmpA(LPSTR p1,LPSTR p2, LPSTR p1End, LPSTR p2End)
265{
266 CHAR C1 = '\0';
267 CHAR C2 = '\0';
268 int i_Temp = -1;
269 int i_len1 = lstrlenA(p1);
270 int i_len2 = lstrlenA(p2);
271
272 if (p1End && (&p1[i_len1] >= p1End) && ('\\' == p1End[0]))
273 {
274 C1 = p1End[0];
275 p1End[0] = '\0';
276 i_len1 = lstrlenA(p1);
277 }
278 if (p2End)
279 {
280 if ((&p2[i_len2] >= p2End) && ('\\' == p2End[0]))
281 {
282 C2 = p2End[0];
283 if (C2)
284 p2End[0] = '\0';
285 }
286 }
287 else
288 {
289 if ((i_len1 <= i_len2) && ('\\' == p2[i_len1]))
290 {
291 C2 = p2[i_len1];
292 if (C2)
293 p2[i_len1] = '\0';
294 }
295 }
296 i_len2 = lstrlenA(p2);
297 if (i_len1 == i_len2)
298 i_Temp = lstrcmpiA(p1,p2);
299 if (C1)
300 p1[i_len1] = C1;
301 if (C2)
302 p2[i_len2] = C2;
303 return !(i_Temp);
304}
305
306#define IsAttribFile(x) (!(x == -1) && !(x & FILE_ATTRIBUTE_DIRECTORY))
307#define IsAttribDir(x) (!(x == -1) && (x & FILE_ATTRIBUTE_DIRECTORY))
308#define TextFromPtr(x) (x ? x:"NULL")
309/*************************************************************************
310 * SHFileOperationA [SHELL32.@]
311 *
312 * NOTES
313 * exported by name
314 */
315DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
316{
317 SHFILEOPSTRUCTA nlpFileOp = *(lpFileOp);
318
319 LPCSTR pNextFrom = nlpFileOp.pFrom;
320 LPCSTR pNextTo = nlpFileOp.pTo;
321 LPCSTR pFrom = pNextFrom;
322 LPCSTR pTo = NULL;
323 HANDLE hFind = INVALID_HANDLE_VALUE;
324 WIN32_FIND_DATAA wfd;
325 LPSTR pTempFrom = NULL;
326 LPSTR pTempTo = NULL;
327 LPSTR pFromFile;
328 LPSTR pToFile;
329 long retCode = 0;
330 DWORD ToAttr;
331 DWORD ToPathAttr;
332 FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
333
334 BOOL b_Multi = (nlpFileOp.fFlags & FOF_MULTIDESTFILES);
335
336 BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & 0xf));
337 BOOL b_MultiFrom = FALSE;
338 BOOL not_overwrite;
339 BOOL ask_overwrite;
340 BOOL b_SameRoot;
341 BOOL b_SameTailName;
342 BOOL b_ToInvalidTail;
343 BOOL b_ToValid; /* for W98-Bug for FO_MOVE with source and taget in same rootdrive */
344 BOOL b_Mask; /* wird als Schalter benutzt, vieleicht finde ich die richtige bitposition */
345 BOOL b_ToTailSlash;
346 LPSTR pToFuncTXT;
347
348 long FuncSwitch = (nlpFileOp.wFunc & 0xf);
349 long level= nlpFileOp.wFunc>>4;
350
351/* default no error */
352 nlpFileOp.fAnyOperationsAborted=FALSE;
353
354 switch(FuncSwitch)
355 {
356 case FO_MOVE:
357 pToFuncTXT = "FO_MOVE";break;
358 case FO_COPY:
359 pToFuncTXT = "FO_COPY";break;
360 case FO_DELETE:
361 pToFuncTXT = "FO_DELETE";break;
362 case FO_RENAME:
363 pToFuncTXT = "FO_RENAME";break;
364 default:
365 pToFuncTXT = "FO_????";
366 goto shfileop_normal;
367 }
368
369 if (level == 0)
370 TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n",pToFuncTXT, nlpFileOp.fFlags,
371 nlpFileOp.fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
372 nlpFileOp.fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
373 nlpFileOp.fFlags & FOF_SILENT ? "FOF_SILENT " : "",
374 nlpFileOp.fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
375 nlpFileOp.fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
376 nlpFileOp.fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
377 nlpFileOp.fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
378 nlpFileOp.fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
379 nlpFileOp.fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
380 nlpFileOp.fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
381 nlpFileOp.fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
382 nlpFileOp.fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
383 ;
384 {
385 /* establish when pTo is interpreted as the name of the destination file
386 * or the directory where the Fromfile should be copied to.
387 * This depends on:
388 * (1) pTo points to the name of an existing directory;
389 * (2) the flag FOF_MULTIDESTFILES is present;
390 * (3) whether pFrom point to multiple filenames.
391 *
392 * Some experiments:
393 *
394 * destisdir 1 1 1 1 0 0 0 0
395 * FOF_MULTIDESTFILES 1 1 0 0 1 1 0 0
396 * multiple from filenames 1 0 1 0 1 0 1 0
397 * ---------------
398 * copy files to dir 1 0 1 1 0 0 1 0
399 * create dir 0 0 0 0 0 0 1 0
400 */
401/*
402 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY are implemented
403 * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS are not implemented and ignored
404 * FOF_RENAMEONCOLLISION are implemented partially and breaks if file exist
405 * FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE are not implemented and breaks
406 * if any other flag set, an error occurs
407 */
408 TRACE(__FUNCTION__" %s level=%d nlpFileOp.fFlags=0x%x\n", pToFuncTXT, level, lpFileOp->fFlags);
409
410/* OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY));
411/* OFl ^= (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR); */
412 OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY)); /* implemented */
413 OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR); /* ignored, if one */
414 OFl &= (~FOF_SIMPLEPROGRESS); /* ignored, only wit FOF_SILEN */
415 if (OFl)
416 {
417 if (OFl & ( ~ (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR)))
418 {
419 TRACE("%s level=%d lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", pToFuncTXT, level, OFl);
420 retCode = 0x403; /* we need a extension of shlfileop */
421 nlpFileOp.fAnyOperationsAborted=TRUE;
422 }
423 else
424 {
425 TRACE("%s level=%d lpFileOp->fFlags=0x%x not full implemented ,stub\n", pToFuncTXT, level, OFl);
426 } /* endif */
427 } /* endif */
428
429 if ((pNextFrom) && (!(b_MultiTo) || (pNextTo)))
430 {
431 nlpFileOp.pFrom = pTempFrom = HeapAlloc(GetProcessHeap(), 0, (1+2*(b_MultiTo)) * MAX_PATH+6);
432 if (b_MultiTo) pTempTo = &pTempFrom[MAX_PATH+4];
433 nlpFileOp.pTo = pTempTo;
434 ask_overwrite = (!(nlpFileOp.fFlags & FOF_NOCONFIRMATION) && !(nlpFileOp.fFlags & FOF_RENAMEONCOLLISION));
435 not_overwrite = (!(nlpFileOp.fFlags & FOF_NOCONFIRMATION) || (nlpFileOp.fFlags & FOF_RENAMEONCOLLISION));
436 }
437 else
438 {
439 nlpFileOp.fAnyOperationsAborted=TRUE;
440 retCode = 0x402;
441 goto shfileop_error;
442 }
443/* need break at error before change sourcepointer */
444 while(!nlpFileOp.fAnyOperationsAborted && (pNextFrom[0]))
445 {
446 nlpFileOp.wFunc = ((level+1)<<4) + FuncSwitch;
447 nlpFileOp.fFlags = lpFileOp->fFlags;
448
449 if (b_MultiTo)
450 {
451 pTo = pNextTo;
452 pNextTo = &pNextTo[lstrlenA(pTo)+1];
453 b_MultiTo = (b_Multi && pNextTo[0]);
454 }
455
456 pFrom = pNextFrom;
457 pNextFrom = &pNextFrom[lstrlenA(pNextFrom)+1];
458 if (!b_MultiFrom && !b_MultiTo)
459 b_MultiFrom = (pNextFrom[0]);
460
461 pFromFile = SHFileStrCpyCatA(pTempFrom, pFrom, NULL);
462
463 if (pTo)
464 {
465 pToFile = SHFileStrCpyCatA(pTempTo, pTo, NULL);
466 if (!(pToFile))
467 {
468 nlpFileOp.fAnyOperationsAborted=TRUE;
469 retCode = 0x402;
470 goto shfileop_error;
471 } /* endif */
472 b_ToTailSlash = (!pToFile[1]);
473 if (b_ToTailSlash)
474 {
475 pToFile[0] = '\0';
476 if (strchr(pTempTo,'\\'))
477 {
478 pToFile = SHFileStrCpyCatA(pTempTo, NULL, NULL);
479 }
480 }
481 b_ToInvalidTail = (NULL != strpbrk(&pToFile[1],"*?"));
482 }
483
484 if (FO_RENAME == FuncSwitch)
485 {
486/* tempor„r only for FO_RENAME */
487 b_Mask = (NULL != strpbrk(pFrom,"*?"));
488 if (b_MultiTo || (pNextFrom[0]) || (b_Mask && !b_ToInvalidTail))
489 {
490/* no work, only RC=0 */
491// /* ???? */ nlpFileOp.fAnyOperationsAborted=TRUE;
492 goto shfileop_normal;
493 }
494 }
495
496 hFind = (!(pFromFile) || !(pFromFile[1])) ? INVALID_HANDLE_VALUE : FindFirstFileA(pFrom, &wfd);
497 if (INVALID_HANDLE_VALUE == hFind)
498 {
499/* root (without mask) is also not allowed as source, tested in W98 */
500 nlpFileOp.fAnyOperationsAborted=TRUE;
501 retCode = 0x402;
502 goto shfileop_error;
503 } /* endif */
504
505/* for all */
506#define HIGH_ADR (LPSTR)0xffffffff
507 b_Mask = (!SHFileStrICmpA(&pFromFile[1], &wfd.cFileName[0], HIGH_ADR, HIGH_ADR));
508
509 if (!pTo) /* FO_DELETE */
510 {
511 do
512 {
513 if (wfd.cFileName[0] == '.')
514 {
515 if (wfd.cFileName[1] == '\0')
516 continue;
517 if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0')
518 continue;
519 }
520 SHFileStrCpyCatA(&pFromFile[1], &wfd.cFileName[0], NULL);
521 if (IsAttribFile(wfd.dwFileAttributes))
522 {
523 nlpFileOp.fAnyOperationsAborted = (!Win32DeleteFileA(pTempFrom));
524 retCode = 0x78; /* value unknown */
525 }
526 else
527 {
528 nlpFileOp.fAnyOperationsAborted = (!SHELL_DeleteDirectoryA(pTempFrom,FALSE));
529 retCode = 0x78; /* value unknown */
530 }
531 } while(!nlpFileOp.fAnyOperationsAborted && FindNextFileA(hFind, &wfd));
532 FindClose(hFind);
533 hFind = INVALID_HANDLE_VALUE;
534 if (nlpFileOp.fAnyOperationsAborted)
535 {
536 goto shfileop_error;
537 }
538 continue;
539 } /* FO_DELETE ends, pTo must be every valid from here */
540
541 b_SameRoot = (toupper(pTempFrom[0]) == toupper(pTempTo[0]));
542 b_SameTailName = SHFileStrICmpA(pToFile, pFromFile, NULL, NULL);
543
544 /* W98 Bug with FO_MOVE(/RENAME ?) different to FO_COPY, better the same as FO_COPY */
545
546 b_ToValid = ((b_SameTailName && b_SameRoot && (FO_COPY == FuncSwitch)) ||
547 (b_SameTailName && !b_SameRoot) || (b_ToInvalidTail));
548
549 ToPathAttr = ToAttr = GetFileAttributesA(pTempTo);
550 if (!b_Mask && /* IsAttribDir(wfd.dwFileAttributes) && */(ToAttr -1))
551 {
552 if (pToFile)
553 {
554 pToFile[0] = '\0';
555 ToPathAttr = GetFileAttributesA(pTempTo);
556 /* if (-1 != ToPathAttr) */ pToFile[0] = '\\';
557 }
558 }
559 if (FO_RENAME == FuncSwitch)
560 {
561 if (!b_SameRoot || b_Mask /* FO_RENAME works not with Mask */
562 || !SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, NULL)
563 || (SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, HIGH_ADR) && !b_ToTailSlash))
564 {
565 retCode = 0x73;
566 nlpFileOp.fAnyOperationsAborted=TRUE;
567 goto shfileop_error;
568 }
569 if (b_ToInvalidTail)
570 {
571 nlpFileOp.fAnyOperationsAborted=TRUE;
572 retCode=0x2;
573 goto shfileop_error;
574 }
575 if (IsAttribDir(wfd.dwFileAttributes) && IsAttribDir(ToAttr))
576 {
577 if (b_ToTailSlash)
578 {
579 retCode = 0xb7;
580 }
581 else
582 {
583 retCode = 0x7b;
584 }
585 nlpFileOp.fAnyOperationsAborted=TRUE;
586 goto shfileop_error;
587 }
588 if (-1 == ToPathAttr)
589 {
590 nlpFileOp.fAnyOperationsAborted=TRUE;
591 retCode = 0x75;
592 goto shfileop_error;
593 } /* endif */
594 if (!MoveFileA(pTempFrom, pTempTo))
595 {
596 nlpFileOp.fAnyOperationsAborted=TRUE;
597/* we need still the value for the returncode, we use the mostly assumed */
598 retCode = 0xb7;
599 goto shfileop_error;
600 }
601 goto shfileop_normal;
602 }
603
604 if (!b_Mask && IsAttribDir(wfd.dwFileAttributes) && (ToAttr -1))
605 {
606 if (pToFile)
607 {
608 pToFile[0] = '\0';
609 ToPathAttr = GetFileAttributesA(pTempTo);
610 if ((ToPathAttr == -1) && b_ToValid)
611 {
612/* create dir k”nnte hier erfolgen, smple target D:\y\ *.* create with RC=10003 */
613 if(!SHCreateDirectory(NULL,pTempTo))
614 {
615 nlpFileOp.fAnyOperationsAborted=TRUE;
616 retCode = 0x73;/* value unknown */
617 goto shfileop_error;
618 }
619 ToPathAttr = GetFileAttributesA(pTempTo);
620 }
621 pToFile[0] = '\\';
622 if (b_ToInvalidTail)
623 {
624 nlpFileOp.fAnyOperationsAborted=TRUE;
625 retCode=0x10003;
626 goto shfileop_error;
627 }
628 }
629 }
630
631/* handle mask in source */
632 if (b_Mask)
633 {
634 if (!IsAttribDir(ToAttr))
635 {
636 nlpFileOp.fAnyOperationsAborted=TRUE;
637 if (b_ToInvalidTail && b_SameTailName && (FO_MOVE == FuncSwitch))
638 {
639 retCode = 0x2;
640 }
641 else
642 {
643 retCode = 0x75;
644 }
645 goto shfileop_error;
646 }
647 pToFile = SHFileStrCpyCatA(pTempTo,NULL, "\\");
648 nlpFileOp.fFlags = (nlpFileOp.fFlags | FOF_MULTIDESTFILES);
649 do
650 {
651 if (wfd.cFileName[0] == '.')
652 {
653 if (wfd.cFileName[1] == '\0')
654 continue;
655 if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0') continue;
656 }
657 if (IsAttribDir(wfd.dwFileAttributes) && (nlpFileOp.fFlags & FOF_FILESONLY))
658 {
659 continue; /* next name in pTempFrom(dir) */
660 }
661 SHFileStrCpyCatA(&pToFile[1], &wfd.cFileName[0], NULL);
662 SHFileStrCpyCatA(&pFromFile[1], &wfd.cFileName[0], NULL);
663 retCode = SHFileOperationA (&nlpFileOp);
664 } while(!nlpFileOp.fAnyOperationsAborted && FindNextFileA(hFind, &wfd));
665 }
666 FindClose(hFind);
667 hFind = INVALID_HANDLE_VALUE;
668 /* only FO_COPY/FO_MOVE without mask, FO_DELETE and FO_RENAME are solved */
669 if (b_Mask)
670 continue;
671
672/* tailling BackSlash is ever removed and pToFile points to BackSlash before */
673 if (!b_MultiTo && (b_MultiFrom || (!(b_Multi) && IsAttribDir(ToAttr))))
674 {
675 if ((FO_MOVE == FuncSwitch) && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
676 {
677 if (b_Multi)
678 {
679 retCode = 0x73; /* !b_Multi = 0x8 ?? */
680 nlpFileOp.fAnyOperationsAborted=TRUE;
681 goto shfileop_error;
682 }
683 }
684 pToFile = SHFileStrCpyCatA(&pTempTo[strlen(pTempTo)], "\\", wfd.cFileName);
685 ToAttr = GetFileAttributesA(pTempTo);
686 }
687
688 if (IsAttribDir(ToAttr))
689 {
690 if (IsAttribFile(wfd.dwFileAttributes))
691 {
692 if (FO_COPY == FuncSwitch)
693 {
694/* ????? */ retCode = 0x75;
695 }
696 else
697 {
698 retCode = 0xb7;
699 }
700 nlpFileOp.fAnyOperationsAborted=TRUE;
701 goto shfileop_error;
702 }
703 }
704 else
705 {
706 pToFile[0] = '\0';
707 ToPathAttr = GetFileAttributesA(pTempTo);
708 pToFile[0] = '\\';
709 if (IsAttribFile(ToPathAttr))
710 {
711/* fehler, ist das schon getestet ? */
712 nlpFileOp.fAnyOperationsAborted=TRUE;
713 retCode = 0x777402;
714 goto shfileop_error;
715 } /* endif */
716 }
717
718/* singlesource + no mask */
719 if (-1 == (ToAttr & ToPathAttr))
720 {
721/* Target-dir does not exist, and can not created */
722 nlpFileOp.fAnyOperationsAborted=TRUE;
723 retCode=0x75;
724 goto shfileop_error;
725 }
726
727 switch(FuncSwitch)
728 {
729 case FO_MOVE:
730 if ((ToAttr == -1) && SHFileStrICmpA(pTempFrom, pTempTo, pFromFile, NULL))
731 {
732 nlpFileOp.wFunc = ((level+1)<<4) + FO_RENAME;
733 retCode = SHFileOperationA(&nlpFileOp);
734 }
735 else
736 {
737 if (b_SameRoot && IsAttribDir(ToAttr) && IsAttribDir(wfd.dwFileAttributes))
738 {
739 pToFile = SHFileStrCpyCatA(pTempFrom, NULL, "\\*.*");
740 retCode = SHFileOperationA(&nlpFileOp);
741 ((WORD*)pToFile)[0] = '\0';
742 }
743 else
744 {
745 nlpFileOp.wFunc = ((level+1)<<4) + FO_COPY;
746 retCode = SHFileOperationA(&nlpFileOp);
747 } /* endif */
748 if (!nlpFileOp.fAnyOperationsAborted)
749 {
750 nlpFileOp.wFunc = ((level+1)<<4) + FO_DELETE;
751 retCode = SHFileOperationA(&nlpFileOp);
752 } /* endif */
753 }
754 continue;
755 case FO_COPY:
756 if (SHFileStrICmpA(pTempFrom, pTempTo, NULL, NULL))
757 { /* target is the same as source ? */
758 nlpFileOp.fAnyOperationsAborted=TRUE;
759/* we need still the value for the returncode, we assume 0x71 */
760 retCode = 0x71;
761 goto shfileop_error;
762 } /* endif */
763 if (IsAttribDir((ToAttr & wfd.dwFileAttributes)))
764 {
765 if (IsAttribDir(ToAttr) || SHCreateDirectory(NULL,pTempTo))
766 {
767/* ??? nlpFileOp.fFlags = (nlpFileOp.fFlags | FOF_MULTIDESTFILES); */
768 SHFileStrCpyCatA(pTempFrom, NULL, "\\*.*");
769 retCode = SHFileOperationA(&nlpFileOp);
770 }
771 else
772 {
773 nlpFileOp.fAnyOperationsAborted=TRUE;
774 retCode = 0x750;/* value unknown */
775 }
776 }
777 else
778 {
779 if (!(ask_overwrite && SHELL_ConfirmDialog (ASK_OVERWRITE_FILE, pTempTo))
780 && (not_overwrite))
781 {
782 nlpFileOp.fAnyOperationsAborted=TRUE;
783 /* we need still the value for the returncode, we use the mostly assumed */
784 retCode = 0x73;
785 goto shfileop_error;
786 }
787 if (!(CopyFileA(pTempFrom, pTempTo, FALSE)))
788 {
789 nlpFileOp.fAnyOperationsAborted=TRUE;
790 retCode = 0x77; /* value unknown */
791 }
792 }
793 } /* end-switch */
794 } /* end-while */
795 }
796shfileop_normal:
797 if (!(nlpFileOp.fAnyOperationsAborted))
798 retCode = 0;
799shfileop_error:
800 if (hFind != INVALID_HANDLE_VALUE)
801 FindClose(hFind);
802 hFind = INVALID_HANDLE_VALUE;
803 if (pTempFrom)
804 HeapFree(GetProcessHeap(), 0, pTempFrom);
805
806 TRACE("%s level=%d AnyOpsAborted=%s ret=0x%x, with %s%s%s\n",
807 pToFuncTXT, level, nlpFileOp.fAnyOperationsAborted ? "TRUE":"FALSE",
808 retCode, debugstr_a(pFrom), pTo ? " -> ":"", debugstr_a(pTo));
809
810 lpFileOp->fAnyOperationsAborted = nlpFileOp.fAnyOperationsAborted;
811 return retCode;
812}
813
814/*************************************************************************
815 * SHFileOperationW [SHELL32.@]
816 *
817 * NOTES
818 * exported by name
819 */
820DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
821{
822 FIXME("(%p):stub.\n", lpFileOp);
823 return 1;
824}
825
826/*************************************************************************
827 * SHFileOperation [SHELL32.@]
828 *
829 */
830DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
831{
832 if (SHELL_OsIsUnicode())
833 return SHFileOperationW(lpFileOp);
834 return SHFileOperationA(lpFileOp);
835}
836
837/*************************************************************************
838 * SheGetDirW [SHELL32.281]
839 *
840 */
841HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
842{ FIXME("%p %p stub\n",u,v);
843 return 0;
844}
845
846/*************************************************************************
847 * SheChangeDir [SHELL32.@]
848 *
849 */
850HRESULT WINAPI SheChangeDirW(LPWSTR path)
851{ FIXME("(%s),stub\n",debugstr_w(path));
852 return 0;
853}
854
855HRESULT WINAPI SheChangeDirA(LPSTR path)
856{
857 WCHAR wPath[MAX_PATH];
858
859 TRACE("(%s)\n", path);
860
861 if (!path)
862 return 0;
863 MultiByteToWideChar(CP_ACP, 0, path, -1, wPath, MAX_PATH);
864 return SheChangeDirW(wPath);
865}
866/*************************************************************************
867 * SheChangeDirEx [SHELL32.@]
868 *
869 */
870HRESULT WINAPI SheChangeDirExW(LPWSTR path)
871{ FIXME("(%s),stub\n",debugstr_w(path));
872 return 0;
873}
874
875HRESULT WINAPI SheChangeDirExA(LPSTR path)
876{
877 WCHAR wPath[MAX_PATH];
878
879 TRACE("(%s)\n", path);
880
881 if (!path)
882 return 0;
883 MultiByteToWideChar(CP_ACP, 0, path, -1, wPath, MAX_PATH);
884 return SheChangeDirExW(wPath);
885}
886
887/*************************************************************************
888 * IsNetDrive [SHELL32.66]
889 */
890BOOL WINAPI IsNetDrive(DWORD drive)
891{
892 char root[4];
893 strcpy(root, "A:\\");
894 root[0] += (char)drive;
895 return (GetDriveTypeA(root) == DRIVE_REMOTE);
896}
Note: See TracBrowser for help on using the repository browser.