Update the address of the Free Software Foundation.
[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, LPSTR szFilename)
158 {
159     pNode->next = NULL;
160     pNode->unknown = TRUE;
161
162     pNode->filename = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
163     lstrcpyA(pNode->filename, szFilename);
164 }
165
166 static BOOL file_in_list(struct ExtractFileList *pNode, LPSTR 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             {
221                 /* skip this file it it's not in the file list */
222                 if (!file_in_list(pDestination->filelist, pfdin->psz1))
223                     return 0;
224
225                 /* create the destination directory if it doesn't exist */
226                 if (GetFileAttributesA(szDirectory) == INVALID_FILE_ATTRIBUTES)
227                     CreateDirectoryA(szDirectory, NULL);
228
229                 hFile = CreateFileA(szFullPath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
230                                     CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
231
232                 if (hFile == INVALID_HANDLE_VALUE)
233                     hFile = 0;
234             }
235
236             HeapFree(GetProcessHeap(), 0, szFullPath);
237             HeapFree(GetProcessHeap(), 0, szDirectory);
238
239             return (INT_PTR) hFile;
240         }
241
242         case fdintCLOSE_FILE_INFO:
243         {
244             FILETIME ft;
245             FILETIME ftLocal;
246             HANDLE handle = (HANDLE) pfdin->hf;
247
248             if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
249                 return FALSE;
250
251             if (!LocalFileTimeToFileTime(&ft, &ftLocal))
252                 return FALSE;
253
254             if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
255                 return FALSE;
256
257             CloseHandle(handle);
258             return TRUE;
259         }
260
261         default:
262             return 0;
263     }
264 }
265
266 /***********************************************************************
267  * Extract (CABINET.3)
268  *
269  * Extracts the contents of the cabinet file to the specified
270  * destination.
271  *
272  * PARAMS
273  *   dest      [I/O] Controls the operation of Extract.  See NOTES.
274  *   szCabName [I] Filename of the cabinet to extract.
275  *
276  * RETURNS
277  *     Success: S_OK.
278  *     Failure: E_FAIL.
279  *
280  * NOTES
281  *   The following members of the dest struct control the operation
282  *   of Extract:
283  *       filelist  [I] A linked list of filenames.  Extract only extracts
284  *                     files from the cabinet that are in this list.
285  *       filecount [O] Contains the number of files in filelist on
286  *                     completion.
287  *       flags     [I] See Operation.
288  *       directory [I] The destination directory.
289  *       lastfile  [O] The last file extracted.
290  *
291  *   Operation
292  *     If flags contains EXTRACT_FILLFILELIST, then filelist will be
293  *     filled with all the files in the cabinet.  If flags contains
294  *     EXTRACT_EXTRACTFILES, then only the files in the filelist will
295  *     be extracted from the cabinet.  EXTRACT_FILLFILELIST can be called
296  *     by itself, but EXTRACT_EXTRACTFILES must have a valid filelist
297  *     in order to succeed.  If flags contains both EXTRACT_FILLFILELIST
298  *     and EXTRACT_EXTRACTFILES, then all the files in the cabinet
299  *     will be extracted.
300  */
301 HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR szCabName)
302 {
303     HRESULT res = S_OK;
304     HFDI hfdi;
305     ERF erf;
306
307     TRACE("(%p, %s)\n", dest, szCabName);
308
309     hfdi = FDICreate(mem_alloc,
310                      mem_free,
311                      fdi_open,
312                      fdi_read,
313                      fdi_write,
314                      fdi_close,
315                      fdi_seek,
316                      cpuUNKNOWN,
317                      &erf);
318
319     if (!hfdi)
320         return E_FAIL;
321
322     if (GetFileAttributesA(dest->directory) == INVALID_FILE_ATTRIBUTES)
323         return S_OK;
324
325     if (!FDICopy(hfdi, (LPSTR)szCabName, "", 0,
326          fdi_notify_extract, NULL, dest))
327         res = E_FAIL;
328
329     FDIDestroy(hfdi);
330
331     return res;
332 }