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

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

DT: minor change

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