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

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

DT: SHFileOperationA updates

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