cabinet_main.c 11.1 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 254 255 256 257

                hFile = CreateFileA(szFullPath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                                    CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);

                if (hFile == INVALID_HANDLE_VALUE)
                    hFile = 0;
258 259
                else if (node)
                    node->DoExtract = FALSE;
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 290 291
            }

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

336
    TRACE("(%p, %s)\n", dest, szCabName);
Greg Turner's avatar
Greg Turner committed
337

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

348 349
    if (!hfdi)
        return E_FAIL;
Greg Turner's avatar
Greg Turner committed
350

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

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

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

385 386
    dest->FileSize = 0;

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

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