Alexandre Julliard : setupapi: Add an extension to support file copies from module resources.

Alexandre Julliard julliard at winehq.org
Wed Nov 11 15:31:42 CST 2020


Module: wine
Branch: master
Commit: 5696c3c23d5be9f5ce57ef7e361d88722120da09
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=5696c3c23d5be9f5ce57ef7e361d88722120da09

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Nov 11 11:03:38 2020 +0100

setupapi: Add an extension to support file copies from module resources.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/setupapi/queue.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 65 insertions(+), 5 deletions(-)

diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c
index eebfe971546..7ed66c298d3 100644
--- a/dlls/setupapi/queue.c
+++ b/dlls/setupapi/queue.c
@@ -19,6 +19,7 @@
  */
 
 #include <stdarg.h>
+#include <stdlib.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -151,8 +152,11 @@ static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
     unsigned int src_len = 1, dst_len = 1;
     WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
 
-    if (op->media) src_len += lstrlenW(op->media->root) + 1;
-    if (op->src_path) src_len += lstrlenW(op->src_path) + 1;
+    if (op->src_file[0] != '@')
+    {
+        if (op->media) src_len += lstrlenW(op->media->root) + 1;
+        if (op->src_path) src_len += lstrlenW(op->src_path) + 1;
+    }
     if (op->src_file) src_len += lstrlenW(op->src_file) + 1;
     if (op->dst_path) dst_len += lstrlenW(op->dst_path) + 1;
     if (op->dst_file) dst_len += lstrlenW(op->dst_file) + 1;
@@ -170,7 +174,10 @@ static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
         paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
     }
     if (!source || !target) return FALSE;
-    concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file );
+    if (op->src_file[0] != '@')
+        concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file );
+    else
+        lstrcpyW( source, op->src_file );
     concat_W( target, NULL, op->dst_path, op->dst_file );
     paths->Win32Error = 0;
     paths->Flags      = 0;
@@ -1002,6 +1009,59 @@ static BOOL create_full_pathW(const WCHAR *path)
     return ret;
 }
 
+static BOOL copy_file( LPCWSTR source, LPCWSTR target )
+{
+    WCHAR module[MAX_PATH];
+    HMODULE mod = NULL;
+    HRSRC res;
+    HGLOBAL data;
+    HANDLE handle;
+    DWORD size, written;
+    BOOL ret = FALSE;
+    int id = 0;
+    const WCHAR *p;
+
+    TRACE( "%s -> %s\n", debugstr_w(source), debugstr_w(target) );
+
+    if (source[0] != '@') return CopyFileW( source, target, FALSE );
+
+    /* Wine extension: when the source of a file copy is in the format "@file.dll,-123"
+     * the source data is extracted from the corresponding file.dll resource */
+
+    source++;  /* skip '@' */
+    p = wcschr( source, ',' );
+    if (!p || p - source >= MAX_PATH)
+    {
+        SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
+        return FALSE;
+    }
+    memcpy( module, source, (p - source) * sizeof(WCHAR) );
+    module[p - source] = 0;
+    id = -wcstol( p + 1, NULL, 10 );
+    if (id <= 0 || id > 0xffff ||
+        !(mod = LoadLibraryExW( module, 0, LOAD_LIBRARY_AS_DATAFILE )) ||
+        !(res = FindResourceW( mod, MAKEINTRESOURCEW(id), L"WINE_DATA_FILE" )) ||
+        !(data = LoadResource( mod, res )))
+    {
+        WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
+        if (mod) FreeLibrary( mod );
+        SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
+        return FALSE;
+    }
+    size = SizeofResource( mod, res );
+    if ((handle = CreateFileW( target, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                               CREATE_ALWAYS, 0, 0 )) == INVALID_HANDLE_VALUE)
+    {
+        WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
+        if (mod) FreeLibrary( mod );
+        return FALSE;
+    }
+    ret = WriteFile( handle, LockResource(data), size, &written, NULL ) && written == size;
+    CloseHandle( handle );
+    if (!ret) DeleteFileW( target );
+    return ret;
+}
+
 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style, 
                            PSP_FILE_CALLBACK_W handler, PVOID context )
 {
@@ -1124,7 +1184,7 @@ static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
 
     if (docopy)
     {
-        rc = CopyFileW(source,target,FALSE);
+        rc = copy_file( source, target );
         if (!rc && GetLastError() == ERROR_SHARING_VIOLATION &&
             (style & SP_COPY_IN_USE_NEEDS_REBOOT))
         {
@@ -1134,7 +1194,7 @@ static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
             if (GetTempPathW(MAX_PATH, temp) &&
                 GetTempFileNameW(temp, L"SET", 0, temp_file))
             {
-                rc = CopyFileW(source, temp_file, FALSE);
+                rc = copy_file( source, temp_file );
                 if (rc)
                     rc = MoveFileExW(temp_file, target, MOVEFILE_DELAY_UNTIL_REBOOT);
                 else




More information about the wine-cvs mailing list