Sync cabinet.dll with Wine HEAD (fixes a memory leak)
[reactos.git] / reactos / dll / win32 / cabinet / cabinet_main.c
index fe2739d..35810e3 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
 
-/* the following defintions are copied from msvcrt/fcntl.h */
-
-#define _O_RDONLY      0
-#define _O_WRONLY      1
-#define _O_RDWR        2
-#define _O_ACCMODE     (_O_RDONLY|_O_WRONLY|_O_RDWR)
-
 
 /***********************************************************************
  * DllGetVersion (CABINET.2)
@@ -91,7 +84,7 @@ static INT_PTR fdi_open(char *pszFile, int oflag, int pmode)
     HANDLE handle;
     DWORD dwAccess = 0;
     DWORD dwShareMode = 0;
-    DWORD dwCreateDisposition = OPEN_EXISTING;
+    DWORD dwCreateDisposition;
 
     switch (oflag & _O_ACCMODE)
     {
@@ -109,10 +102,17 @@ static INT_PTR fdi_open(char *pszFile, int oflag, int pmode)
             break;
     }
 
-    if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
-        dwCreateDisposition = OPEN_EXISTING;
+    if (oflag & _O_CREAT)
+    {
+        dwCreateDisposition = OPEN_ALWAYS;
+        if (oflag & _O_EXCL) dwCreateDisposition = CREATE_NEW;
+        else if (oflag & _O_TRUNC) dwCreateDisposition = CREATE_ALWAYS;
+    }
     else
-        dwCreateDisposition = CREATE_NEW;
+    {
+        dwCreateDisposition = OPEN_EXISTING;
+        if (oflag & _O_TRUNC) dwCreateDisposition = TRUNCATE_EXISTING;
+    }
 
     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
                          dwCreateDisposition, 0, NULL);
@@ -154,21 +154,27 @@ static long fdi_seek(INT_PTR hf, long dist, int seektype)
     return SetFilePointer(handle, dist, NULL, seektype);
 }
 
-static void fill_file_node(struct ExtractFileList *pNode, LPSTR szFilename)
+static void fill_file_node(struct FILELIST *pNode, LPCSTR szFilename)
 {
     pNode->next = NULL;
-    pNode->unknown = TRUE;
+    pNode->DoExtract = FALSE;
 
-    pNode->filename = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
-    lstrcpyA(pNode->filename, szFilename);
+    pNode->FileName = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
+    lstrcpyA(pNode->FileName, szFilename);
 }
 
-static BOOL file_in_list(struct ExtractFileList *pNode, LPSTR szFilename)
+static BOOL file_in_list(struct FILELIST *pNode, LPCSTR szFilename,
+                         struct FILELIST **pOut)
 {
     while (pNode)
     {
-        if (!lstrcmpiA(pNode->filename, szFilename))
+        if (!lstrcmpiA(pNode->FileName, szFilename))
+        {
+            if (pOut)
+                *pOut = pNode;
+
             return TRUE;
+        }
 
         pNode = pNode->next;
     }
@@ -182,17 +188,17 @@ static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pf
     {
         case fdintCOPY_FILE:
         {
-            struct ExtractFileList **fileList;
-            EXTRACTdest *pDestination = pfdin->pv;
+            struct FILELIST *fileList, *node = NULL;
+            SESSION *pDestination = pfdin->pv;
             LPSTR szFullPath, szDirectory;
             HANDLE hFile = 0;
             DWORD dwSize;
 
-            dwSize = lstrlenA(pDestination->directory) +
+            dwSize = lstrlenA(pDestination->Destination) +
                     lstrlenA("\\") + lstrlenA(pfdin->psz1) + 1;
             szFullPath = HeapAlloc(GetProcessHeap(), 0, dwSize);
 
-            lstrcpyA(szFullPath, pDestination->directory);
+            lstrcpyA(szFullPath, pDestination->Destination);
             lstrcatA(szFullPath, "\\");
             lstrcatA(szFullPath, pfdin->psz1);
 
@@ -201,26 +207,33 @@ static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pf
             szDirectory = HeapAlloc(GetProcessHeap(), 0, dwSize);
             lstrcpynA(szDirectory, szFullPath, dwSize);
 
-            if (pDestination->flags & EXTRACT_FILLFILELIST)
-            {
-                fileList = &pDestination->filelist;
-
-                while (*fileList)
-                    fileList = &((*fileList)->next);
-
-                *fileList = HeapAlloc(GetProcessHeap(), 0,
-                                      sizeof(struct ExtractFileList));
+            pDestination->FileSize += pfdin->cb;
 
-                fill_file_node(*fileList, pfdin->psz1);
-                lstrcpyA(pDestination->lastfile, szFullPath);
-                pDestination->filecount++;
+            if (pDestination->Operation & EXTRACT_FILLFILELIST)
+            {
+                fileList = HeapAlloc(GetProcessHeap(), 0,
+                                     sizeof(struct FILELIST));
+
+                fill_file_node(fileList, pfdin->psz1);
+                fileList->DoExtract = TRUE;
+                fileList->next = pDestination->FileList;
+                pDestination->FileList = fileList;
+                lstrcpyA(pDestination->CurrentFile, szFullPath);
+                pDestination->FileCount++;
             }
 
-            if (pDestination->flags & EXTRACT_EXTRACTFILES)
+            if ((pDestination->Operation & EXTRACT_EXTRACTFILES) ||
+                file_in_list(pDestination->FilterList, pfdin->psz1, NULL))
             {
-                /* skip this file it it's not in the file list */
-                if (!file_in_list(pDestination->filelist, pfdin->psz1))
+               /* find the file node */
+                file_in_list(pDestination->FileList, pfdin->psz1, &node);
+
+                if (node && !node->DoExtract)
+                {
+                    HeapFree(GetProcessHeap(), 0, szFullPath);
+                    HeapFree(GetProcessHeap(), 0, szDirectory);
                     return 0;
+                }
 
                 /* create the destination directory if it doesn't exist */
                 if (GetFileAttributesA(szDirectory) == INVALID_FILE_ATTRIBUTES)
