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

Greg Turner's avatar
Greg Turner committed
21 22
#include "config.h"

23 24 25 26
#include <assert.h>
#include <stdarg.h>
#include <string.h>

Greg Turner's avatar
Greg Turner committed
27 28 29 30 31 32 33 34 35 36 37 38 39
#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);

40

Greg Turner's avatar
Greg Turner committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
/***********************************************************************
 * 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
 */
56
HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
Greg Turner's avatar
Greg Turner committed
57 58 59 60 61 62 63 64 65 66 67 68 69
{
  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;
}

70 71
/* FDI callback functions */

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

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

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

    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;
    }

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

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

    return (INT_PTR) handle;
}

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

    return 0;
}

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

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

    return 0;
}

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

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

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

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

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

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

        pNode = pNode->next;
    }

    return FALSE;
}

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

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

201
            lstrcpyA(szFullPath, pDestination->Destination);
202 203 204 205 206 207 208 209
            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);

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

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

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

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

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

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

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

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

256
                if (hFile != INVALID_HANDLE_VALUE && node)
257
                    node->DoExtract = FALSE;
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 289
            }

            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
290 291 292
/***********************************************************************
 * Extract (CABINET.3)
 *
293 294
 * Extracts the contents of the cabinet file to the specified
 * destination.
Greg Turner's avatar
Greg Turner committed
295 296
 *
 * PARAMS
297
 *   dest      [I/O] Controls the operation of Extract.  See NOTES.
298
 *   szCabName [I] Filename of the cabinet to extract.
Greg Turner's avatar
Greg Turner committed
299 300
 *
 * RETURNS
301 302 303 304 305 306
 *     Success: S_OK.
 *     Failure: E_FAIL.
 *
 * NOTES
 *   The following members of the dest struct control the operation
 *   of Extract:
307 308 309 310 311 312 313 314 315 316
 *       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.
317 318
 *
 *   Operation
319 320 321
 *     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
322
 *     be extracted from the cabinet.  EXTRACT_FILLFILELIST can be called
323 324
 *     by itself, but EXTRACT_EXTRACTFILES must have a valid FileList
 *     in order to succeed.  If Operation contains both EXTRACT_FILLFILELIST
325 326
 *     and EXTRACT_EXTRACTFILES, then all the files in the cabinet
 *     will be extracted.
Greg Turner's avatar
Greg Turner committed
327
 */
328
HRESULT WINAPI Extract(SESSION *dest, LPCSTR szCabName)
Greg Turner's avatar
Greg Turner committed
329
{
330 331
    HRESULT res = S_OK;
    HFDI hfdi;
332
    char *str, *end, *path = NULL, *name = NULL;
Greg Turner's avatar
Greg Turner committed
333

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

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

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

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

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

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

383 384
    dest->FileSize = 0;

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

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