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

Last change on this file since 9462 was 9424, checked in by sandervl, 23 years ago

DT: minor updates

File size: 33.5 KB
Line 
1/*
2 * SHFileOperation
3 *
4 * Copyright 2000 Juergen Schmied
5 * Copyright 2002 Andriy Palamarchuk
6 * Copyright 2002 Dietrich Teickner (from Odin)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <string.h>
23#include "winreg.h"
24#include "shellapi.h"
25#include "shlobj.h"
26#include "shresdef.h"
27#include "shell32_main.h"
28#include "undocshell.h"
29#include "shlwapi.h"
30#include "wine/debug.h"
31
32WINE_DEFAULT_DEBUG_CHANNEL(shell);
33
34#ifdef __WIN32OS2__
35BOOL SHELL_ConfirmDialog (int nKindOfDialog, LPCSTR szDir)
36{
37 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
38 UINT caption_resource_id, text_resource_id;
39
40 switch(nKindOfDialog) {
41
42 case ASK_DELETE_FILE:
43 caption_resource_id = IDS_DELETEITEM_CAPTION;
44 text_resource_id = IDS_DELETEITEM_TEXT;
45 break;
46 case ASK_DELETE_FOLDER:
47 caption_resource_id = IDS_DELETEFOLDER_CAPTION;
48 text_resource_id = IDS_DELETEITEM_TEXT;
49 break;
50 case ASK_DELETE_MULTIPLE_ITEM:
51 caption_resource_id = IDS_DELETEITEM_CAPTION;
52 text_resource_id = IDS_DELETEMULTIPLE_TEXT;
53 break;
54 case ASK_OVERWRITE_FILE:
55 caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
56 text_resource_id = IDS_OVERWRITEFILE_TEXT;
57 break;
58 default:
59 FIXME(__FUNCTION__" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
60 return FALSE;
61 }
62
63 LoadStringA(shell32_hInstance, caption_resource_id, szCaption, sizeof(szCaption));
64 LoadStringA(shell32_hInstance, text_resource_id, szText, sizeof(szText));
65#else
66BOOL SHELL_WarnItemDelete (int nKindOfDialog, LPCSTR szDir)
67{
68 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
69
70 if(nKindOfDialog == ASK_DELETE_FILE)
71 {
72 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
73 sizeof(szText));
74 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
75 szCaption, sizeof(szCaption));
76 }
77 else if(nKindOfDialog == ASK_DELETE_FOLDER)
78 {
79 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
80 sizeof(szText));
81 LoadStringA(shell32_hInstance, IDS_DELETEFOLDER_CAPTION,
82 szCaption, sizeof(szCaption));
83 }
84 else if(nKindOfDialog == ASK_DELETE_MULTIPLE_ITEM)
85 {
86 LoadStringA(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, szText,
87 sizeof(szText));
88 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
89 szCaption, sizeof(szCaption));
90 }
91 else {
92 FIXME("Called without a valid nKindOfDialog specified!\n");
93 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
94 sizeof(szText));
95 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
96 szCaption, sizeof(szCaption));
97 }
98#endif
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/**************************************************************************
106 * SHELL_DeleteDirectoryA()
107 *
108 * like rm -r
109 */
110
111BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
112{
113 BOOL ret = FALSE;
114 HANDLE hFind;
115 WIN32_FIND_DATAA wfd;
116 char szTemp[MAX_PATH];
117
118 strcpy(szTemp, pszDir);
119 PathAddBackslashA(szTemp);
120 strcat(szTemp, "*.*");
121
122 if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FOLDER, pszDir))
123 return FALSE;
124
125 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(szTemp, &wfd)))
126 {
127 do
128 {
129 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
130 {
131 strcpy(szTemp, pszDir);
132 PathAddBackslashA(szTemp);
133 strcat(szTemp, wfd.cFileName);
134
135 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
136 SHELL_DeleteDirectoryA(szTemp, FALSE);
137 else
138 DeleteFileA(szTemp);
139 }
140 } while(FindNextFileA(hFind, &wfd));
141
142 FindClose(hFind);
143 ret = RemoveDirectoryA(pszDir);
144 }
145
146 return ret;
147}
148
149/**************************************************************************
150 * SHELL_DeleteFileA()
151 */
152
153BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
154{
155 if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FILE, pszFile))
156 return FALSE;
157
158 return DeleteFileA(pszFile);
159}
160
161/*************************************************************************
162 * SHCreateDirectory [SHELL32.165]
163 *
164 * NOTES
165 * exported by ordinal
166 * not sure about LPSECURITY_ATTRIBUTES
167 */
168DWORD WINAPI SHCreateDirectory(LPSECURITY_ATTRIBUTES sec,LPCSTR path)
169{
170 DWORD ret;
171 TRACE("(%p,%s)\n",sec,path);
172 if ((ret = CreateDirectoryA(path,sec)))
173 {
174 SHChangeNotifyA(SHCNE_MKDIR, SHCNF_PATHA, path, NULL);
175 }
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 * FIXME:
185 * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be
186 * ANSI. Is this Unicode on NT?
187 *
188 */
189
190BOOL WINAPI Win32DeleteFile(LPSTR fName)
191{
192 TRACE("%p(%s)\n", fName, fName);
193
194 DeleteFileA(fName);
195 SHChangeNotifyA(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
196 return TRUE;
197}
198
199#ifdef __WIN32OS2__
200/*************************************************************************
201 *
202 * SHFileTyp (internal)
203 *
204 */
205DWORD SHFileTyp(LPSTR pFromTo, long *len, LPSTR pTemp, long *lenTemp, LPSTR *pFile, DWORD *PathAttr, DWORD *Attr) {
206#define TypisBad -1
207#define TypisUnkn 0
208#define TypisNewPath 1
209#define TypisRoot 2
210#define TypisDirS 3
211#define TypisDir 4
212#define TypisFile 5
213#define TypisName 6
214#define TypisNameS 7
215#define TypisMask 8
216 DWORD Typ = TypisUnkn;
217 DWORD i_Attr;
218 DWORD i_PathAttr;
219 BOOL i_Slash = FALSE;
220 LPSTR i_pFile;
221 LPSTR i_pLastSlash;
222 long i_lenTemp;
223 long i_len = *len = strlen(pFromTo);
224 if (i_len == 0) return TypisUnkn;
225 strcpy(pTemp,pFromTo);
226 *pFile = i_pFile = &pTemp[i_len];
227 pTemp[i_len+1] = '\0';
228 if (i_len == 0) return /* ?? */ TypisBad;
229 if (PathIsRootA(pFromTo)) Typ = TypisRoot;
230 i_pLastSlash = strrchr(pTemp,'\\');
231 if (i_pLastSlash == NULL) return TypisBad /* ??? */;
232 i_Slash = (i_pLastSlash[1] == '\0');
233 *lenTemp = i_lenTemp = strlen(pTemp) - i_Slash;
234 *pFile = i_pFile = &pTemp[i_lenTemp];
235 if (Typ != TypisRoot) i_pFile[0] = '\0';
236 *PathAttr = *Attr = i_PathAttr = i_Attr = GetFileAttributesA(pTemp);
237 if (i_Attr == -1) {
238 if (Typ == TypisRoot) Typ = TypisBad;
239 } else {
240 if (i_Attr & FILE_ATTRIBUTE_DIRECTORY) {
241 if (Typ == TypisUnkn) {
242 Typ = TypisDir;
243 if (i_Slash) Typ = TypisDirS;
244 }
245 } else {
246 if (Typ == TypisUnkn && !i_Slash) {
247 Typ = TypisFile;
248 } else Typ = TypisBad;
249 }
250 }
251// is the directory exists with \*.* ?
252 i_pFile = strrchr(pTemp,'\\');
253 if (NULL == i_pFile) Typ = TypisBad;
254 if (Typ == TypisUnkn || Typ == TypisFile) {
255 PathRemoveFileSpecA(pTemp);
256// mask in Path ?
257 if (NULL != strpbrk(pTemp,"*?\0")) {
258 Typ = TypisBad;
259 } else {
260 while (-1 == (i_PathAttr = GetFileAttributesA(pTemp)) && !PathIsRootA(pTemp)) {
261 PathRemoveFileSpecA(pTemp);
262 Typ = TypisNewPath;
263 }
264 i_lenTemp = strlen(pTemp);
265 if (pTemp[i_lenTemp - 1] == '\\') i_lenTemp--;
266 *lenTemp = i_lenTemp;
267 *pFile = i_pFile = &pTemp[i_lenTemp];
268 *PathAttr = i_PathAttr;
269 if (-1 == i_PathAttr || !(i_PathAttr & FILE_ATTRIBUTE_DIRECTORY)) Typ = TypisBad;
270 }
271 strcpy(pTemp,pFromTo);
272 if (Typ == TypisUnkn && i_PathAttr != -1 && (i_PathAttr & FILE_ATTRIBUTE_DIRECTORY)) {
273 if (NULL == strpbrk(i_pFile,"*?\0")) {
274 if (!i_Slash) {
275 *lenTemp = i_lenTemp = strlen(pTemp);
276 *pFile = &pTemp[i_lenTemp];
277 Typ = TypisName;
278 } else Typ = TypisNameS;
279 } else Typ = TypisMask;
280 }
281 }
282 i_pLastSlash[0] = '\\';
283 return Typ;
284}
285#else
286/**************************************************************************
287 * SHELL_FileNamesMatch()
288 *
289 * Accepts two \0 delimited lists of the file names. Checks whether number of
290 * files in the both lists is the same.
291 */
292BOOL SHELL_FileNamesMatch(LPCSTR pszFiles1, LPCSTR pszFiles2)
293{
294 while ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
295 (pszFiles2[strlen(pszFiles2) + 1] != '\0'))
296 {
297 pszFiles1 += strlen(pszFiles1) + 1;
298 pszFiles2 += strlen(pszFiles2) + 1;
299 }
300
301 return
302 ((pszFiles1[strlen(pszFiles1) + 1] == '\0') &&
303 (pszFiles2[strlen(pszFiles2) + 1] == '\0')) ||
304 ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
305 (pszFiles2[strlen(pszFiles2) + 1] != '\0'));
306}
307#endif
308
309/*************************************************************************
310 * SHFileOperationA [SHELL32.243]
311 *
312 * NOTES
313 * exported by name
314 */
315DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
316{
317 LPSTR pFrom = (LPSTR)lpFileOp->pFrom;
318 LPSTR pTo = (LPSTR)lpFileOp->pTo;
319 LPSTR pTempTo;
320#ifdef __WIN32OS2__
321 DWORD FromAttr;
322 DWORD ToAttr;
323 DWORD FromPathAttr;
324 DWORD ToPathAttr;
325 DWORD FromTyp;
326 DWORD ToTyp = TypisBad;
327 DWORD zTyp;
328 LPSTR pFromFile;
329 LPSTR pToFile;
330 LPSTR pTempFrom = NULL;
331 LPSTR pToSlash;
332 LPSTR pToFuncTXT = "FO_COPY";
333 FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
334 BOOL Multi = ((lpFileOp->fFlags & FOF_MULTIDESTFILES) != 0);
335 BOOL MakeDir = FALSE;
336 BOOL not_overwrite;
337 BOOL TargetisDir;
338 BOOL ask_overwrite;
339 BOOL ToSingle;
340 BOOL recurseinto;
341 long lenFrom = -1;
342 long lenTo = -1;
343 long lenTempFrom;
344 long lenTempTo;
345 long retCode = 0x75;
346 long TempretCode = 0;
347 long where = 0;
348 long FuncSwitch = (lpFileOp->wFunc & 15);
349 SHFILEOPSTRUCTA nlpFileOp = *(lpFileOp);
350 long level= nlpFileOp.wFunc>>4;
351 HANDLE hFind;
352 WIN32_FIND_DATAA wfd;
353
354/* default no error
355*/
356 lpFileOp->fAnyOperationsAborted=FALSE;
357 nlpFileOp.fAnyOperationsAborted=FALSE;
358 level++;
359 nlpFileOp.wFunc = (level<<4) + FuncSwitch;
360 if (level == 1)
361#endif
362 TRACE("flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n", lpFileOp->fFlags,
363 lpFileOp->fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
364 lpFileOp->fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
365 lpFileOp->fFlags & FOF_SILENT ? "FOF_SILENT " : "",
366 lpFileOp->fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
367 lpFileOp->fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
368 lpFileOp->fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
369 lpFileOp->fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
370 lpFileOp->fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
371 lpFileOp->fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
372 lpFileOp->fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
373 lpFileOp->fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
374 lpFileOp->fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
375#ifdef __WIN32OS2__
376 switch(FuncSwitch) {
377 case FO_MOVE:
378 retCode = 0xb7;
379 pToFuncTXT = "FO_MOVE";
380#else
381 switch(lpFileOp->wFunc) {
382 case FO_MOVE:
383#endif
384 case FO_COPY:
385 {
386 /* establish when pTo is interpreted as the name of the destination file
387 * or the directory where the Fromfile should be copied to.
388 * This depends on:
389 * (1) pTo points to the name of an existing directory;
390 * (2) the flag FOF_MULTIDESTFILES is present;
391 * (3) whether pFrom point to multiple filenames.
392 *
393 * Some experiments:
394 *
395 * destisdir 1 1 1 1 0 0 0 0
396 * FOF_MULTIDESTFILES 1 1 0 0 1 1 0 0
397 * multiple from filenames 1 0 1 0 1 0 1 0
398 * ---------------
399 * copy files to dir 1 0 1 1 0 0 1 0
400 * create dir 0 0 0 0 0 0 1 0
401 */
402#ifdef __WIN32OS2__
403 nlpFileOp.pFrom = pTempFrom = HeapAlloc(GetProcessHeap(), 0, 3 * MAX_PATH+6);
404 nlpFileOp.pTo = pTempTo = &pTempFrom[MAX_PATH+4];
405/*
406 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY are implemented
407 * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS are not implemented and ignored
408 * FOF_RENAMEONCOLLISION are implemented partially and breaks if file exist
409 * FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE are not implemented and breaks
410 * if any other flag set, an error occurs
411 */
412 TRACE(__FUNCTION__" %s level=%d lpFileOp->fFlags=0x%x\n", pToFuncTXT, level, lpFileOp->fFlags);
413// OFl = (OFl & (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY)));
414// OFl = (OFl ^ (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR));
415 OFl = (OFl & ( ~ (FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY))); // implemented
416 OFl = (OFl ^ (FOF_SILENT | FOF_NOCONFIRMMKDIR)); // ignored, if one
417 OFl = (OFl & ( ~ FOF_SIMPLEPROGRESS)); // ignored, only with FOF_SILENT
418 if (OFl) {
419 if (OFl & ( ~ (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR))) {
420 TRACE(__FUNCTION__" %s level=%d lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n", pToFuncTXT, level, OFl);
421 nlpFileOp.fAnyOperationsAborted=TRUE;
422 } else {
423 TRACE(__FUNCTION__" %s level=%d lpFileOp->fFlags=0x%x not full implemented ,stub\n", pToFuncTXT, level, OFl);
424 } /* endif */
425 } /* endif */
426
427 ask_overwrite = (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) && !(lpFileOp->fFlags & FOF_RENAMEONCOLLISION));
428 not_overwrite = (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (lpFileOp->fFlags & FOF_RENAMEONCOLLISION));
429
430// need break at error before change sourcepointer
431 while(!nlpFileOp.fAnyOperationsAborted && (pFrom+=lenFrom+1)[0]) {
432
433 if (Multi) pTo += lenTo + 1;
434 if(!pTo[0]) {
435 nlpFileOp.fAnyOperationsAborted=TRUE;
436 where = 200;
437 break;
438 } /* endif */
439
440 TRACE(__FUNCTION__" %s level=%d From='%s' To='%s'\n", pToFuncTXT, level, pFrom, pTo);
441
442 FromTyp = SHFileTyp(pFrom, &lenFrom,
443 pTempFrom, &lenTempFrom,
444 &pFromFile,
445 &FromPathAttr, &FromAttr);
446
447// Check Source
448 if (FromTyp != TypisDir
449 && FromTyp != TypisFile
450 && FromTyp != TypisMask) {
451 nlpFileOp.fAnyOperationsAborted=TRUE;
452 where = 201;
453 retCode=0x402;
454 break;
455 } /* endif */
456 zTyp = ToTyp;
457 ToTyp = SHFileTyp(pTo, &lenTo,
458 pTempTo, &lenTempTo,
459 &pToFile,
460 &ToPathAttr, &ToAttr);
461
462// fix for more then one source for one target
463 if (ToTyp == TypisUnkn
464 && zTyp < TypisFile
465 && zTyp > TypisUnkn
466 && lenTo == 0) {
467 pToFile[0] = '\0';
468 ToTyp = zTyp;
469 lenTo = strlen(pTempTo);
470 } /* endif */
471// recursiv creating from directorys are not valid for FO_MOVE.
472 if (FuncSwitch == FO_MOVE && ToTyp == TypisNewPath) ToTyp = TypisUnkn;
473// Check Target
474 if (ToTyp == TypisMask) {
475 nlpFileOp.fAnyOperationsAborted=TRUE;
476 where = 202;
477 if (FromTyp != TypisMask) {
478 retCode=0x10003;
479 } else {
480 if ((lpFileOp->wFunc & 0xf) == FO_MOVE) TempretCode = 0x2;
481 }
482 break;
483 } /* endif */
484 if (ToTyp == TypisBad) {
485 nlpFileOp.fAnyOperationsAborted=TRUE;
486 where = 203;
487 retCode=0x402;
488 break;
489 } /* endif */
490 TargetisDir = (ToTyp == TypisDir || ToTyp == TypisDirS || ToTyp == TypisRoot);
491 ToSingle = (pTo[lenTo+1]=='\0');
492 if (Multi && ToSingle) {
493 Multi = (!(pFrom[lenFrom+1]!='\0'));
494 }
495
496 switch(FromTyp) {
497 case TypisFile: { /* Source is File */
498 if (ToTyp == TypisName) {
499 if (ToSingle && pFrom[lenFrom+1] == '\0') break;
500 if (Multi) break;
501 }
502 if (ToTyp == TypisFile) {
503 if (0 == strcmp(pTempFrom,pTempTo)) { /* target is the same as source ? */
504 nlpFileOp.fAnyOperationsAborted=TRUE;
505 retCode = 0x71;
506 where = 221;
507 break;
508 } /* endif */
509 if (ask_overwrite && SHELL_ConfirmDialog (ASK_OVERWRITE_FILE, pTempTo)) break;
510 if (!not_overwrite) break;
511 if (FuncSwitch == FO_MOVE && (!Multi)) TempretCode = 0x75;
512 }
513 if (!Multi && TargetisDir) {
514 strcpy(pToFile,pFromFile);
515 pTempTo[strlen(pTempTo)+1] = '\0';
516 ToAttr = GetFileAttributesA(pTempTo);
517 if (ToAttr == -1) break;
518 if (!(ToAttr & FILE_ATTRIBUTE_DIRECTORY)) break;
519 }
520 if (FuncSwitch == FO_MOVE && (ToTyp == TypisUnkn || ToTyp == TypisName || ToTyp == TypisNameS)) TempretCode = 0x75;
521 nlpFileOp.fAnyOperationsAborted=TRUE;
522 where = 210 + TypisFile;
523 break;
524 }
525 case TypisMask: { /* Source is Mask */
526 if (TargetisDir) break;
527 nlpFileOp.fAnyOperationsAborted=TRUE;
528 where = 210 + TypisMask;
529 break;
530 }
531 case TypisRoot: /* Source is Root, only small test with this */
532 case TypisDir: { /* Source is Dir */
533 if (TargetisDir) {
534// From Root to Root not full tested, also no Comparsion in W98
535 MakeDir = (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) && ToTyp != TypisRoot);
536 break;
537 }
538 MakeDir = TRUE;
539 if ((ToTyp == TypisName || ToTyp == TypisNameS || ToTyp == TypisNewPath)) break;
540 nlpFileOp.fAnyOperationsAborted=TRUE;
541 where = 210 + TypisDir;
542 break;
543 }
544 default: {
545 nlpFileOp.fAnyOperationsAborted=TRUE;
546 where = 210 + FromTyp;
547// retCode=0x750;
548 break;
549 }
550 }
551 if (nlpFileOp.fAnyOperationsAborted) {
552 if (FuncSwitch == FO_MOVE && (ToTyp == TypisUnkn || ToTyp == TypisName || ToTyp == TypisNameS)) TempretCode = 0x75;
553 break;
554 }
555
556 recurseinto = FALSE;
557
558 if (FuncSwitch == FO_MOVE && ToTyp == TypisName && (FromTyp == TypisDir || FromTyp == TypisFile)) {
559 if (':' == pTempFrom[1] && ':' == pTempTo[1] && pTempFrom[0] == pTempTo[0]) {
560 if (MoveFileA(pTempFrom, pTempTo)) continue;
561 }
562 }
563 if (FromTyp == TypisDir && TargetisDir && MakeDir) {
564 PathRemoveFileSpecA(pTempFrom);
565 lenTempTo = strlen(pTempFrom);
566 strcpy(pTempFrom,pFrom);
567 if (pTempFrom[lenTempTo-1] == '\\') lenTempTo--;
568 strcpy(pToFile,&pFrom[lenTempTo]);
569 lenTempTo = strlen(pTempTo);
570 pTempTo[lenTempTo+1] = '\0';
571 }
572
573 if (MakeDir) {
574 pToSlash = NULL;
575 if ((ToTyp == TypisNameS || ToTyp == TypisNewPath)) {
576 pToSlash = strchr(&pToFile[1],'\\');
577 if (NULL != pToSlash) pToSlash[0] = '\0';
578 }
579 TRACE(__FUNCTION__" %s level=%d Creating Directory '%s'\n", pToFuncTXT, level, pTempTo);
580 SHCreateDirectory(NULL,pTempTo);
581 ToPathAttr = GetFileAttributesA(pTempTo);
582 if (NULL != pToSlash) pToSlash[0] = '\\';
583 if (ToPathAttr == -1) {
584 nlpFileOp.fAnyOperationsAborted=TRUE;
585 retCode=0x10004;
586 where = 220;
587 break;
588 }
589 recurseinto = TRUE;
590 }
591 if (ToTyp != TypisNewPath) {
592 if (FromTyp == TypisDir || FromTyp == TypisRoot) {
593 strcpy(pFromFile,"\\*.*");
594 pTempFrom[strlen(pTempFrom)+1] = '\0';
595 recurseinto = TRUE;
596 } else {
597 if (FromTyp == TypisFile) {
598 if (TargetisDir) {
599 recurseinto = TRUE;
600 } else {
601 if (CopyFileA(pTempFrom, pTempTo, FALSE)) {
602 if (FuncSwitch == FO_COPY) continue;
603 if (DeleteFileA(pTempFrom)) continue;
604 }
605 nlpFileOp.fAnyOperationsAborted=TRUE;
606 where = 222;
607 break;
608 }
609 } /* endif */
610 }
611 }
612 if (recurseinto) {
613 TRACE(__FUNCTION__" %s level=%d Entering into Directory '%s'\n", pToFuncTXT, level, pTempTo);
614 TempretCode = SHFileOperationA (&nlpFileOp);
615 if (nlpFileOp.fAnyOperationsAborted) {where = 223;break;}
616 if (FuncSwitch == FO_MOVE && FromTyp == TypisDir) {
617 if (!(RemoveDirectoryA(pFrom))) {
618 nlpFileOp.fAnyOperationsAborted=TRUE;
619 where = 100;
620 break;
621 }
622 }
623 continue; /* next pTo/pFrom */
624 }
625 if (FromTyp == TypisMask) {
626 hFind = FindFirstFileA(pTempFrom, &wfd);
627 if (INVALID_HANDLE_VALUE == hFind) {
628 nlpFileOp.fAnyOperationsAborted=TRUE;
629 retCode=0x79;
630 where = 224;
631 break;
632 }
633
634 TRACE(__FUNCTION__" %s level=%d between Subdir %s -> %s'\n", pToFuncTXT, level, nlpFileOp.pFrom, nlpFileOp.pTo);
635 nlpFileOp.fFlags = (nlpFileOp.fFlags & (-1 - (FOF_MULTIDESTFILES)));
636
637 do {
638 TRACE(__FUNCTION__" %s level=%d find '%s'\n", pToFuncTXT, level, wfd.cFileName);
639 if (0==strcmp(wfd.cFileName,".")) continue;
640 if (0==strcmp(wfd.cFileName,"..")) continue;
641 if ((nlpFileOp.fFlags & FOF_FILESONLY) && (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)) {
642 continue; /* next name in pFrom(dir) */
643 } /* endif */
644
645 strcpy(&pFromFile[1],wfd.cFileName);
646 pTempFrom[strlen(pTempFrom)+1]='\0';
647
648 TempretCode = SHFileOperationA (&nlpFileOp);
649
650 if (nlpFileOp.fAnyOperationsAborted) {where = 230;break;}
651
652 } while(FindNextFileA(hFind, &wfd));
653 }
654 }
655 break;
656#else
657 int multifrom = pFrom[strlen(pFrom) + 1] != '\0';
658 int destisdir = PathIsDirectoryA( pTo );
659 int todir = 0;
660
661 if (lpFileOp->wFunc == FO_COPY)
662 TRACE("File Copy:\n");
663 else
664 TRACE("File Move:\n");
665
666 if( destisdir ) {
667 if ( !((lpFileOp->fFlags & FOF_MULTIDESTFILES) && !multifrom))
668 todir = 1;
669 } else {
670 if ( !(lpFileOp->fFlags & FOF_MULTIDESTFILES) && multifrom)
671 todir = 1;
672 }
673
674 if ((pTo[strlen(pTo) + 1] != '\0') &&
675 !(lpFileOp->fFlags & FOF_MULTIDESTFILES))
676 {
677 WARN("Attempt to use multiple file names as a destination "
678 "without specifying FOF_MULTIDESTFILES\n");
679 return 1;
680 }
681
682 if ((lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
683 !SHELL_FileNamesMatch(pTo, pFrom))
684 {
685 WARN("Attempt to use multiple file names as a destination "
686 "with mismatching number of files in the source and "
687 "destination lists\n");
688 return 1;
689 }
690
691 if ( todir ) {
692 char szTempFrom[MAX_PATH];
693 char *fromfile;
694 int lenPTo;
695 if ( ! destisdir) {
696 TRACE(" creating directory %s\n",pTo);
697 SHCreateDirectory(NULL,pTo);
698 }
699 lenPTo = strlen(pTo);
700 while(1) {
701 HANDLE hFind;
702 WIN32_FIND_DATAA wfd;
703
704 if(!pFrom[0]) break;
705 TRACE(" From Pattern='%s'\n", pFrom);
706 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
707 {
708 do
709 {
710 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
711 {
712 strcpy(szTempFrom, pFrom);
713
714 pTempTo = HeapAlloc(GetProcessHeap(), 0,
715 lenPTo + strlen(wfd.cFileName) + 5);
716 if (pTempTo) {
717 strcpy(pTempTo,pTo);
718 PathAddBackslashA(pTempTo);
719 strcat(pTempTo,wfd.cFileName);
720
721 fromfile = PathFindFileNameA(szTempFrom);
722 fromfile[0] = '\0';
723 PathAddBackslashA(szTempFrom);
724 strcat(szTempFrom, wfd.cFileName);
725 TRACE(" From='%s' To='%s'\n", szTempFrom, pTempTo);
726 if(lpFileOp->wFunc == FO_COPY)
727 {
728 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
729 {
730 /* copy recursively */
731 if(!(lpFileOp->fFlags & FOF_FILESONLY))
732 {
733 SHFILEOPSTRUCTA shfo;
734
735 SHCreateDirectory(NULL,pTempTo);
736 PathAddBackslashA(szTempFrom);
737 strcat(szTempFrom, "*.*");
738 szTempFrom[strlen(szTempFrom) + 1] = '\0';
739 pTempTo[strlen(pTempTo) + 1] = '\0';
740 memcpy(&shfo, lpFileOp, sizeof(shfo));
741 shfo.pFrom = szTempFrom;
742 shfo.pTo = pTempTo;
743 SHFileOperationA(&shfo);
744
745 szTempFrom[strlen(szTempFrom) - 4] = '\0';
746 }
747 }
748 else
749 CopyFileA(szTempFrom, pTempTo, FALSE);
750 }
751 else
752 {
753 /* move file/directory */
754 MoveFileA(szTempFrom, pTempTo);
755 }
756 HeapFree(GetProcessHeap(), 0, pTempTo);
757 }
758 }
759 } while(FindNextFileA(hFind, &wfd));
760 FindClose(hFind);
761 }
762 else
763 {
764 /* can't find file with specified name */
765 break;
766 }
767 pFrom += strlen(pFrom) + 1;
768 }
769 } else {
770 while(1) {
771 if(!pFrom[0]) break;
772 if(!pTo[0]) break;
773 TRACE(" From='%s' To='%s'\n", pFrom, pTo);
774
775 pTempTo = HeapAlloc(GetProcessHeap(), 0, strlen(pTo)+1);
776 if (pTempTo)
777 {
778 strcpy( pTempTo, pTo );
779 PathRemoveFileSpecA(pTempTo);
780 TRACE(" Creating Directory '%s'\n", pTempTo);
781 SHCreateDirectory(NULL,pTempTo);
782 HeapFree(GetProcessHeap(), 0, pTempTo);
783 }
784 if (lpFileOp->wFunc == FO_COPY)
785 CopyFileA(pFrom, pTo, FALSE);
786 else
787 MoveFileA(pFrom, pTo);
788
789 pFrom += strlen(pFrom) + 1;
790 pTo += strlen(pTo) + 1;
791 }
792 }
793 TRACE("Setting AnyOpsAborted=FALSE\n");
794 lpFileOp->fAnyOperationsAborted=FALSE;
795 return 0;
796#endif
797 }
798
799 case FO_DELETE:
800#ifdef __WIN32OS2__
801 TRACE(__FUNCTION__" FO_DELETE level=%d\n",level);
802// need break at error before change sourcepointer
803 while(!nlpFileOp.fAnyOperationsAborted && (pFrom+=lenFrom+1)[0]) {
804 lenFrom=strlen(pFrom);
805 FromAttr = GetFileAttributesA(pFrom);
806 if (!(FromAttr & FILE_ATTRIBUTE_DIRECTORY)) {
807 TRACE(__FUNCTION__" FO_DELETE level=%d File='%s'\n",level , pFrom);
808 if (DeleteFileA(pFrom)) continue;
809 nlpFileOp.fAnyOperationsAborted=TRUE;
810// retCode = 0x71;
811 where = 301;
812 break;
813 }
814 if (!(pTempFrom)) pTempFrom = HeapAlloc(GetProcessHeap(), 0, MAX_PATH+2);
815 strcpy(pTempFrom,pFrom);
816 PathRemoveBackslashA(pTempFrom);
817 FromAttr = GetFileAttributesA(pTempFrom);
818 if (!(FromAttr & FILE_ATTRIBUTE_DIRECTORY) ) {
819 nlpFileOp.fAnyOperationsAborted=TRUE;
820// retCode = 0x71;
821 where = 302;
822 break;
823 }
824// is Source an existing directory\*.* ?
825 if (FromAttr == -1) {
826 PathRemoveFileSpecA(pTempFrom);
827 FromAttr = GetFileAttributesA(pTempFrom);
828 }
829
830 PathAddBackslashA(pTempFrom);
831 lenTempFrom = strlen(pTempFrom);
832 pFromFile=&pTempFrom[lenTempFrom];
833
834 if (FromAttr == -1 ||
835 ((lenTempFrom==lenFrom) && !PathIsRootA(pFrom)) ||
836 !(FromAttr & FILE_ATTRIBUTE_DIRECTORY) ||
837 !(('\0'==pFrom[lenTempFrom]) || (0==strcmp(&pFrom[lenTempFrom],"*.*"))) ) {
838 retCode=0x402;
839 nlpFileOp.fAnyOperationsAborted=TRUE;
840 where = 303;
841 break;
842 }
843 strcpy(pFromFile, "*.*");
844 lenTempFrom = strlen(pTempFrom);
845 if (lenFrom < lenTempFrom) {
846// Source is without \*.*
847 pTempFrom[lenTempFrom+1]='\0';
848 nlpFileOp.pFrom = pTempFrom;
849
850 TRACE(__FUNCTION__" FO_DELETE level=%d Entering Directory '%s'\n",level , nlpFileOp.pFrom);
851 TempretCode = SHFileOperationA (&nlpFileOp);
852
853 if (nlpFileOp.fAnyOperationsAborted) {break;}
854// Call SHELL_DeleteDirectoryA ?
855 if (RemoveDirectoryA(pFrom)) continue;
856 nlpFileOp.fAnyOperationsAborted=TRUE;
857 where = 304;
858 break;
859 }
860 hFind = FindFirstFileA(pTempFrom, &wfd);
861 if (INVALID_HANDLE_VALUE == hFind) {
862 nlpFileOp.fAnyOperationsAborted=TRUE;
863 retCode=0x79;
864 where = 303;
865 break;
866 }
867
868 nlpFileOp.pFrom = pTempFrom;
869
870 nlpFileOp.fFlags = (nlpFileOp.fFlags & (-1 - (FOF_MULTIDESTFILES)));
871
872 TRACE(__FUNCTION__" FO_DELETE level=%d Delete in Subdir %s'\n",level , nlpFileOp.pFrom);
873
874 do {
875 TRACE(__FUNCTION__" FO_DELETE level=%d find '%s'\n",level , wfd.cFileName);
876 if (0==strcmp(wfd.cFileName,".")) continue;
877 if (0==strcmp(wfd.cFileName,"..")) continue;
878 if ((nlpFileOp.fFlags & FOF_FILESONLY) && (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)) {
879 continue;
880 } /* endif */
881
882 strcpy(pFromFile,wfd.cFileName);
883 pTempFrom[strlen(pTempFrom)+1]='\0';
884
885 TempretCode = SHFileOperationA (&nlpFileOp);
886
887 if (nlpFileOp.fAnyOperationsAborted) {where = 304;break;}
888
889 } while(FindNextFileA(hFind, &wfd));
890
891 FindClose(hFind);
892 if (nlpFileOp.fAnyOperationsAborted) {where = 305;break;}
893 continue;
894 }
895 break;
896 case 0:
897 break;
898#else
899 {
900 HANDLE hFind;
901 WIN32_FIND_DATAA wfd;
902 char szTemp[MAX_PATH];
903 char *file_name;
904
905 TRACE("File Delete:\n");
906 while(1) {
907 if(!pFrom[0]) break;
908 TRACE(" Pattern='%s'\n", pFrom);
909 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
910 {
911 do
912 {
913 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
914 {
915 strcpy(szTemp, pFrom);
916 file_name = PathFindFileNameA(szTemp);
917 file_name[0] = '\0';
918 PathAddBackslashA(szTemp);
919 strcat(szTemp, wfd.cFileName);
920
921 TRACE(" File='%s'\n", szTemp);
922 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
923 {
924 if(!(lpFileOp->fFlags & FOF_FILESONLY))
925 SHELL_DeleteDirectoryA(szTemp, FALSE);
926 }
927 else
928 DeleteFileA(szTemp);
929 }
930 } while(FindNextFileA(hFind, &wfd));
931
932 FindClose(hFind);
933 }
934 pFrom += strlen(pFrom) + 1;
935 }
936 TRACE("Setting AnyOpsAborted=FALSE\n");
937 lpFileOp->fAnyOperationsAborted=FALSE;
938 return 0;
939 }
940#endif
941 case FO_RENAME:
942 TRACE("File Rename:\n");
943 if (pFrom[strlen(pFrom) + 1] != '\0')
944 {
945 WARN("Attempt to rename more than one file\n");
946 return 1;
947 }
948 lpFileOp->fAnyOperationsAborted = FALSE;
949 TRACE("From %s, To %s\n", pFrom, pTo);
950 return !MoveFileA(pFrom, pTo);
951
952 default:
953#ifdef __WIN32OS2__
954 TRACE(__FUNCTION__" Unhandled shell file operation %d at level=%d stub\n",(lpFileOp->wFunc & 15), level );
955 lpFileOp->fAnyOperationsAborted=TRUE;
956#else
957 FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc);
958 }
959#endif
960 return 1;
961
962#ifdef __WIN32OS2__
963 }
964 if (pTempFrom) HeapFree(GetProcessHeap(), 0, pTempFrom);
965
966 if (nlpFileOp.fAnyOperationsAborted) {
967 lpFileOp->fAnyOperationsAborted=TRUE;
968 if (TempretCode > 0 /* retCode */) {
969 retCode = TempretCode;
970 } /* endif */
971 }
972 if (lpFileOp->fAnyOperationsAborted==TRUE) {
973 if (FO_DELETE == (lpFileOp->wFunc & 15)) {
974 TRACE(__FUNCTION__" Setting AnyOpsAborted=TRUE level=%d ret=0x%x, at=%i with %s\n",level, retCode,where,pFrom);
975 } else {
976 TRACE(__FUNCTION__" Setting AnyOpsAborted=TRUE level=%d ret=0x%x, at=%i with %s -> %s\n",level, retCode,where,pFrom,pTo);
977 }
978 return retCode;
979 } /* endif */
980 TRACE(__FUNCTION__" Setting AnyOpsAborted=FALSE\n");
981 return 0;
982
983#endif
984}
985
986/*************************************************************************
987 * SHFileOperationW [SHELL32.244]
988 *
989 * NOTES
990 * exported by name
991 */
992DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
993{
994 FIXME("(%p):stub.\n", lpFileOp);
995 return 1;
996}
997
998/*************************************************************************
999 * SHFileOperation [SHELL32.242]
1000 *
1001 */
1002DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
1003{
1004 if (SHELL_OsIsUnicode())
1005 return SHFileOperationW(lpFileOp);
1006 return SHFileOperationA(lpFileOp);
1007}
1008
1009/*************************************************************************
1010 * SheGetDirW [SHELL32.281]
1011 *
1012 */
1013HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
1014{ FIXME("%p %p stub\n",u,v);
1015 return 0;
1016}
1017
1018/*************************************************************************
1019 * SheChangeDirW [SHELL32.274]
1020 *
1021 */
1022HRESULT WINAPI SheChangeDirW(LPWSTR u)
1023{ FIXME("(%s),stub\n",debugstr_w(u));
1024 return 0;
1025}
1026
1027/*************************************************************************
1028 * IsNetDrive [SHELL32.66]
1029 */
1030BOOL WINAPI IsNetDrive(DWORD drive)
1031{
1032 char root[4];
1033 strcpy(root, "A:\\");
1034 root[0] += drive;
1035 return (GetDriveTypeA(root) == DRIVE_REMOTE);
1036}
1037
1038
Note: See TracBrowser for help on using the repository browser.