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