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

Last change on this file since 5648 was 5636, checked in by sandervl, 24 years ago

DT: SHFileOperationA updates

File size: 19.3 KB
Line 
1/*
2 * SHFileOperation
3 */
4#ifdef __WIN32OS2__
5#define ICOM_CINTERFACE 1
6#include <odin.h>
7#endif
8#include <string.h>
9#include "debugtools.h"
10#include "shellapi.h"
11#include "shlwapi.h"
12
13#include "shlobj.h"
14#include "shresdef.h"
15#include "shell32_main.h"
16#include "wine/undocshell.h"
17#include "shlwapi.h"
18
19DEFAULT_DEBUG_CHANNEL(shell);
20
21
22#ifdef __WIN32OS2__
23BOOL SHELL_ConfirmDialog (int nKindOfDialog, LPCSTR szDir)
24{
25 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
26 UINT caption_resource_id, text_resource_id;
27
28 switch(nKindOfDialog) {
29
30 case ASK_DELETE_FILE:
31 caption_resource_id = IDS_DELETEITEM_CAPTION;
32 text_resource_id = IDS_DELETEITEM_TEXT;
33 break;
34 case ASK_DELETE_FOLDER:
35 caption_resource_id = IDS_DELETEFOLDER_CAPTION;
36 text_resource_id = IDS_DELETEITEM_TEXT;
37 break;
38 case ASK_DELETE_MULTIPLE_ITEM:
39 caption_resource_id = IDS_DELETEITEM_CAPTION;
40 text_resource_id = IDS_DELETEMULTIPLE_TEXT;
41 break;
42 case ASK_OVERWRITE_FILE:
43 caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
44 text_resource_id = IDS_OVERWRITEFILE_TEXT;
45 break;
46 default:
47 FIXME(__FUNCTION__" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
48 return FALSE;
49 }
50
51 LoadStringA(shell32_hInstance, caption_resource_id, szCaption, sizeof(szCaption));
52 LoadStringA(shell32_hInstance, text_resource_id, szText, sizeof(szText));
53#else
54BOOL SHELL_WarnItemDelete (int nKindOfDialog, LPCSTR szDir)
55{
56 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
57
58 if(nKindOfDialog == ASK_DELETE_FILE)
59 {
60 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
61 sizeof(szText));
62 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
63 szCaption, sizeof(szCaption));
64 }
65 else if(nKindOfDialog == ASK_DELETE_FOLDER)
66 {
67 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
68 sizeof(szText));
69 LoadStringA(shell32_hInstance, IDS_DELETEFOLDER_CAPTION,
70 szCaption, sizeof(szCaption));
71 }
72 else if(nKindOfDialog == ASK_DELETE_MULTIPLE_ITEM)
73 {
74 LoadStringA(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, szText,
75 sizeof(szText));
76 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
77 szCaption, sizeof(szCaption));
78 }
79 else {
80 FIXME("Called without a valid nKindOfDialog specified!");
81 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
82 sizeof(szText));
83 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
84 szCaption, sizeof(szCaption));
85 }
86#endif
87 FormatMessageA(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
88 szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
89
90 return (IDOK == MessageBoxA(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
91}
92
93/**************************************************************************
94 * SHELL_DeleteDirectoryA()
95 *
96 * like rm -r
97 */
98
99BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
100{
101 BOOL ret = FALSE;
102 HANDLE hFind;
103 WIN32_FIND_DATAA wfd;
104 char szTemp[MAX_PATH];
105
106 strcpy(szTemp, pszDir);
107 PathAddBackslashA(szTemp);
108 strcat(szTemp, "*.*");
109
110 if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FOLDER, pszDir))
111 return FALSE;
112
113 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(szTemp, &wfd)))
114 {
115 do
116 {
117 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
118 {
119 strcpy(szTemp, pszDir);
120 PathAddBackslashA(szTemp);
121 strcat(szTemp, wfd.cFileName);
122
123 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
124 SHELL_DeleteDirectoryA(szTemp, FALSE);
125 else
126 DeleteFileA(szTemp);
127 }
128 } while(FindNextFileA(hFind, &wfd));
129
130 FindClose(hFind);
131 ret = RemoveDirectoryA(pszDir);
132 }
133
134 return ret;
135}
136
137/**************************************************************************
138 * SHELL_DeleteFileA()
139 */
140
141BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
142{
143 if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FILE, pszFile))
144 return FALSE;
145
146 return DeleteFileA(pszFile);
147}
148
149/*************************************************************************
150 * SHCreateDirectory [SHELL32.165]
151 *
152 * NOTES
153 * exported by ordinal
154 * not sure about LPSECURITY_ATTRIBUTES
155 */
156DWORD WINAPI SHCreateDirectory(LPSECURITY_ATTRIBUTES sec,LPCSTR path)
157{
158 DWORD ret;
159 TRACE("(%p,%s)\n",sec,path);
160 if ((ret = CreateDirectoryA(path,sec)))
161 {
162 SHChangeNotifyA(SHCNE_MKDIR, SHCNF_PATHA, path, NULL);
163 }
164 return ret;
165}
166
167/************************************************************************
168 * Win32DeleteFile [SHELL32.164]
169 *
170 * Deletes a file. Also triggers a change notify if one exists.
171 *
172 * FIXME:
173 * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be
174 * ANSI. Is this Unicode on NT?
175 *
176 */
177
178BOOL WINAPI Win32DeleteFile(LPSTR fName)
179{
180 TRACE("%p(%s)\n", fName, fName);
181
182 DeleteFileA(fName);
183 SHChangeNotifyA(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
184 return TRUE;
185}
186
187/*************************************************************************
188 * SHFileOperationA [SHELL32.243]
189 *
190 * NOTES
191 * exported by name
192 */
193DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
194{
195 LPSTR pFrom = (LPSTR)lpFileOp->pFrom;
196 LPSTR pTo = (LPSTR)lpFileOp->pTo;
197#ifdef __WIN32OS2__
198 DWORD FromAttr;
199 DWORD ToAttr;
200 LPSTR pTempFrom;
201 LPSTR pTempTo = NULL;
202 LPSTR pFromFile;
203 LPSTR pToFile;
204
205 FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
206 BOOL Multi = TRUE;
207 BOOL withFileName;
208 BOOL not_overwrite;
209 BOOL ToSingle;
210 BOOL BothDir;
211 BOOL ToWithoutBackSlash;
212 long lenFrom = -1;
213 long lenTo = -1;
214 long lenTempFrom;
215 long lenTempTo;
216 long retCode = 0x75;
217 long TempretCode = 0;
218 long where = 0;
219 SHFILEOPSTRUCTA nlpFileOp = *(lpFileOp);
220 HANDLE hFind;
221 WIN32_FIND_DATAA wfd;
222
223/* default no error
224*/
225 lpFileOp->fAnyOperationsAborted=FALSE;
226 nlpFileOp.fAnyOperationsAborted=FALSE;
227#else
228 LPSTR pTempTo;
229#endif
230
231 switch(lpFileOp->wFunc) {
232 case FO_COPY:
233 TRACE("File Copy:\n");
234#ifdef __WIN32OS2__
235 pTempTo = HeapAlloc(GetProcessHeap(), 0, 3 * MAX_PATH+6);
236 pTempFrom = &pTempTo[2*MAX_PATH+2];
237/*
238 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY are implemented
239 * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS are not implemented and ignored
240 * if any other flag set, an error occurs
241 */
242 OFl = (OFl & (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY)));
243 OFl = (OFl ^ (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR));
244 if (OFl) {
245 if (OFl & (-1 - (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR))) {
246 FIXME(__FUNCTION__" FO_COPY with this fFlags not implemented:%x ,stub\n",lpFileOp->fFlags);
247 lpFileOp->fAnyOperationsAborted=TRUE;
248 } else {
249// not FOF_SILENT, not FOF_SIMPLEPROGRESS, not FOF_NOCONFIRMMKDIR
250 FIXME(__FUNCTION__" FO_COPY with this lpFileOp->fFlags not full implemented:0x%x ,stub\n",lpFileOp->fFlags);
251 } /* endif */
252 } /* endif */
253
254 not_overwrite = (!(lpFileOp->fFlags & FOF_NOCONFIRMATION));
255
256// fix for more then one source for one target
257 pToFile = pTempTo;
258
259 while((pFrom+=lenFrom+1)[0] && !nlpFileOp.fAnyOperationsAborted) {
260
261 if (!withFileName && Multi && (pTo[lenTo+1]=='\0')) {
262// Win Bug ?
263 Multi = FALSE;
264 } /* endif */
265
266 if (Multi) pTo += lenTo + 1;
267 if(!pTo[0]) {
268 nlpFileOp.fAnyOperationsAborted=TRUE;
269 where = 13;
270 break;
271 }
272
273 TRACE(" From='%s' To='%s'\n", pFrom, pTo);
274
275// fix for more then one source for one target
276 pToFile[0] = '\0';
277
278 lenFrom=strlen(pFrom);
279 strcpy(pTempFrom,pFrom);
280 FromAttr = GetFileAttributesA(pTempFrom);
281
282 if (Multi) {
283 lenTo = strlen(pTo);
284// single targetdir !Multi
285 Multi = (Multi && (lpFileOp->fFlags & FOF_MULTIDESTFILES));
286// multi target, each one for one source. ? last target + more than one source (all source files an one dir as target)
287
288 ToSingle = ((pTo[lenTo+1]=='\0') || !Multi);
289
290 strcpy(pTempTo,pTo);
291 PathRemoveBackslashA(pTempTo);
292 ToWithoutBackSlash = (strlen(pTempTo)==lenTo);
293 ToAttr = GetFileAttributesA(pTempTo);
294
295 BothDir = (Multi &&
296 ToWithoutBackSlash &&
297 (-1 != (FromAttr | ToAttr)) &&
298 (ToAttr & FromAttr & FILE_ATTRIBUTE_DIRECTORY));
299
300 withFileName = (!BothDir &&
301 (ToWithoutBackSlash || !ToSingle) &&
302 (ToAttr == -1 || !(ToAttr & FILE_ATTRIBUTE_DIRECTORY)));
303
304 if (withFileName) {
305// Target must not be an directory
306 PathRemoveFileSpecA(pTempTo);
307 ToAttr = GetFileAttributesA(pTempTo);
308 }
309 if ((ToAttr == -1) ||
310 !(ToAttr & FILE_ATTRIBUTE_DIRECTORY) ||
311 (!withFileName && !ToSingle) ) {
312 nlpFileOp.fAnyOperationsAborted=TRUE;
313 where = 1;
314 break;
315 }
316 lenTempTo = strlen(pTempTo);
317 withFileName = (((lenTempTo + 1) < lenTo) || (PathIsRootA(pTo) && lenTempTo < lenTo));
318 PathAddBackslashA(pTempTo);
319 }
320
321 if (FromAttr == -1 || BothDir) {
322// is Source an existing directory\*.* ?
323 if (FromAttr == -1) {
324 PathRemoveFileSpecA(pTempFrom);
325 FromAttr = GetFileAttributesA(pTempFrom);
326 }
327
328 PathAddBackslashA(pTempFrom);
329 lenTempFrom = strlen(pTempFrom);
330 pFromFile=&pTempFrom[lenTempFrom];
331
332 if (FromAttr == -1 ||
333 ((lenTempFrom==lenFrom) && !PathIsRootA(pFrom)) ||
334 !(FromAttr & FILE_ATTRIBUTE_DIRECTORY) ||
335 !((0==strcmp(&pFrom[lenTempFrom],"*.*")) || BothDir)) {
336 retCode=0x402;
337 nlpFileOp.fAnyOperationsAborted=TRUE;
338 where = 2;
339 break;
340 }
341
342 strcpy(pFromFile, "*.*");
343 hFind = FindFirstFileA(pTempFrom, &wfd);
344 if (INVALID_HANDLE_VALUE == hFind) {
345 nlpFileOp.fAnyOperationsAborted=TRUE;
346 retCode=0x79;
347 where = 3;
348 break;
349 }
350
351 nlpFileOp.pFrom = pTempFrom;
352// single copy never with FOF_MULTIDESTFILES, I can use lpFileOp->pTo as nlpFileOp.pTo,
353// I need no different targetarea for the name
354 nlpFileOp.fFlags = (nlpFileOp.fFlags & (-1 - (FOF_MULTIDESTFILES)));
355
356 TRACE(__FUNCTION__" Copy between Subdir %s -> %s'\n", nlpFileOp.pFrom, nlpFileOp.pTo);
357
358 do {
359 TRACE(__FUNCTION__" find '%s'\n", wfd.cFileName);
360 if (0==strcmp(wfd.cFileName,".")) continue;
361 if (0==strcmp(wfd.cFileName,"..")) continue;
362 if ((nlpFileOp.fFlags & FOF_FILESONLY) && (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)) {
363 continue;
364 } /* endif */
365
366 strcpy(pFromFile,wfd.cFileName);
367 pTempFrom[strlen(pTempFrom)+1]='\0';
368
369 TempretCode = SHFileOperationA (&nlpFileOp);
370
371 if (nlpFileOp.fAnyOperationsAborted) {where = 4;break;}
372
373 } while(FindNextFileA(hFind, &wfd));
374
375 FindClose(hFind);
376 if (nlpFileOp.fAnyOperationsAborted) {where = 5;break;}
377 continue;
378 }
379
380
381 lenTempTo = strlen(pTempTo);
382 pToFile = &pTempTo[lenTempTo];
383// Check Source
384 strcpy(pToFile,pTempFrom);
385 PathRemoveBackslashA(pToFile);
386 if (strlen(pToFile)<lenFrom) {
387 nlpFileOp.fAnyOperationsAborted=TRUE;
388 retCode=0x402;
389 where = 6;
390 break;
391 } /* endif */
392
393// target name in target or from source
394 pFromFile = NULL;
395 if (withFileName) {
396 if ((pFrom[lenFrom+1]=='\0') || (Multi && !(pTo[lenTo+1]=='\0'))) {
397 pFromFile = pTo;
398 } /* endif */
399 } else {
400// Multi Target
401 if (!Multi || !(pFrom[lenFrom+1]=='\0') ||
402// only target+\, target without \ has 0x402
403 (Multi && (FromAttr & ToAttr & FILE_ATTRIBUTE_DIRECTORY))) {
404 pFromFile = pTempFrom;
405 }
406 } /* endif */
407
408 if (!pFromFile) {
409 nlpFileOp.fAnyOperationsAborted=TRUE;
410 where = 7;
411 break;
412 } /* endif */
413
414// move isolated target filename
415 strcpy(pToFile,pFromFile);
416 PathRemoveFileSpecA(pToFile);
417 PathAddBackslashA(pToFile);
418
419 strcpy(pToFile,&pFromFile[strlen(pToFile)]);
420 ToAttr = GetFileAttributesA(pTempTo);
421
422
423 if (FromAttr == -1) {
424 FIXME(__FUNCTION__" FO_COPY with Source %s not implementiert ,stub\n",pTempFrom);
425 nlpFileOp.fAnyOperationsAborted=TRUE;
426 where = 8;
427 break;
428 }
429 if (FromAttr & FILE_ATTRIBUTE_DIRECTORY) {
430 if (ToAttr == -1) {
431// Try to create an new Directory and enter in it
432 TRACE(" Creating Directory '%s'\n", pTempTo);
433 SHCreateDirectory(NULL,pTempTo);
434 ToAttr = GetFileAttributesA(pTempTo);
435 if (ToAttr == -1) {
436 nlpFileOp.fAnyOperationsAborted=TRUE;
437 retCode=0x10003;
438 where = 9;
439 break;
440 }
441
442 lenTempTo = strlen(pTempTo);
443
444 PathAddBackslashA(pTempFrom);
445 strcat(pTempFrom, "*.*");
446 pTempFrom[strlen(pTempFrom)+1]='\0';
447 nlpFileOp.pFrom = pTempFrom;
448
449 pTempTo[lenTempTo+1]='\0';
450 nlpFileOp.pTo = pTempTo;
451
452 TRACE(__FUNCTION__" Entering Directory '%s'\n", nlpFileOp.pTo);
453 TempretCode = SHFileOperationA (&nlpFileOp);
454
455 if (nlpFileOp.fAnyOperationsAborted) {break;}
456 continue;
457
458 } else {
459 FIXME(__FUNCTION__" FO_COPY unexpected with %s -> %s ? ,stub\n",pTempFrom,pTo);
460 nlpFileOp.fAnyOperationsAborted=TRUE;
461 where = 10;
462 retCode=0x77;
463 break;
464
465 }
466
467 }
468
469 if (!(ToAttr == -1) && (ToAttr & FILE_ATTRIBUTE_DIRECTORY)) {
470 nlpFileOp.fAnyOperationsAborted=TRUE;
471 where = 11;
472 break;
473 }
474 if (0==strcmp(pTempFrom, pTempTo)) {
475 nlpFileOp.fAnyOperationsAborted=TRUE;
476 retCode = 0x71;
477 where = 12;
478 break;
479 }
480// first try to copy
481 if (CopyFileA(pTempFrom, pTempTo, not_overwrite)) continue;
482
483 if (not_overwrite) {
484 if (SHELL_ConfirmDialog (ASK_OVERWRITE_FILE, pTempTo))
485// second try to copy after confirm
486 if (CopyFileA(pTempFrom, pTempTo, FALSE)) continue;
487 } /* endif */
488
489 nlpFileOp.fAnyOperationsAborted=TRUE;
490 }
491
492 if (pTempTo) HeapFree(GetProcessHeap(), 0, pTempTo);
493
494 if (nlpFileOp.fAnyOperationsAborted) {
495 lpFileOp->fAnyOperationsAborted=TRUE;
496 if (TempretCode > retCode) {
497 retCode = TempretCode;
498 } /* endif */
499 }
500 if (lpFileOp->fAnyOperationsAborted==TRUE) {
501 TRACE(__FUNCTION__" Setting AnyOpsAborted=TRUE ret=0x%x, at=%i with %s -> %s\n",retCode,where,pFrom,pTo);
502 return retCode;
503 } /* endif */
504
505 TRACE(__FUNCTION__" Setting AnyOpsAborted=FALSE\n");
506 return 0;
507#else
508 while(1) {
509 if(!pFrom[0]) break;
510 if(!pTo[0]) break;
511 TRACE(" From='%s' To='%s'\n", pFrom, pTo);
512
513 pTempTo = HeapAlloc(GetProcessHeap(), 0, strlen(pTo)+1);
514 if (pTempTo)
515 {
516 strcpy( pTempTo, pTo );
517 PathRemoveFileSpecA(pTempTo);
518 TRACE(" Creating Directory '%s'\n", pTempTo);
519 SHCreateDirectory(NULL,pTempTo);
520 HeapFree(GetProcessHeap(), 0, pTempTo);
521 }
522 CopyFileA(pFrom, pTo, FALSE);
523
524 pFrom += strlen(pFrom) + 1;
525 pTo += strlen(pTo) + 1;
526 }
527 TRACE("Setting AnyOpsAborted=FALSE\n");
528 lpFileOp->fAnyOperationsAborted=FALSE;
529 return 0;
530#endif
531
532 case FO_DELETE:
533 TRACE("File Delete:\n");
534 while(1) {
535 if(!pFrom[0]) break;
536 TRACE(" File='%s'\n", pFrom);
537 DeleteFileA(pFrom);
538 pFrom += strlen(pFrom) + 1;
539 }
540 TRACE("Setting AnyOpsAborted=FALSE\n");
541 lpFileOp->fAnyOperationsAborted=FALSE;
542 return 0;
543
544 default:
545 FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc);
546 }
547
548 return 1;
549}
550
551/*************************************************************************
552 * SHFileOperationW [SHELL32.244]
553 *
554 * NOTES
555 * exported by name
556 */
557DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
558{
559 FIXME("(%p):stub.\n", lpFileOp);
560 return 1;
561}
562
563/*************************************************************************
564 * SHFileOperation [SHELL32.242]
565 *
566 */
567DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
568{
569 if (SHELL_OsIsUnicode())
570 return SHFileOperationW(lpFileOp);
571 return SHFileOperationA(lpFileOp);
572}
573
574/*************************************************************************
575 * SheGetDirW [SHELL32.281]
576 *
577 */
578HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
579{ FIXME("%p %p stub\n",u,v);
580 return 0;
581}
582
583/*************************************************************************
584 * SheChangeDirW [SHELL32.274]
585 *
586 */
587HRESULT WINAPI SheChangeDirW(LPWSTR u)
588{ FIXME("(%s),stub\n",debugstr_w(u));
589 return 0;
590}
591
592/*************************************************************************
593 * IsNetDrive [SHELL32.66]
594 */
595BOOL WINAPI IsNetDrive(DWORD drive)
596{
597 char root[4];
598 strcpy(root, "A:\\");
599 root[0] += drive;
600 return (GetDriveTypeA(root) == DRIVE_REMOTE);
601}
602
Note: See TracBrowser for help on using the repository browser.