cabinet_main.c 11 KB
Newer Older
Greg Turner's avatar
Greg Turner committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * cabinet.dll main
 *
 * Copyright 2002 Patrik Stridvall
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Greg Turner's avatar
Greg Turner committed
19
 */
20 21 22 23

#include <assert.h>
#include <stdarg.h>
#include <string.h>
24
#include <fcntl.h>
25

Greg Turner's avatar
Greg Turner committed
26 27 28 29 30 31 32 33 34 35 36 37 38
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#define NO_SHLWAPI_REG
#include "shlwapi.h"
#undef NO_SHLWAPI_REG

#include "cabinet.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(cabinet);

39

Greg Turner's avatar
Greg Turner committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
/***********************************************************************
 * DllGetVersion (CABINET.2)
 *
 * Retrieves version information of the 'CABINET.DLL'
 *
 * PARAMS
 *     pdvi [O] pointer to version information structure.
 *
 * RETURNS
 *     Success: S_OK
 *     Failure: E_INVALIDARG
 *
 * NOTES
 *     Supposedly returns version from IE6SP1RP1
 */
55
HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
Greg Turner's avatar
Greg Turner committed
56 57 58 59 60 61 62 63 64 65 66 67 68
{
  WARN("hmmm... not right version number \"5.1.1106.1\"?\n");

  if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) return E_INVALIDARG;

  pdvi->dwMajorVersion = 5;
  pdvi->dwMinorVersion = 1;
  pdvi->dwBuildNumber = 1106;
  pdvi->dwPlatformID = 1;

  return S_OK;
}

69 70
/* FDI callback functions */

71
static void * CDECL mem_alloc(ULONG cb)
72 73 74 75
{
    return HeapAlloc(GetProcessHeap(), 0, cb);
}

76
static void CDECL mem_free(void *memory)
77 78 79 80
{
    HeapFree(GetProcessHeap(), 0, memory);
}

81
static INT_PTR CDECL fdi_open(char *pszFile, int oflag, int pmode)
82 83 84 85
{
    HANDLE handle;
    DWORD dwAccess = 0;
    DWORD dwShareMode = 0;
86
    DWORD dwCreateDisposition;
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

    switch (oflag & _O_ACCMODE)
    {
        case _O_RDONLY:
            dwAccess = GENERIC_READ;
            dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
            break;
        case _O_WRONLY:
            dwAccess = GENERIC_WRITE;
            dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
            break;
        case _O_RDWR:
            dwAccess = GENERIC_READ | GENERIC_WRITE;
            dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
            break;
    }

104 105 106 107 108 109
    if (oflag & _O_CREAT)
    {
        dwCreateDisposition = OPEN_ALWAYS;
        if (oflag & _O_EXCL) dwCreateDisposition = CREATE_NEW;
        else if (oflag & _O_TRUNC) dwCreateDisposition = CREATE_ALWAYS;
    }
110
    else
111 112 113 114
    {
        dwCreateDisposition = OPEN_EXISTING;
        if (oflag & _O_TRUNC) dwCreateDisposition = TRUNCATE_EXISTING;
    }
115 116 117 118 119 120 121

    handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
                         dwCreateDisposition, 0, NULL);

    return (INT_PTR) handle;
}

122
static UINT CDECL fdi_read(INT_PTR hf, void *pv, UINT cb)
123 124 125 126 127 128 129 130 131 132
{
    HANDLE handle = (HANDLE) hf;
    DWORD dwRead;
    
    if (ReadFile(handle, pv, cb, &dwRead, NULL))
        return dwRead;

    return 0;
}

133
static UINT CDECL fdi_write(INT_PTR hf, void *pv, UINT cb)
134 135 136 137 138 139 140 141 142 143
{
    HANDLE handle = (HANDLE) hf;
    DWORD dwWritten;

    if (WriteFile(handle, pv, cb, &dwWritten, NULL))
        return dwWritten;

    return 0;
}

144
static int CDECL fdi_close(INT_PTR hf)
145 146 147 148 149
{
    HANDLE handle = (HANDLE) hf;
    return CloseHandle(handle) ? 0 : -1;
}

150
static LONG CDECL fdi_seek(INT_PTR hf, LONG dist, int seektype)
151 152 153 154 155
{
    HANDLE handle = (HANDLE) hf;
    return SetFilePointer(handle, dist, NULL, seektype);
}

