Esempio n. 1
0
/* returns the number of files that are in both the linked list and szFileList */
static DWORD fill_file_list(SESSION *session, LPCSTR szCabName, LPCSTR szFileList)
{
    DWORD dwNumFound = 0;
    struct FILELIST *pNode;

    session->Operation |= EXTRACT_FILLFILELIST;
    if (pExtract(session, szCabName) != S_OK)
    {
        session->Operation &= ~EXTRACT_FILLFILELIST;
        return -1;
    }

    pNode = session->FileList;
    while (pNode)
    {
        if (!file_in_list(pNode->FileName, szFileList))
            pNode->DoExtract = FALSE;
        else
            dwNumFound++;

        pNode = pNode->next;
    }

    session->Operation &= ~EXTRACT_FILLFILELIST;
    return dwNumFound;
}
Esempio n. 2
0
/***********************************************************************
 * Extract (URLMON.@)
 */
HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
{
    HRESULT (WINAPI *pExtract)(void *, LPCSTR);

    if (!hCabinet)
        hCabinet = LoadLibraryA("cabinet.dll");

    if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
    pExtract = (void *)GetProcAddress(hCabinet, "Extract");
    if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());

    return pExtract(dest, szCabName);
}
Esempio n. 3
0
/***********************************************************************
 *             ExtractFilesA    (ADVPACK.@)
 *
 * Extracts the specified files from a cab archive into
 * a destination directory.
 *
 * PARAMS
 *   CabName   [I] Filename of the cab archive.
 *   ExpandDir [I] Destination directory for the extracted files.
 *   Flags     [I] Reserved.
 *   FileList  [I] Optional list of files to extract.  See NOTES.
 *   LReserved [I] Reserved.  Must be NULL.
 *   Reserved  [I] Reserved.  Must be 0.
 *
 * RETURNS
 *   Success: S_OK.
 *   Failure: E_FAIL.
 *
 * NOTES
 *   FileList is a colon-separated list of filenames.  If FileList is
 *   non-NULL, only the files in the list will be extracted from the
 *   cab file, otherwise all files will be extracted.  Any number of
 *   spaces, tabs, or colons can be before or after the list, but
 *   the list itself must only be separated by colons.
 */
HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
                             LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
{   
    SESSION session;
    HMODULE hCabinet;
    HRESULT res = S_OK;
    DWORD dwFileCount = 0;
    DWORD dwFilesFound = 0;
    LPSTR szConvertedList = NULL;

    TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
          Flags, debugstr_a(FileList), LReserved, Reserved);

    if (!CabName || !ExpandDir)
        return E_INVALIDARG;

    if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
        return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);

    hCabinet = LoadLibraryA("cabinet.dll");
    if (!hCabinet)
        return E_FAIL;

    ZeroMemory(&session, sizeof(SESSION));

    pExtract = (void *)GetProcAddress(hCabinet, "Extract");
    if (!pExtract)
    {
        res = E_FAIL;
        goto done;
    }

    lstrcpyA(session.Destination, ExpandDir);

    if (FileList)
    {
        szConvertedList = convert_file_list(FileList, &dwFileCount);
        if (!szConvertedList)
        {
            res = E_FAIL;
            goto done;
        }

        dwFilesFound = fill_file_list(&session, CabName, szConvertedList);
        if (dwFilesFound != dwFileCount)
        {
            res = E_FAIL;
            goto done;
        }
    }
    else
        session.Operation |= EXTRACT_FILLFILELIST;

    session.Operation |= EXTRACT_EXTRACTFILES;
    res = pExtract(&session, CabName);

