[SETUPAPI] Fix extraction of files from a cabinet file using the SetupQueueCopy and...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 31 Dec 2017 01:47:03 +0000 (02:47 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 31 Dec 2017 01:48:58 +0000 (02:48 +0100)
CORE-14164

- Contrary to what Wine thought, this works even if the cabinet file does not have a ".cab" extension.
- Instead of polluting the directory where the cabinet file exists with all the files extracted from it,
  we only extract the needed file to a temporary folder (thus being sure it does not overwrite any other
  existing file with the same name), and then we move the extracted file to its final destination with rename.

dll/win32/setupapi/queue.c

index b556418..060984b 100644 (file)
@@ -362,7 +362,11 @@ static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
 }
 
 
 }
 
 
+#ifndef __REACTOS__
 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
+#else
+static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, LPSTR, LPVOID, DWORD );
+#endif
 
 /***********************************************************************
  *            extract_cabinet_file
 
 /***********************************************************************
  *            extract_cabinet_file
@@ -372,14 +376,21 @@ static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
                                   const WCHAR *src, const WCHAR *dst )
 {
 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
                                   const WCHAR *src, const WCHAR *dst )
 {
+#ifndef __REACTOS__
     static const WCHAR extW[] = {'.','c','a','b',0};
     static const WCHAR extW[] = {'.','c','a','b',0};
+#endif
     static HMODULE advpack;
 
     char *cab_path, *cab_file;
     int len = strlenW( cabinet );
 
     static HMODULE advpack;
 
     char *cab_path, *cab_file;
     int len = strlenW( cabinet );
 
+#ifdef __REACTOS__
+    TRACE("extract_cabinet_file(cab = '%s' ; root = '%s' ; src = '%s' ; dst = '%s')\n",
+          debugstr_w(cabinet), debugstr_w(root), debugstr_w(src), debugstr_w(dst));
+#else
     /* make sure the cabinet file has a .cab extension */
     if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
     /* make sure the cabinet file has a .cab extension */
     if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
+#endif
     if (!pExtractFiles)
     {
         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
     if (!pExtractFiles)
     {
         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
@@ -405,10 +416,74 @@ static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
     if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
     WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
     if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
     WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
+
+#ifdef __REACTOS__
+    {
+    BOOL Success;
+    char *src_file;
+    const WCHAR *src_fileW;
+    WCHAR TempPath[MAX_PATH];
+
+    /* Retrieve the temporary path */
+    if (!GetTempPathW(ARRAYSIZE(TempPath), TempPath))
+    {
+        ERR("GetTempPathW error\n");
+        HeapFree( GetProcessHeap(), 0, cab_file );
+        return FALSE;
+    }
+
+    /* Build the real path to where the file will be extracted */
+    HeapFree( GetProcessHeap(), 0, cab_path );
+    if (!(cab_path = strdupWtoA( TempPath )))
+    {
+        HeapFree( GetProcessHeap(), 0, cab_file );
+        return FALSE;
+    }
+
+    /* Build the file list */
+    src_fileW = strrchrW(src, '\\'); // Find where the filename starts.
+    if (src_fileW) ++src_fileW;
+    else src_fileW = src;
+    /* Convert to ANSI */
+    if (!(src_file = strdupWtoA( src_fileW )))
+    {
+        HeapFree( GetProcessHeap(), 0, cab_file );
+        HeapFree( GetProcessHeap(), 0, cab_path );
+        return FALSE;
+    }
+
+    /* Prepare for the move operation */
+    /* Build the full path to the extracted file, that will be renamed */
+    if (!(src = HeapAlloc( GetProcessHeap(), 0, (strlenW(TempPath) + 1 + strlenW(src_fileW) + 1) * sizeof(WCHAR) )))
+    {
+        HeapFree( GetProcessHeap(), 0, src_file );
+        HeapFree( GetProcessHeap(), 0, cab_file );
+        HeapFree( GetProcessHeap(), 0, cab_path );
+        return FALSE;
+    }
+    concat_W( (WCHAR*)src, NULL, TempPath, src_fileW );
+
+    TRACE("pExtractFiles(cab_file = '%s' ; cab_path = '%s', src_file = '%s')\n",
+          debugstr_a(cab_file), debugstr_a(cab_path), debugstr_a(src_file));
+
+    /* Extract to temporary folder */
+    pExtractFiles( cab_file, cab_path, 0, src_file, NULL, 0 );
+    HeapFree( GetProcessHeap(), 0, src_file );
+    HeapFree( GetProcessHeap(), 0, cab_file );
+    HeapFree( GetProcessHeap(), 0, cab_path );
+
+    /* Move to destination, overwriting the original file if needed */
+    TRACE("Renaming src = '%s' to dst = '%s')\n", debugstr_w(src), debugstr_w(dst));
+    Success = MoveFileExW( src, dst , MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED );
+    HeapFree( GetProcessHeap(), 0, (WCHAR*)src );
+    return Success;
+    }
+#else
     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
     HeapFree( GetProcessHeap(), 0, cab_file );
     HeapFree( GetProcessHeap(), 0, cab_path );
     return CopyFileW( src, dst, FALSE /*FIXME*/ );
     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
     HeapFree( GetProcessHeap(), 0, cab_file );
     HeapFree( GetProcessHeap(), 0, cab_path );
     return CopyFileW( src, dst, FALSE /*FIXME*/ );
+#endif
 }
 
 
 }