@@ -231,6 +244,8 @@ static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pf
 
                 if (hFile == INVALID_HANDLE_VALUE)
                     hFile = 0;
+                else if (node)
+                    node->DoExtract = FALSE;
             }
 
             HeapFree(GetProcessHeap(), 0, szFullPath);
@@ -280,29 +295,32 @@ static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pf
  * NOTES
  *   The following members of the dest struct control the operation
  *   of Extract:
- *       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.
- *       flags     [I] See Operation.
- *       directory [I] The destination directory.
- *       lastfile  [O] The last file extracted.
+ *       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.
  *
  *   Operation
- *     If flags contains EXTRACT_FILLFILELIST, then filelist will be
- *     filled with all the files in the cabinet.  If flags contains
- *     EXTRACT_EXTRACTFILES, then only the files in the filelist will
+ *     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
  *     be extracted from the cabinet.  EXTRACT_FILLFILELIST can be called
- *     by itself, but EXTRACT_EXTRACTFILES must have a valid filelist
- *     in order to succeed.  If flags contains both EXTRACT_FILLFILELIST
+ *     by itself, but EXTRACT_EXTRACTFILES must have a valid FileList
+ *     in order to succeed.  If Operation contains both EXTRACT_FILLFILELIST
  *     and EXTRACT_EXTRACTFILES, then all the files in the cabinet
  *     will be extracted.
  */
-HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR szCabName)
+HRESULT WINAPI Extract(SESSION *dest, LPCSTR szCabName)
 {
     HRESULT res = S_OK;
     HFDI hfdi;
-    ERF erf;
+    char *str, *path, *name;
 
     TRACE("(%p, %s)\n", dest, szCabName);
 
@@ -314,17 +332,44 @@ HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR szCabName)
                      fdi_close,
                      fdi_seek,
                      cpuUNKNOWN,
-                     &erf);
+                     &dest->Error);
 
     if (!hfdi)
         return E_FAIL;
 
-    if (GetFileAttributesA(dest->directory) == INVALID_FILE_ATTRIBUTES)
-        return S_OK;
+    if (GetFileAttributesA(dest->Destination) == INVALID_FILE_ATTRIBUTES)
+    {
+        res = S_OK;
+        goto end;
+    }
+
+    /* split the cabinet name into path + name */
+    str = HeapAlloc(GetProcessHeap(), 0, lstrlenA(szCabName)+1);
+    if (!str)
+    {
+        res = E_OUTOFMEMORY;
+        goto end;
+    }
+    lstrcpyA(str, szCabName);
 
-    if (!FDICopy(hfdi, (LPSTR)szCabName, "", 0,
+    path = str;
+    name = strrchr(path, '\\');
+    if (name)
+        *name++ = 0;
+    else
+    {
+        name = path;
+        path = NULL;
+    }
+
+    dest->FileSize = 0;
+
+    if (!FDICopy(hfdi, name, path, 0,
          fdi_notify_extract, NULL, dest))
-        res = E_FAIL;
+        res = HRESULT_FROM_WIN32(GetLastError());
+
+    HeapFree(GetProcessHeap(), 0, str);
+end:
 
     FDIDestroy(hfdi);