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

Last change on this file since 5625 was 5623, checked in by sandervl, 24 years ago

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 pTempTo = NULL;
201 LPSTR pTempFrom;
202 LPSTR pNextFrom;
203 LPSTR pNextTo;
204 LPSTR pToFile;
205
206 FILEOP_FLAGS OFl = ((FILEOP_FLAGS)lpFileOp->fFlags & 0x7ff);
207 BOOL Multi = TRUE;
208 BOOL withFileName = FALSE;
209 BOOL not_overwrite;
210 BOOL toSingle;
211 BOOL StarStar;
212 BOOL copyOk;
213 long lenFrom = -1;
214 long lenTo = -1;
215 long lenTempTo;
216 long retCode = 0x75;
217 long TempretCode = 0;
218 long lenNextFrom;
219 long lenNextTo;
220 SHFILEOPSTRUCTA nlpFileOp = *(lpFileOp);
221 HANDLE hFind;
222 WIN32_FIND_DATAA wfd;
223
224/* default no error
225*/
226 lpFileOp->fAnyOperationsAborted=FALSE;
227 nlpFileOp.fAnyOperationsAborted=FALSE;
228#else
229 LPSTR pTempTo;
230#endif
231
232 switch(lpFileOp->wFunc) {
233 case FO_COPY:
234 TRACE("File Copy:\n");
235#ifdef __WIN32OS2__
236 pTempTo = HeapAlloc(GetProcessHeap(), 0, 4 * MAX_PATH+4);
237 pNextFrom = &pTempTo[2*MAX_PATH+2];
238 pNextTo = &pNextFrom[MAX_PATH+1];
239/*
240 * FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY are implemented
241 * FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR, FOF_SIMPLEPROGRESS are not implemented and ignored
242 * if any other flag set, an error occurs
243 */
244 OFl = (OFl & (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY)));
245 OFl = (OFl ^ (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR));
246 if (OFl) {
247 if (OFl & (-1 - (FOF_CONFIRMMOUSE | FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR))) {
248 FIXME(__FUNCTION__" FO_COPY with this fFlags not implemented:%2x ,stub\n",lpFileOp->fFlags);
249 lpFileOp->fAnyOperationsAborted=TRUE;
250 } else {
251// not FOF_SILENT, not FOF_SIMPLEPROGRESS, not FOF_NOCONFIRMMKDIR
252 FIXME(__FUNCTION__" FO_COPY with this lpFileOp->fFlags not full implemented:0x%2x ,stub\n",lpFileOp->fFlags);
253 } /* endif */
254 } /* endif */
255
256 not_overwrite = (!(lpFileOp->fFlags & FOF_NOCONFIRMATION));
257
258// fix for more then one source for one target
259 pToFile = pTempTo;
260
261 while((pFrom+=lenFrom+1)[0] && !nlpFileOp.fAnyOperationsAborted) {
262
263 if (!withFileName && Multi && (pTo[lenTo+1]=='\0')) {
264// Win Bug ?
265 Multi = FALSE;
266 } /* endif */
267
268 if (Multi) pTo += lenTo + 1;
269 if(!pTo[0]) break;
270
271 TRACE(" From='%s' To='%s'\n", pFrom, pTo);
272
273// fix for more then one source for one target
274 pToFile[0] = '\0';
275
276 lenFrom=strlen(pFrom);
277 strcpy(pNextFrom,pFrom);
278 FromAttr = GetFileAttributesA(pNextFrom);
279 StarStar = FALSE;
280
281 if (Multi) {
282 lenTo = strlen(pTo);
283// single targetdir !Multi
284 Multi = (Multi && (lpFileOp->fFlags & FOF_MULTIDESTFILES));
285// multi target, each one for one source. ? last target + more than one source (all source files an one dir as target)
286
287 toSingle = ((pTo[lenTo+1]=='\0') || !Multi);
288 withFileName = FALSE;
289
290 strcpy(pTempTo,pTo);
291 PathRemoveBackslashA(pTempTo);
292 ToAttr = GetFileAttributesA(pTempTo);
293 if (ToAttr == -1 || !(ToAttr & FILE_ATTRIBUTE_DIRECTORY)) {
294 withFileName = ((lenTo == strlen(pTempTo)) || !toSingle);
295 if (withFileName) {
296// Target must not be an directory
297 PathRemoveFileSpecA(pTempTo);
298 ToAttr = GetFileAttributesA(pTempTo);
299 }
300 }
301 if (ToAttr == -1) {
302 nlpFileOp.fAnyOperationsAborted=TRUE;
303 break;
304 }
305 if (!(ToAttr & FILE_ATTRIBUTE_DIRECTORY) || (!withFileName && !toSingle) ) {
306// never Create directory at this time
307 nlpFileOp.fAnyOperationsAborted=TRUE;
308 /* retCode=0x279; */
309 break;
310 }
311 lenTempTo = strlen(pTempTo);
312 withFileName = (((lenTempTo + 1) < lenTo) || (PathIsRootA(pTo) && lenTempTo < lenTo));
313 PathAddBackslashA(pTempTo);
314 StarStar = (Multi && !withFileName &&
315 (ToAttr & FILE_ATTRIBUTE_DIRECTORY) &&
316 (FromAttr != -1) &&
317 (FromAttr & FILE_ATTRIBUTE_DIRECTORY) &&
318 (0!=strcmp(pTempTo,pTo)));
319 }
320
321 if (FromAttr == -1 || StarStar) {
322// is Source an existing directory\*.* ?
323 if (FromAttr == -1) {
324 PathRemoveFileSpecA(pNextFrom);
325 FromAttr = GetFileAttributesA(pNextFrom);
326 }
327 PathAddBackslashA(pNextFrom);
328 lenNextFrom = strlen(pNextFrom);
329 pToFile=&pNextFrom[lenNextFrom];
330
331 if (FromAttr == -1 ||
332 ((0==strcmp(pNextFrom,pFrom)) && !PathIsRootA(pFrom)) ||
333 !(FromAttr & FILE_ATTRIBUTE_DIRECTORY) ||
334 !((0==strcmp(&pFrom[lenNextFrom],"*.*")) || StarStar)) {
335 retCode=0x402;
336 nlpFileOp.fAnyOperationsAborted=TRUE;
337 break;
338 }
339
340 strcpy(pToFile, "*.*");
341 hFind = FindFirstFileA(pNextFrom, &wfd);
342 if (INVALID_HANDLE_VALUE == hFind) {
343 nlpFileOp.fAnyOperationsAborted=TRUE;
344 retCode=0x79;
345 break;
346 }
347 nlpFileOp.pFrom = pNextFrom;
348 strcpy(pNextTo,pTo);
349 pNextTo[strlen(pNextTo)+1]='\0';
350 nlpFileOp.fFlags = (nlpFileOp.fFlags & (-1 - (FOF_MULTIDESTFILES)));
351
352 TRACE(__FUNCTION__" Copy between Subdir %s -> %s'\n", nlpFileOp.pFrom, nlpFileOp.pTo);
353
354 do {
355 TRACE(__FUNCTION__" find '%s'\n", wfd.cFileName);
356 if (0==strcmp(wfd.cFileName,".")) continue;
357 if (0==strcmp(wfd.cFileName,"..")) continue;
358 if ((nlpFileOp.fFlags & FOF_FILESONLY) && (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)) {
359 continue;
360 } /* endif */
361
362 strcpy(pToFile,wfd.cFileName);
363 pNextFrom[strlen(pNextFrom)+1]='\0';
364
365 TempretCode = SHFileOperationA (&nlpFileOp);
366
367 if (nlpFileOp.fAnyOperationsAborted) {/*retCode=0x179;*/break;}
368
369 } while(FindNextFileA(hFind, &wfd));
370
371 FindClose(hFind);
372 if (nlpFileOp.fAnyOperationsAborted) break;
373 continue;
374 }
375
376
377 lenTempTo = strlen(pTempTo);
378 pToFile = &pTempTo[lenTempTo];
379// Check Source
380 strcpy(pToFile,pNextFrom);
381 PathRemoveBackslashA(pToFile);
382 if (strlen(pToFile)<lenFrom) {
383 nlpFileOp.fAnyOperationsAborted=TRUE;
384 retCode=0x402;
385 break;
386 } /* endif */
387
388// target name in target or from source
389 pTempFrom = NULL;
390 if (withFileName) {
391 if ((pFrom[lenFrom+1]=='\0') || (Multi && !(pTo[lenTo+1]=='\0'))) {
392 pTempFrom = pTo;
393 } /* endif */
394 } else {
395// Multi Target
396 if (!Multi || !(pFrom[lenFrom+1]=='\0') ||
397// only target+\, target without \ has 0x402
398 (Multi && (FromAttr & FILE_ATTRIBUTE_DIRECTORY) && (ToAttr & FILE_ATTRIBUTE_DIRECTORY))) {
399 pTempFrom = pNextFrom;
400 }
401 } /* endif */
402
403 if (!pTempFrom) {
404 nlpFileOp.fAnyOperationsAborted=TRUE;
405 break;
406 } /* endif */
407
408// move isolated target filename
409 strcpy(pToFile,pTempFrom);
410 PathRemoveFileSpecA(pToFile);
411 PathAddBackslashA(pToFile);
412
413 strcpy(pToFile,&pTempFrom[strlen(pToFile)]);
414 ToAttr = GetFileAttributesA(pTempTo);
415
416
417 if (FromAttr == -1) {
418 FIXME(__FUNCTION__" FO_COPY with Source %s not implementiert ,stub\n",pNextFrom);
419 nlpFileOp.fAnyOperationsAborted=TRUE;
420 retCode=0x76;
421 break;
422 }
423 if (FromAttr & FILE_ATTRIBUTE_DIRECTORY) {
424 if (ToAttr == -1) {
425// Try to create an new Directory and enter in it
426 TRACE(" Creating Directory '%s'\n", pTempTo);
427 SHCreateDirectory(NULL,pTempTo);
428 ToAttr = GetFileAttributesA(pTempTo);
429 if (ToAttr == -1) {
430 nlpFileOp.fAnyOperationsAborted=TRUE;
431 retCode=0x10003;
432 break;
433 }
434
435 lenTempTo = strlen(pTempTo);
436
437 PathAddBackslashA(pNextFrom);
438 strcat(pNextFrom, "*.*");
439 pNextFrom[strlen(pNextFrom)+1]='\0';
440 nlpFileOp.pFrom = pNextFrom;
441
442 pTempTo[lenTempTo+1]='\0';
443 nlpFileOp.pTo = pTempTo;
444
445 TRACE(__FUNCTION__" Entering Directory '%s'\n", nlpFileOp.pTo);
446 TempretCode = SHFileOperationA (&nlpFileOp);
447
448 if (nlpFileOp.fAnyOperationsAborted) {break;}
449 continue;
450
451 } else {
452 if (!(ToAttr & FILE_ATTRIBUTE_DIRECTORY)) {
453 FIXME(__FUNCTION__" FO_COPY only with %s -> %t ? ,stub\n",pNextFrom,pTo);
454 nlpFileOp.fAnyOperationsAborted=TRUE;
455 retCode=0x77;
456 break;
457 }
458 if (strlen(pToFile)==0) {
459 nlpFileOp.fAnyOperationsAborted=TRUE;
460 retCode=0x78;
461 break;
462 } else {
463 nlpFileOp.fAnyOperationsAborted=TRUE;
464 retCode=0x80;
465 break;
466 } /* endif */
467
468 }
469
470 }
471
472 if (!(ToAttr == -1) && (ToAttr & FILE_ATTRIBUTE_DIRECTORY)) {
473 nlpFileOp.fAnyOperationsAborted=TRUE;
474 break;
475 }
476// first try to copy
477 if (CopyFileA(pNextFrom, pTempTo, not_overwrite)) continue;
478
479 if (not_overwrite) {
480 if (SHELL_ConfirmDialog (ASK_OVERWRITE_FILE, pTempTo))
481// second try to copy after confirm
482 if (CopyFileA(pNextFrom, pTempTo, FALSE)) continue;
483 } /* endif */
484
485 nlpFileOp.fAnyOperationsAborted=TRUE;
486 }
487
488 if (pTempTo) HeapFree(GetProcessHeap(), 0, pTempTo);
489
490 if (nlpFileOp.fAnyOperationsAborted) {
491 lpFileOp->fAnyOperationsAborted=TRUE;
492 if (TempretCode > retCode) {
493 retCode = TempretCode;
494 } /* endif */
495 }
496 if (lpFileOp->fAnyOperationsAborted==TRUE) {
497 TRACE(__FUNCTION__" Setting AnyOpsAborted=TRUE\n");
498 return retCode;
499 } /* endif */
500
501 TRACE(__FUNCTION__" Setting AnyOpsAborted=FALSE\n");
502 return 0;
503#else
504 while(1) {
505 if(!pFrom[0]) break;
506 if(!pTo[0]) break;
507 TRACE(" From='%s' To='%s'\n", pFrom, pTo);
508
509 pTempTo = HeapAlloc(GetProcessHeap(), 0, strlen(pTo)+1);
510 if (pTempTo)
511 {
512 strcpy( pTempTo, pTo );
513 PathRemoveFileSpecA(pTempTo);
514 TRACE(" Creating Directory '%s'\n", pTempTo);
515 SHCreateDirectory(NULL,pTempTo);
516 HeapFree(GetProcessHeap(), 0, pTempTo);
517 }
518 CopyFileA(pFrom, pTo, FALSE);
519
520 pFrom += strlen(pFrom) + 1;
521 pTo += strlen(pTo) + 1;
522 }
523 TRACE("Setting AnyOpsAborted=FALSE\n");
524 lpFileOp->fAnyOperationsAborted=FALSE;
525 return 0;
526#endif
527
528 case FO_DELETE:
529 TRACE("File Delete:\n");
530 while(1) {
531 if(!pFrom[0]) break;
532 TRACE(" File='%s'\n", pFrom);
533 DeleteFileA(pFrom);
534 pFrom += strlen(pFrom) + 1;
535 }
536 TRACE("Setting AnyOpsAborted=FALSE\n");
537 lpFileOp->fAnyOperationsAborted=FALSE;
538 return 0;
539
540 default:
541 FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc);
542 }
543
544 return 1;
545}
546
547/*************************************************************************
548 * SHFileOperationW [SHELL32.244]
549 *
550 * NOTES
551 * exported by name
552 */
553DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
554{
555 FIXME("(%p):stub.\n", lpFileOp);
556 return 1;
557}
558
559/*************************************************************************
560 * SHFileOperation [SHELL32.242]
561 *
562 */
563DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
564{
565 if (SHELL_OsIsUnicode())
566 return SHFileOperationW(lpFileOp);
567 return SHFileOperationA(lpFileOp);
568}
569
570/*************************************************************************
571 * SheGetDirW [SHELL32.281]
572 *
573 */
574HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
575{ FIXME("%p %p stub\n",u,v);
576 return 0;
577}
578
579/*************************************************************************
580 * SheChangeDirW [SHELL32.274]
581 *
582 */
583HRESULT WINAPI SheChangeDirW(LPWSTR u)
584{ FIXME("(%s),stub\n",debugstr_w(u));
585 return 0;
586}
587
588/*************************************************************************
589 * IsNetDrive [SHELL32.66]
590 */
591BOOL WINAPI IsNetDrive(DWORD drive)
592{
593 char root[4];
594 strcpy(root, "A:\\");
595 root[0] += drive;
596 return (GetDriveTypeA(root) == DRIVE_REMOTE);
597}
Note: See TracBrowser for help on using the repository browser.