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

Last change on this file since 9818 was 9808, checked in by sandervl, 23 years ago

DT: updates

File size: 26.9 KB
Line 
1
2/*
3 * SHFileOperation
4 *
5 * Copyright 2000 Juergen Schmied
6 * Copyright 2002 Andriy Palamarchuk
7 * Copyright 2002 Dietrich Teickner (from Odin)
8 * Copyright 2002 Rolf Kalbermatter
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25#include "config.h"
26#include "wine/port.h"
27
28#include <string.h>
29#include <ctype.h>
30
31#include "winreg.h"
32#include "shellapi.h"
33#include "shlobj.h"
34#include "shresdef.h"
35#include "shell32_main.h"
36#include "undocshell.h"
37#include "shlwapi.h"
38#include "wine/debug.h"
39
40WINE_DEFAULT_DEBUG_CHANNEL(shell);
41
42BOOL SHELL_ConfirmDialog (int nKindOfDialog, LPCSTR szDir)
43{
44 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
45 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));
77}
78
79/**************************************************************************
80 * SHELL_DeleteDirectoryA()
81 *
82 * like rm -r
83 */
84
85BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
86{
87 BOOL ret = TRUE;
88 HANDLE hFind;
89 WIN32_FIND_DATAA wfd;
90 char szTemp[MAX_PATH];
91
92 /* Make sure the directory exists before eventually prompting the user */
93 PathCombineA(szTemp, pszDir, "*.*");
94 hFind = FindFirstFileA(szTemp, &wfd);
95 if (hFind == INVALID_HANDLE_VALUE)
96 return FALSE;
97
98 if (!bShowUI || SHELL_ConfirmDialog(ASK_DELETE_FOLDER, pszDir))
99 {
100 do
101 {
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 }
110 } while (ret && FindNextFileA(hFind, &wfd));
111 }
112 FindClose(hFind);
113 if (ret)
114 ret = RemoveDirectoryA(pszDir);
115 return ret;
116}
117
118/**************************************************************************
119 * SHELL_DeleteFileA()
120 */
121
122BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
123{
124 if (bShowUI && !SHELL_ConfirmDialog(ASK_DELETE_FILE, pszFile))
125 return FALSE;
126
127 return DeleteFileA(pszFile);
128}
129
130/**************************************************************************
131 * Win32CreateDirectory (SHELL32_93) [SHELL32.93]
132 *
133 * Creates a directory. Also triggers a change notify if one exists.
134 */
135static BOOL Win32CreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec)
136{
137 BOOL ret;
138 TRACE("(%%s, %p)\n", debugstr_a(path), sec);
139
140 ret = CreateDirectoryA(path, sec);
141 if (ret)
142 {
143 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA, path, NULL);
144 }
145 return ret;
146}
147
148static BOOL Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
149{
150 BOOL ret;
151 TRACE("(%%s, %p)\n", debugstr_w(path), sec);
152
153 ret = CreateDirectoryW(path, sec);
154 if (ret)
155 {
156 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, path, NULL);
157 }
158 return ret;
159}
160
161BOOL WINAPI Win32CreateirectoryAW(LPCVOID path, LPSECURITY_ATTRIBUTES sec)
162{
163 if (SHELL_OsIsUnicode())
164 return Win32CreateDirectoryW(path, sec);
165 return Win32CreateDirectoryA(path, sec);
166}
167
168/************************************************************************
169 * Win32RemoveDirectory (SHELL32_94) [SHELL32.94]
170 *
171 * Deletes a directory. Also triggers a change notify if one exists.
172 */
173static BOOL Win32RemoveDirectoryA(LPCSTR path)
174{
175 DWORD attr;
176 BOOL ret;
177 TRACE("(%%s)\n", debugstr_a(path));
178
179 ret = RemoveDirectoryA(path);
180 if (!ret)
181 {
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 }
188 }
189 if (ret)
190 {
191 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA, path, NULL);
192 }
193 return ret;
194}
195
196static BOOL Win32RemoveDirectoryW(LPCWSTR path)
197{
198 DWORD attr;
199 BOOL ret;
200 TRACE("(%%s)\n", debugstr_w(path));
201
202 ret = RemoveDirectoryW(path);
203 if (!ret)
204 {
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 }
211 }
212 if (ret)
213 {
214 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, path, NULL);
215 }
216 return ret;
217}
218
219BOOL WINAPI Win32RemoveDirectoryAW(LPCVOID path)
220{
221 if (SHELL_OsIsUnicode())
222 return Win32RemoveDirectoryW(path);
223 return Win32RemoveDirectoryA(path);
224}
225
226/************************************************************************
227 * Win32DeleteFile (SHELL32_164) [SHELL32.164]
228 *
229 * Deletes a file. Also triggers a change notify if one exists.
230 *
231 * NOTES:
232 * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI.
233 * This is Unicode on NT/2000
234 */
235static BOOL Win32DeleteFileA(LPCSTR path)
236{
237 BOOL ret;
238
239 TRACE("(%s)\n", debugstr_a(path));
240
241 ret = DeleteFileA(path);
242 if (!ret)
243 {
244 /* File may be write protected or a system file */
245 DWORD dwAttr = GetFileAttributesA(path);
246 if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
247 if (SetFileAttributesA(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
248 ret = DeleteFileA(path);
249 }
250 if (ret)
251 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHA, path, NULL);
252 return ret;
253}
254
255static BOOL Win32DeleteFileW(LPCWSTR path)
256{
257 BOOL ret;
258
259 TRACE("(%s)\n", debugstr_w(path));
260
261 ret = DeleteFileW(path);
262 if (!ret)
263 {
264 /* File may be write protected or a system file */
265 DWORD dwAttr = GetFileAttributesW(path);
266 if ((dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
267 if (SetFileAttributesW(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
268 ret = DeleteFileW(path);
269 }
270 if (ret)
271 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, path, NULL);
272 return ret;
273}
274
275DWORD WINAPI Win32DeleteFileAW(LPCVOID path)
276{
277 if (SHELL_OsIsUnicode())
278 return Win32DeleteFileW(path);
279 return Win32DeleteFileA(path);
280}
281
282/*************************************************************************
283 * SHCreateDirectory [SHELL32.165]
284 *
285 * NOTES
286 * exported by ordinal
287 * WinNT/2000 exports Unicode
288 */
289DWORD WINAPI SHCreateDirectory(HWND hWnd, LPCVOID path)
290{
291 if (SHELL_OsIsUnicode())
292 return SHCreateDirectoryExW(hWnd, path, NULL);
293 return SHCreateDirectoryExA(hWnd, path, NULL);
294}
295
296/*************************************************************************
297 * SHCreateDirectoryExA [SHELL32.@]
298 */
299DWORD WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec)
300{
301 WCHAR wPath[MAX_PATH];
302 TRACE("(%p, %s, %p)\n",hWnd, debugstr_a(path), sec);
303
304 MultiByteToWideChar(CP_ACP, 0, path, -1, wPath, MAX_PATH);
305 return SHCreateDirectoryExW(hWnd, wPath, sec);
306}
307
308/*************************************************************************
309 * SHCreateDirectoryExW [SHELL32.@]
310 */
311DWORD WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
312{
313 DWORD ret = ERROR_SUCCESS;
314 TRACE("(%p, %s, %p)\n",hWnd, debugstr_w(path), sec);
315
316 if (PathIsRelativeW(path))
317 {
318 ret = ERROR_BAD_PATHNAME;
319 SetLastError(ERROR_BAD_PATHNAME);
320 }
321 else
322 {
323 if (!Win32CreateDirectoryW(path, sec))
324 {
325 ret = GetLastError();
326 if (ret != ERROR_FILE_EXISTS &&
327 ret != ERROR_ALREADY_EXISTS &&
328 ret != ERROR_FILENAME_EXCED_RANGE)
329 {
330 /*lstrcpynW(pathName, path, MAX_PATH);
331 lpStr = PathAddBackslashW(pathName);*/
332 FIXME("Semi-stub, non zero hWnd should be used somehow?");
333 }
334 }
335 }
336 return ret;
337}
338
339/*************************************************************************
340 *
341 * SHFileStrICmp HelperFunction for SHFileOperationA
342 *
343 */
344BOOL 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
395/*************************************************************************
396 * SHFileOperationA [SHELL32.@]
397 *
398 * NOTES
399 * exported by name
400 */
401DWORD 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;
438
439/* default no error */
440 nlpFileOp.fAnyOperationsAborted=FALSE;
441
442 if (!(FuncSwitch) || (FO_RENAME < FuncSwitch))
443 goto shfileop_normal;
444
445 pToFuncTXT = cFO_Name [FuncSwitch-1];
446 if (level == 0)
447 TRACE("%s: flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n",pToFuncTXT, nlpFileOp.fFlags,
448 nlpFileOp.fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
449 nlpFileOp.fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
450 nlpFileOp.fFlags & FOF_SILENT ? "FOF_SILENT " : "",
451 nlpFileOp.fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
452 nlpFileOp.fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
453 nlpFileOp.fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
454 nlpFileOp.fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
455 nlpFileOp.fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
456 nlpFileOp.fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
457 nlpFileOp.fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
458 nlpFileOp.fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
459 nlpFileOp.fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
460 ;
461 {
462 /* establish when pTo is interpreted as the name of the destination file
463 * or the directory where the Fromfile should be copied to.
464 * This depends on:
465 * (1) pTo points to the name of an existing directory;
466 * (2) the flag FOF_MULTIDESTFILES is present;
467 * (3) whether pFrom point to multiple filenames.
468 *
469 * Some experiments:
470 *
471 * destisdir 1 1 1 1 0 0 0 0
472 * FOF_MULTIDESTFILES 1 1 0 0 1 1 0 0
473 * multiple from filenames 1 0 1 0 1 0 1 0
474 * ---------------
475 * copy files to dir 1 0 1 1 0 0 1 0
476 * create dir 0 0 0 0 0 0 1 0
477 */
478/*
479 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY are implemented
480 * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS are not implemented and ignored
481 * FOF_RENAMEONCOLLISION are implemented partially and breaks if file exist
482 * FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE are not implemented and breaks
483 * if any other flag set, an error occurs
484 */
485 TRACE(__FUNCTION__" %s level=%d nlpFileOp.fFlags=0x%x\n", pToFuncTXT, level, lpFileOp->fFlags);
486
487/* OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY));
488/* 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 }
519/* 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 */
582
583/* 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 }
842shfileop_normal:
843 if (!(nlpFileOp.fAnyOperationsAborted))
844 retCode = 0;
845shfileop_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 */
868DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
869{
870 FIXME("(%p):stub.\n", lpFileOp);
871 return 1;
872}
873
874/*************************************************************************
875 * SHFileOperation [SHELL32.@]
876 *
877 */
878DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
879{
880 if (SHELL_OsIsUnicode())
881 return SHFileOperationW(lpFileOp);
882 return SHFileOperationA(lpFileOp);
883}
884
885/*************************************************************************
886 * SheGetDirW [SHELL32.281]
887 *
888 */
889HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
890{ FIXME("%p %p stub\n",u,v);
891 return 0;
892}
893
894/*************************************************************************
895 * SheChangeDirW [SHELL32.274]
896 *
897 */
898HRESULT WINAPI SheChangeDirW(LPWSTR u)
899{ FIXME("(%s),stub\n",debugstr_w(u));
900 return 0;
901}
902
903/*************************************************************************
904 * IsNetDrive [SHELL32.66]
905 */
906BOOL WINAPI IsNetDrive(DWORD drive)
907{
908 char root[4];
909 strcpy(root, "A:\\");
910 root[0] += (char)drive;
911 return (GetDriveTypeA(root) == DRIVE_REMOTE);
912}
913
914
Note: See TracBrowser for help on using the repository browser.