done:
    free_file_list(&session);
    FreeLibrary(hCabinet);
    HeapFree(GetProcessHeap(), 0, szConvertedList);

    return res;
}
Esempio n. 4
0
static void test_Extract(void)
{
    SESSION session;
    HRESULT res;
    struct FILELIST *node;

    /* native windows crashes if
    *   - invalid parameters are sent in
    *   - you call EXTRACT_EXTRACTFILES without calling
    *     EXTRACT_FILLFILELIST first or at the same time
    */

    /* try to extract all files */
    ZeroMemory(&session, sizeof(SESSION));
    lstrcpyA(session.Destination, "dest");
    session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
    ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
       "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
    ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
    ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
    ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
    free_file_list(&session);

    /* try fill file list operation */
    ZeroMemory(&session, sizeof(SESSION));
    lstrcpyA(session.Destination, "dest");
    session.Operation = EXTRACT_FILLFILELIST;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
    ok(session.Operation == EXTRACT_FILLFILELIST,
       "Expected EXTRACT_FILLFILELIST, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
    ok(check_list(&node, "testdir\\d.txt", TRUE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", TRUE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", TRUE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", TRUE), "list entry wrong\n");

    /* try extract files operation once file list is filled */
    session.Operation = EXTRACT_EXTRACTFILES;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
    ok(session.Operation == EXTRACT_EXTRACTFILES,
       "Expected EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
    ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
    ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
    ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
    ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");

    /* Extract does not extract files if the dest dir does not exist */
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
    ok(session.Operation == EXTRACT_EXTRACTFILES,
       "Expected EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
    ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
    ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");

    /* remove two of the files in the list */
    node = session.FileList->next;
    session.FileList->next = session.FileList->next->next;
    free_file_node(node);
    free_file_node(session.FileList->next->next);
    session.FileList->next->next = NULL;
    session.FilterList = NULL;
    CreateDirectoryA("dest", NULL);
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
    ok(session.Operation == EXTRACT_EXTRACTFILES,
       "Expected EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
    ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
    ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
    ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(!check_list(&node, "a.txt", FALSE), "list entry wrong\n");
    free_file_list(&session);

    session.Operation = EXTRACT_FILLFILELIST;
    session.FileList = NULL;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 8, "Expected 8, got %d\n", session.FileCount);
    ok(session.Operation == EXTRACT_FILLFILELIST,
       "Expected EXTRACT_FILLFILELIST, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
    ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
    ok(check_list(&node, "testdir\\d.txt", TRUE), "list entry wrong\n");
    ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(!check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(!check_list(&node, "a.txt", FALSE), "list entry wrong\n");

    session.Operation = 0;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 8, "Expected 8, got %d\n", session.FileCount);
    ok(session.Operation == 0, "Expected 0, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
    ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
    ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
    ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
    ok(check_list(&node, "testdir\\d.txt", TRUE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", TRUE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", TRUE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", TRUE), "list entry wrong\n");

    session.Operation = 0;
    session.FilterList = session.FileList;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    ok(res == S_OK, "Expected S_OK, got %d\n", res);
    ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
    ok(session.Error.erfOper == FDIERROR_NONE,
       "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
    ok(session.FileCount == 8, "Expected 8, got %d\n", session.FileCount);
    ok(session.Operation == 0, "Expected 0, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
       "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
    ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
    ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
    ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
    node = session.FilterList;
    ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
    free_file_list(&session);

    /* cabinet does not exist */
    ZeroMemory(&session, sizeof(SESSION));
    lstrcpyA(session.Destination, "dest");
    session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
    res = pExtract(&session, "nonexistent.cab");
    node = session.FileList;
    ok(res == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
       "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", res);
    ok(session.Error.erfOper == FDIERROR_CABINET_NOT_FOUND,
       "Expected FDIERROR_CABINET_NOT_FOUND, got %d\n", session.Error.erfOper);
    ok(session.FileSize == 0, "Expected 0, got %d\n", session.FileSize);
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Error.fError == TRUE, "Expected TRUE, got %d\n", session.Error.fError);
    ok(session.FileCount == 0, "Expected 0, got %d\n", session.FileCount);
    ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
       "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!*session.CurrentFile, "Expected empty string, got %s\n", session.CurrentFile);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
    ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
    ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
    ok(!check_list(&node, "testdir\\d.txt", FALSE), "list entry should not exist\n");
    ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry should not exist\n");
    ok(!check_list(&node, "b.txt", FALSE), "list entry should not exist\n");
    ok(!check_list(&node, "a.txt", FALSE), "list entry should not exist\n");
    free_file_list(&session);

    /* first file exists */
    createTestFile("dest\\a.txt");
    SetFileAttributes("dest\\a.txt", FILE_ATTRIBUTE_READONLY);
    ZeroMemory(&session, sizeof(SESSION));
    lstrcpyA(session.Destination, "dest");
    session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    todo_wine
    {
        ok(res == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) || res == E_FAIL,
           "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) or E_FAIL, got %08x\n", res);
        ok(session.FileSize == 6, "Expected 6, got %d\n", session.FileSize);
        ok(session.Error.erfOper == FDIERROR_USER_ABORT,
           "Expected FDIERROR_USER_ABORT, got %d\n", session.Error.erfOper);
        ok(session.Error.fError == TRUE, "Expected TRUE, got %d\n", session.Error.fError);
        ok(session.FileCount == 1, "Expected 1, got %d\n", session.FileCount);
        ok(!lstrcmpA(session.CurrentFile, "dest\\a.txt"),
           "Expected dest\\a.txt, got %s\n", session.CurrentFile);
    }
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
       "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
    todo_wine
    {
        ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
        ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
        ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
        ok(!check_list(&node, "testdir\\d.txt", FALSE), "list entry should not exist\n");
        ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry should not exist\n");
        ok(!check_list(&node, "b.txt", FALSE), "list entry should not exist\n");
    }
    ok(!check_list(&node, "a.txt", FALSE), "list entry should not exist\n");
    free_file_list(&session);

    SetFileAttributesA("dest\\a.txt", FILE_ATTRIBUTE_NORMAL);
    DeleteFileA("dest\\a.txt");

    /* third file exists */
    createTestFile("dest\\testdir\\c.txt");
    SetFileAttributes("dest\\testdir\\c.txt", FILE_ATTRIBUTE_READONLY);
    ZeroMemory(&session, sizeof(SESSION));
    lstrcpyA(session.Destination, "dest");
    session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
    res = pExtract(&session, "extract.cab");
    node = session.FileList;
    todo_wine
    {
        ok(res == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) || res == E_FAIL,
           "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) or E_FAIL, got %08x\n", res);
        ok(session.FileSize == 26, "Expected 26, got %d\n", session.FileSize);
        ok(session.Error.erfOper == FDIERROR_USER_ABORT,
           "Expected FDIERROR_USER_ABORT, got %d\n", session.Error.erfOper);
        ok(session.Error.fError == TRUE, "Expected TRUE, got %d\n", session.Error.fError);
        ok(session.FileCount == 3, "Expected 3, got %d\n", session.FileCount);
        ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\c.txt"),
           "Expected dest\\c.txt, got %s\n", session.CurrentFile);
    }
    ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
    ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
       "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
    ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
    ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
    ok(!session.FilterList, "Expected empty filter list\n");
    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
    ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
    ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
    todo_wine
    {
        ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
        ok(!check_list(&node, "testdir\\d.txt", FALSE), "list entry should not exist\n");
    }
    ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
    ok(!check_list(&node, "b.txt", FALSE), "list entry wrong\n");
    ok(!check_list(&node, "a.txt", TRUE), "list entry wrong\n");
    free_file_list(&session);

    SetFileAttributesA("dest\\testdir\\c.txt", FILE_ATTRIBUTE_NORMAL);
    DeleteFileA("dest\\testdir\\c.txt");

    ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
    ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
}