crypt32: Use skip to avoid failures where support is missing.
[wine] / dlls / cabinet / cabinet_main.c
1 /*
2  * cabinet.dll main
3  *
4  * Copyright 2002 Patrik Stridvall
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #define NO_SHLWAPI_REG
31 #include "shlwapi.h"
32 #undef NO_SHLWAPI_REG
33
34 #include "cabinet.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
39
40 /* the following defintions are copied from msvcrt/fcntl.h */
41
42 #define _O_RDONLY      0
43 #define _O_WRONLY      1
44 #define _O_RDWR        2
45 #define _O_ACCMODE     (_O_RDONLY|_O_WRONLY|_O_RDWR)
46
47
48 /***********************************************************************
49  * DllGetVersion (CABINET.2)
50  *
51  * Retrieves version information of the 'CABINET.DLL'
52  *
53  * PARAMS
54  *     pdvi [O] pointer to version information structure.
55  *
56  * RETURNS
57  *     Success: S_OK
58  *     Failure: E_INVALIDARG
59  *
60  * NOTES
61  *     Supposedly returns version from IE6SP1RP1
62  */
63 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
64 {
65   WARN("hmmm... not right version number \"5.1.1106.1\"?\n");
66
67   if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) return E_INVALIDARG;
68
69   pdvi->dwMajorVersion = 5;
70   pdvi->dwMinorVersion = 1;
71   pdvi->dwBuildNumber = 1106;
72   pdvi->dwPlatformID = 1;
73
74   return S_OK;
75 }
76
77 /* FDI callback functions */
78
79 static void *mem_alloc(ULONG cb)
80 {
81     return HeapAlloc(GetProcessHeap(), 0, cb);
82 }
83
84 static void mem_free(void *memory)
85 {
86     HeapFree(GetProcessHeap(), 0, memory);
87 }
88
89 static INT_PTR fdi_open(char *pszFile, int oflag, int pmode)
90 {
91     HANDLE handle;
92     DWORD dwAccess = 0;
93     DWORD dwShareMode = 0;
94     DWORD dwCreateDisposition = OPEN_EXISTING;
95
96     switch (oflag & _O_ACCMODE)
97     {
98         case _O_RDONLY:
99             dwAccess = GENERIC_READ;
100             dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
101             break;
102         case _O_WRONLY:
103             dwAccess = GENERIC_WRITE;
104             dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
105             break;
106         case _O_RDWR:
107             dwAccess = GENERIC_READ | GENERIC_WRITE;
108             dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
109             break;
110     }
111
112     if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
113         dwCreateDisposition = OPEN_EXISTING;
114     else
115         dwCreateDisposition = CREATE_NEW;
116
117     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
118                          dwCreateDisposition, 0, NULL);
119
120     return (INT_PTR) handle;
121 }
122
123 static UINT fdi_read(INT_PTR hf, void *pv, UINT cb)
124 {
125     HANDLE handle = (HANDLE) hf;
126     DWORD dwRead;
127     
128     if (ReadFile(handle, pv, cb, &dwRead, NULL))
129         return dwRead;
130
131     return 0;
132 }
133
134 static UINT fdi_write(INT_PTR hf, void *pv, UINT cb)
135 {
136     HANDLE handle = (HANDLE) hf;
137     DWORD dwWritten;
138
139     if (WriteFile(handle, pv, cb, &dwWritten, NULL))
140         return dwWritten;
141
142     return 0;
143 }
144
145 static int fdi_close(INT_PTR hf)
146 {
147     HANDLE handle = (HANDLE) hf;
148     return CloseHandle(handle) ? 0 : -1;
149 }
150
151 static long fdi_seek(INT_PTR hf, long dist, int seektype)
152 {
153     HANDLE handle = (HANDLE) hf;
154     return SetFilePointer(handle, dist, NULL, seektype);
155 }
156
157 static void fill_file_node(struct ExtractFileList *pNode, LPCSTR szFilename)
158 {
159     pNode->next = NULL;
160     pNode->flag = FALSE;
161
162     pNode->filename = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
163     lstrcpyA(pNode->filename, szFilename);
164 }
165
166 static BOOL file_in_list(const struct ExtractFileList *pNode, LPCSTR szFilename)
167 {
168     while (pNode)
169     {
170         if (!lstrcmpiA(pNode->filename, szFilename))
171             return TRUE;
172
173         pNode = pNode->next;
174     }
175
176     return FALSE;
177 }
178
179 static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
180 {
181     switch (fdint)
182     {
183         case fdintCOPY_FILE:
184         {
185             struct ExtractFileList **fileList;
186             EXTRACTdest *pDestination = pfdin->pv;
187             LPSTR szFullPath, szDirectory;
188             HANDLE hFile = 0;
189             DWORD dwSize;
190
191             dwSize = lstrlenA(pDestination->directory) +
192                     lstrlenA("\\") + lstrlenA(pfdin->psz1) + 1;
193             szFullPath = HeapAlloc(GetProcessHeap(), 0, dwSize);
194
195             lstrcpyA(szFullPath, pDestination->directory);
196             lstrcatA(szFullPath, "\\");
197             lstrcatA(szFullPath, pfdin->psz1);
198
199             /* pull out the destination directory string from the full path */
200             dwSize = strrchr(szFullPath, '\\') - szFullPath + 1;
201             szDirectory = HeapAlloc(GetProcessHeap(), 0, dwSize);
202             lstrcpynA(szDirectory, szFullPath, dwSize);
203
204             if (pDestination->flags & EXTRACT_FILLFILELIST)
205             {
206                 fileList = &pDestination->filelist;
207
208                 while (*fileList)
209                     fileList = &((*fileList)->next);
210
211                 *fileList = HeapAlloc(GetProcessHeap(), 0,
212                                       sizeof(struct ExtractFileList));
213
214                 fill_file_node(*fileList, pfdin->psz1);
215                 lstrcpyA(pDestination->lastfile, szFullPath);
216                 pDestination->filecount++;
217             }
218
219             if ((pDestination->flags & EXTRACT_EXTRACTFILES) ||
220                 file_in_list(pDestination->filterlist, pfdin->psz1))
221             {
222                 /* skip this file if it is not in the file list */
223                 if (!file_in_list(pDestination->filelist, pfdin->psz1))
224                     return 0;
225
226                 /* create the destination directory if it doesn't exist */
227                 if (GetFileAttributesA(szDirectory) == INVALID_FILE_ATTRIBUTES)
228                     CreateDirectoryA(szDirectory, NULL);
229
230                 hFile = CreateFileA(szFullPath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
231                                     CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
232
233                 if (hFile == INVALID_HANDLE_VALUE)
234                     hFile = 0;
235             }
236
237             HeapFree(GetProcessHeap(), 0, szFullPath);
238             HeapFree(GetProcessHeap(), 0, szDirectory);
239
240             return (INT_PTR) hFile;
241         }
242
243         case fdintCLOSE_FILE_INFO:
244         {
245             FILETIME ft;
246             FILETIME ftLocal;
247             HANDLE handle = (HANDLE) pfdin->hf;
248
249             if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
250                 return FALSE;
251
252             if (!LocalFileTimeToFileTime(&ft, &ftLocal))
253                 return FALSE;
254
255             if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
256                 return FALSE;
257
258             CloseHandle(handle);
259             return TRUE;
260         }
261
262         default:
263             return 0;
264     }
265 }
266
267 /***********************************************************************
268  * Extract (CABINET.3)
269  *
270  * Extracts the contents of the cabinet file to the specified
271  * destination.
272  *
273  * PARAMS
274  *   dest      [I/O] Controls the operation of Extract.  See NOTES.
275  *   szCabName [I] Filename of the cabinet to extract.
276  *
277  * RETURNS
278  *     Success: S_OK.
279  *     Failure: E_FAIL.
280  *
281  * NOTES
282  *   The following members of the dest struct control the operation
283  *   of Extract:
284  *       filelist  [I] A linked list of filenames.  Extract only extracts
285  *                     files from the cabinet that are in this list.
286  *       filecount [O] Contains the number of files in filelist on
287  *                     completion.
288  *       flags     [I] See Operation.
289  *       directory [I] The destination directory.
290  *       lastfile  [O] The last file extracted.
291  *
292  *   Operation
293  *     If flags contains EXTRACT_FILLFILELIST, then filelist will be
294  *     filled with all the files in the cabinet.  If flags contains
295  *     EXTRACT_EXTRACTFILES, then only the files in the filelist will
296  *     be extracted from the cabinet.  EXTRACT_FILLFILELIST can be called
297  *     by itself, but EXTRACT_EXTRACTFILES must have a valid filelist
298  *     in order to succeed.  If flags contains both EXTRACT_FILLFILELIST
299  *     and EXTRACT_EXTRACTFILES, then all the files in the cabinet
300  *     will be extracted.
301  */
302 HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR szCabName)
303 {
304     HRESULT res = S_OK;
305     HFDI hfdi;
306     ERF erf;
307     char *str, *path, *name;
308
309     TRACE("(%p, %s)\n", dest, szCabName);
310
311     hfdi = FDICreate(mem_alloc,
312                      mem_free,
313                      fdi_open,
314                      fdi_read,
315                      fdi_write,
316                      fdi_close,
317                      fdi_seek,
318                      cpuUNKNOWN,
319                      &erf);
320
321     if (!hfdi)
322         return E_FAIL;
323
324     if (GetFileAttributesA(dest->directory) == INVALID_FILE_ATTRIBUTES)
325         return S_OK;
326
327     /* split the cabinet name into path + name */
328     str = HeapAlloc(GetProcessHeap(), 0, lstrlenA(szCabName)+1);
329     if (!str)
330     {
331         res = E_OUTOFMEMORY;
332         goto end;
333     }
334     lstrcpyA(str, szCabName);
335
336     path = str;
337     name = strrchr(path, '\\');
338     if (name)
339         *name++ = 0;
340     else
341     {
342         name = path;
343         path = NULL;
344     }
345
346     if (!FDICopy(hfdi, name, path, 0,
347          fdi_notify_extract, NULL, dest))
348         res = E_FAIL;
349
350     HeapFree(GetProcessHeap(), 0, str);
351 end:
352
353     FDIDestroy(hfdi);
354
355     return res;
356 }