156
static void fill_file_node(struct FILELIST *pNode, LPCSTR szFilename)
157 158
{
    pNode->next = NULL;
159
    pNode->DoExtract = FALSE;
160

161 162
    pNode->FileName = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
    lstrcpyA(pNode->FileName, szFilename);
163 164
}

165 166
static BOOL file_in_list(struct FILELIST *pNode, LPCSTR szFilename,
                         struct FILELIST **pOut)
167 168 169
{
    while (pNode)
    {
170
        if (!lstrcmpiA(pNode->FileName, szFilename))
171 172 173 174
        {
            if (pOut)
                *pOut = pNode;

175
            return TRUE;
176
        }
177 178 179 180 181 182 183

        pNode = pNode->next;
    }

    return FALSE;
}

184
static INT_PTR CDECL fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
185 186 187 188 189
{
    switch (fdint)
    {
        case fdintCOPY_FILE:
        {
190
            struct FILELIST *fileList, *node = NULL;
191
            SESSION *pDestination = pfdin->pv;
192 193 194 195
            LPSTR szFullPath, szDirectory;
            HANDLE hFile = 0;
            DWORD dwSize;

196
            dwSize = lstrlenA(pDestination->Destination) +
197 198 199
                    lstrlenA("\\") + lstrlenA(pfdin->psz1) + 1;
            szFullPath = HeapAlloc(GetProcessHeap(), 0, dwSize);

200
            lstrcpyA(szFullPath, pDestination->Destination);
201 202 203 204 205 206 207 208
            lstrcatA(szFullPath, "\\");
            lstrcatA(szFullPath, pfdin->psz1);

            /* pull out the destination directory string from the full path */
            dwSize = strrchr(szFullPath, '\\') - szFullPath + 1;
            szDirectory = HeapAlloc(GetProcessHeap(), 0, dwSize);
            lstrcpynA(szDirectory, szFullPath, dwSize);

209 210
            pDestination->FileSize += pfdin->cb;

211
            if (pDestination->Operation & EXTRACT_FILLFILELIST)
212
            {
213 214
                fileList = HeapAlloc(GetProcessHeap(), 0,
                                     sizeof(struct FILELIST));
215

216
                fill_file_node(fileList, pfdin->psz1);
217
                fileList->DoExtract = TRUE;
218 219
                fileList->next = pDestination->FileList;
                pDestination->FileList = fileList;
220 221
                lstrcpyA(pDestination->CurrentFile, szFullPath);
                pDestination->FileCount++;
222 223
            }

224
            if ((pDestination->Operation & EXTRACT_EXTRACTFILES) ||
225
                file_in_list(pDestination->FilterList, pfdin->psz1, NULL))
226
            {
227 228 229 230
		/* find the file node */
                file_in_list(pDestination->FileList, pfdin->psz1, &node);

                if (node && !node->DoExtract)
231 232 233
                {
                    HeapFree(GetProcessHeap(), 0, szFullPath);
                    HeapFree(GetProcessHeap(), 0, szDirectory);
234
                    return 0;
235
                }
236 237 238

                /* create the destination directory if it doesn't exist */
                if (GetFileAttributesA(szDirectory) == INVALID_FILE_ATTRIBUTES)
239 240 241 242 243 244 245 246 247 248
                {
                    char *ptr;

                    for(ptr = szDirectory + strlen(pDestination->Destination)+1; *ptr; ptr++) {
                        if(*ptr == '\\') {
                            *ptr = 0;
                            CreateDirectoryA(szDirectory, NULL);
                            *ptr = '\\';
                        }
                    }
249
                    CreateDirectoryA(szDirectory, NULL);
250
                }
251 252

                hFile = CreateFileA(szFullPath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
253
                                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
254

255
                if (hFile != INVALID_HANDLE_VALUE && node)
256
                    node->DoExtract = FALSE;
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
            }

            HeapFree(GetProcessHeap(), 0, szFullPath);
            HeapFree(GetProcessHeap(), 0, szDirectory);

            return (INT_PTR) hFile;
        }

        case fdintCLOSE_FILE_INFO:
        {
            FILETIME ft;
            FILETIME ftLocal;
            HANDLE handle = (HANDLE) pfdin->hf;

            if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
                return FALSE;

            if (!LocalFileTimeToFileTime(&ft, &ftLocal))
                return FALSE;

            if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
                return FALSE;

            CloseHandle(handle);
            return TRUE;
        }

        default:
            return 0;
    }
}

Greg Turner's avatar
Greg Turner committed
289 290 291
/***********************************************************************
 * Extract (CABINET.3)
 *
292 293
 * Extracts the contents of the cabinet file to the specified
 * destination.
Greg Turner's avatar
Greg Turner committed
294 295
 *
 * PARAMS
296
 *   dest      [I/O] Controls the operation of Extract.  See NOTES.
297
 *   szCabName [I] Filename of the cabinet to extract.
Greg Turner's avatar
Greg Turner committed
298 299
 *
 * RETURNS
300 301 302 303 304 305
 *     Success: S_OK.
 *     Failure: E_FAIL.
 *
 * NOTES
 *   The following members of the dest struct control the operation
 *   of Extract:
306 307 308 309 310 311 312 313 314 315
 *       FileSize    [O] The size of all files extracted up to CurrentFile.
 *       Error       [O] The error in case the extract operation fails.
 *       FileList    [I] A linked list of filenames.  Extract only extracts
 *                       files from the cabinet that are in this list.
 *       FileCount   [O] Contains the number of files in FileList on
 *                       completion.
 *       Operation   [I] See Operation.
 *       Destination [I] The destination directory.
 *       CurrentFile [O] The last file extracted.
 *       FilterList  [I] A linked list of files that should not be extracted.
316 317
 *
 *   Operation
318 319 320
 *     If Operation contains EXTRACT_FILLFILELIST, then FileList will be
 *     filled with all the files in the cabinet.  If Operation contains
 *     EXTRACT_EXTRACTFILES, then only the files in the FileList will
321
 *     be extracted from the cabinet.  EXTRACT_FILLFILELIST can be called
322 323
 *     by itself, but EXTRACT_EXTRACTFILES must have a valid FileList
 *     in order to succeed.  If Operation contains both EXTRACT_FILLFILELIST
324 325
 *     and EXTRACT_EXTRACTFILES, then all the files in the cabinet
 *     will be extracted.
Greg Turner's avatar
Greg Turner committed
326
 */
327
HRESULT WINAPI Extract(SESSION *dest, LPCSTR szCabName)
Greg Turner's avatar
Greg Turner committed
328
{
329 330
    HRESULT res = S_OK;
    HFDI hfdi;
331
    char *str, *end, *path = NULL, *name = NULL;
Greg Turner's avatar
Greg Turner committed
332

333
    TRACE("(%p, %s)\n", dest, debugstr_a(szCabName));
Greg Turner's avatar
Greg Turner committed
334

335 336 337 338 339 340 341 342
    hfdi = FDICreate(mem_alloc,
                     mem_free,
                     fdi_open,
                     fdi_read,
                     fdi_write,
                     fdi_close,
                     fdi_seek,
                     cpuUNKNOWN,
343
                     &dest->Error);
Greg Turner's avatar
Greg Turner committed
344

345 346
    if (!hfdi)
        return E_FAIL;
Greg Turner's avatar
Greg Turner committed
347

348
    if (GetFileAttributesA(dest->Destination) == INVALID_FILE_ATTRIBUTES)
349 350 351 352
    {
        res = S_OK;
        goto end;
    }
353

354 355 356 357 358 359 360 361 362
    /* split the cabinet name into path + name */
    str = HeapAlloc(GetProcessHeap(), 0, lstrlenA(szCabName)+1);
    if (!str)
    {
        res = E_OUTOFMEMORY;
        goto end;
    }
    lstrcpyA(str, szCabName);

363 364
    if ((end = strrchr(str, '\\')))
    {
365
        path = str;
366 367 368 369 370 371 372 373 374 375
        end++;
        name = HeapAlloc( GetProcessHeap(), 0, strlen(end) + 1 );
        if (!name)
        {
            res = E_OUTOFMEMORY;
            goto end;
        }
        strcpy( name, end );
        *end = 0;
    }
376 377
    else
    {
378
        name = str;
379 380 381
        path = NULL;
    }

382 383
    dest->FileSize = 0;

384
    if (!FDICopy(hfdi, name, path, 0,
385
         fdi_notify_extract, NULL, dest))
386
        res = HRESULT_FROM_WIN32(GetLastError());
Greg Turner's avatar
Greg Turner committed
387

388
end:
389 390
    HeapFree(GetProcessHeap(), 0, path);
    HeapFree(GetProcessHeap(), 0, name);
391 392
    FDIDestroy(hfdi);
    return res;
Greg Turner's avatar
Greg Turner committed
393
}