In SHFileOperation() when requested to copy files, figure out when the
[wine] / dlls / shell32 / shlfileop.c
1 /*
2  * SHFileOperation
3  */
4 #include <string.h>
5
6 #include "winreg.h"
7 #include "shellapi.h"
8 #include "shlobj.h"
9 #include "shresdef.h"
10 #include "shell32_main.h"
11 #include "undocshell.h"
12 #include "shlwapi.h"
13 #include "debugtools.h"
14
15 DEFAULT_DEBUG_CHANNEL(shell);
16
17 BOOL SHELL_WarnItemDelete (int nKindOfDialog, LPCSTR szDir)
18 {
19         char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
20
21         if(nKindOfDialog == ASK_DELETE_FILE)
22         {
23           LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText, 
24                 sizeof(szText));
25           LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION, 
26                 szCaption, sizeof(szCaption));
27         }
28         else if(nKindOfDialog == ASK_DELETE_FOLDER)
29         {
30           LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText, 
31                 sizeof(szText));
32           LoadStringA(shell32_hInstance, IDS_DELETEFOLDER_CAPTION, 
33                 szCaption, sizeof(szCaption));
34         }
35         else if(nKindOfDialog == ASK_DELETE_MULTIPLE_ITEM)
36         {
37           LoadStringA(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, szText, 
38                 sizeof(szText));
39           LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION, 
40                 szCaption, sizeof(szCaption));
41         }
42         else {
43           FIXME("Called without a valid nKindOfDialog specified!\n");
44           LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText, 
45                 sizeof(szText));
46           LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION, 
47                 szCaption, sizeof(szCaption));
48         }          
49
50         FormatMessageA(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
51             szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
52
53         return (IDOK == MessageBoxA(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
54 }
55
56 /**************************************************************************
57  *      SHELL_DeleteDirectoryA()
58  *
59  * like rm -r
60  */
61
62 BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
63 {
64         BOOL            ret = FALSE;
65         HANDLE          hFind;
66         WIN32_FIND_DATAA wfd;
67         char            szTemp[MAX_PATH];
68
69         strcpy(szTemp, pszDir);
70         PathAddBackslashA(szTemp);
71         strcat(szTemp, "*.*");
72         
73         if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FOLDER, pszDir))
74           return FALSE;
75         
76         if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(szTemp, &wfd)))
77         {
78           do
79           {
80             if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
81             {
82               strcpy(szTemp, pszDir);
83               PathAddBackslashA(szTemp);
84               strcat(szTemp, wfd.cFileName);
85         
86               if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
87                 SHELL_DeleteDirectoryA(szTemp, FALSE);
88               else
89                 DeleteFileA(szTemp);
90             }
91           } while(FindNextFileA(hFind, &wfd));
92
93           FindClose(hFind);
94           ret = RemoveDirectoryA(pszDir);
95         }
96
97         return ret;
98 }
99
100 /**************************************************************************
101  *      SHELL_DeleteFileA()
102  */
103
104 BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
105 {
106         if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FILE, pszFile))
107                 return FALSE;
108  
109         return DeleteFileA(pszFile);
110 }
111
112 /*************************************************************************
113  * SHCreateDirectory                            [SHELL32.165]
114  *
115  * NOTES
116  *  exported by ordinal
117  *  not sure about LPSECURITY_ATTRIBUTES
118  */
119 DWORD WINAPI SHCreateDirectory(LPSECURITY_ATTRIBUTES sec,LPCSTR path)
120 {
121         DWORD ret;
122         TRACE("(%p,%s)\n",sec,path);
123         if ((ret = CreateDirectoryA(path,sec)))
124         {
125           SHChangeNotifyA(SHCNE_MKDIR, SHCNF_PATHA, path, NULL);
126         }
127         return ret;
128 }
129
130 /************************************************************************
131  *      Win32DeleteFile                         [SHELL32.164]  
132  *
133  * Deletes a file.  Also triggers a change notify if one exists.
134  *
135  * FIXME:
136  * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be
137  * ANSI.  Is this Unicode on NT?
138  *
139  */ 
140
141 BOOL WINAPI Win32DeleteFile(LPSTR fName)
142 {
143         TRACE("%p(%s)\n", fName, fName);
144
145         DeleteFileA(fName);
146         SHChangeNotifyA(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
147         return TRUE;
148 }
149
150 /*************************************************************************
151  * SHFileOperationA                             [SHELL32.@]
152  *
153  * NOTES
154  *     exported by name
155  */
156 DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)   
157 {
158         LPSTR pFrom = (LPSTR)lpFileOp->pFrom;
159         LPSTR pTo = (LPSTR)lpFileOp->pTo;
160         LPSTR pTempTo;
161         TRACE("flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n", lpFileOp->fFlags, 
162                 lpFileOp->fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
163                 lpFileOp->fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
164                 lpFileOp->fFlags & FOF_SILENT ? "FOF_SILENT " : "",
165                 lpFileOp->fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
166                 lpFileOp->fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
167                 lpFileOp->fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
168                 lpFileOp->fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
169                 lpFileOp->fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
170                 lpFileOp->fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
171                 lpFileOp->fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
172                 lpFileOp->fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
173                 lpFileOp->fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
174         switch(lpFileOp->wFunc) {
175         case FO_COPY: {
176                 /* establish when pTo is interpreted as the name of the destination file
177                  * or the directory where the Fromfile should be copied to.
178                  * This depends on:
179                  * (1) pTo points to the name of an existing directory;
180                  * (2) the flag FOF_MULTIDESTFILES is present;
181                  * (3) whether pFrom point to multiple filenames.
182                  *
183                  * Some experiments:
184                  *
185                  * destisdir               1 1 1 1 0 0 0 0
186                  * FOF_MULTIDESTFILES      1 1 0 0 1 1 0 0
187                  * multiple from filenames 1 0 1 0 1 0 1 0
188                  *                         ---------------
189                  * copy files to dir       1 0 1 1 0 0 1 0
190                  * create dir              0 0 0 0 0 0 1 0 
191                  */
192                 int multifrom = pFrom[strlen(pFrom) + 1] != '\0';
193                 int destisdir = PathIsDirectoryA( pTo ); 
194                 int copytodir = 0;
195                 TRACE("File Copy:\n");
196                 if( destisdir ) {
197                     if ( !((lpFileOp->fFlags & FOF_MULTIDESTFILES) && !multifrom))
198                         copytodir = 1;
199                 } else {
200                     if ( !(lpFileOp->fFlags & FOF_MULTIDESTFILES) && multifrom)
201                         copytodir = 1;
202                 }
203                 if ( copytodir ) {
204                     char *fromfile;
205                     int lenPTo;
206                     if ( ! destisdir) {
207                         TRACE("   creating directory %s\n",pTo);
208                         SHCreateDirectory(NULL,pTo);
209                     }
210                     lenPTo = strlen(pTo);
211                     while(1) {
212                         if(!pFrom[0]) break;
213                         fromfile = PathFindFileNameA( pFrom);
214                         pTempTo = HeapAlloc(GetProcessHeap(), 0, lenPTo + strlen(fromfile) + 2);
215                         if (pTempTo) {
216                             strcpy(pTempTo,pTo);
217                             if(lenPTo && pTo[lenPTo] != '\\')
218                                 strcat(pTempTo,"\\");
219                             strcat(pTempTo,fromfile);
220                             TRACE("   From='%s' To='%s'\n", pFrom, pTempTo);
221                             CopyFileA(pFrom, pTempTo, FALSE);
222                             HeapFree(GetProcessHeap(), 0, pTempTo);
223                         }
224                         pFrom += strlen(pFrom) + 1;
225                     }
226                 } else {
227                     while(1) {
228                             if(!pFrom[0]) break;
229                             if(!pTo[0]) break;
230                             TRACE("   From='%s' To='%s'\n", pFrom, pTo);
231
232                             pTempTo = HeapAlloc(GetProcessHeap(), 0, strlen(pTo)+1);
233                             if (pTempTo)
234                             {
235                                 strcpy( pTempTo, pTo );
236                                 PathRemoveFileSpecA(pTempTo);
237                                 TRACE("   Creating Directory '%s'\n", pTempTo);
238                                 SHCreateDirectory(NULL,pTempTo);
239                                 HeapFree(GetProcessHeap(), 0, pTempTo);
240                             }
241                             CopyFileA(pFrom, pTo, FALSE);
242
243                             pFrom += strlen(pFrom) + 1;
244                             pTo += strlen(pTo) + 1;
245                     }
246                 }
247                 TRACE("Setting AnyOpsAborted=FALSE\n");
248                 lpFileOp->fAnyOperationsAborted=FALSE;
249                 return 0;
250         }
251
252         case FO_DELETE:
253                 TRACE("File Delete:\n");
254                 while(1) {
255                         if(!pFrom[0]) break;
256                         TRACE("   File='%s'\n", pFrom);
257                         DeleteFileA(pFrom);
258                         pFrom += strlen(pFrom) + 1;
259                 }
260                 TRACE("Setting AnyOpsAborted=FALSE\n");
261                 lpFileOp->fAnyOperationsAborted=FALSE;
262                 return 0;
263
264         default:
265                 FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc);
266         }
267
268         return 1;
269 }
270
271 /*************************************************************************
272  * SHFileOperationW                             [SHELL32.@]
273  *
274  * NOTES
275  *     exported by name
276  */
277 DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)   
278 {
279         FIXME("(%p):stub.\n", lpFileOp);
280         return 1;
281 }
282
283 /*************************************************************************
284  * SHFileOperation                              [SHELL32.@]
285  *
286  */
287 DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
288 {
289         if (SHELL_OsIsUnicode())
290           return SHFileOperationW(lpFileOp);
291         return SHFileOperationA(lpFileOp);
292 }
293
294 /*************************************************************************
295  * SheGetDirW [SHELL32.281]
296  *
297  */
298 HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
299 {       FIXME("%p %p stub\n",u,v);
300         return 0;
301 }
302
303 /*************************************************************************
304  * SheChangeDirW [SHELL32.274]
305  *
306  */
307 HRESULT WINAPI SheChangeDirW(LPWSTR u)
308 {       FIXME("(%s),stub\n",debugstr_w(u));
309         return 0;
310 }
311
312 /*************************************************************************
313  * IsNetDrive                   [SHELL32.66]
314  */
315 BOOL WINAPI IsNetDrive(DWORD drive)
316 {
317         char root[4];
318         strcpy(root, "A:\\");
319         root[0] += drive;
320         return (GetDriveTypeA(root) == DRIVE_REMOTE);
321 }