Skip to content

Commit

Permalink
setupapi: Compare dll files before overwriting them.
Browse files Browse the repository at this point in the history
This is mainly to prevent us from clobbering reflinks created by
the proton script, and to make sure dll symlinks (which we can't
overwrite) are still registered properly.
  • Loading branch information
madewokherd authored and ivyl committed Mar 30, 2022
1 parent cd67ddd commit 3caf432
Showing 1 changed file with 138 additions and 13 deletions.
151 changes: 138 additions & 13 deletions dlls/setupapi/fakedll.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ static const WCHAR *enum_load_path( unsigned int idx )
}

/* try to load a pre-compiled fake dll */
static void *load_fake_dll( const WCHAR *name, SIZE_T *size )
static void *load_fake_dll( const WCHAR *name, SIZE_T *size, WCHAR **out_filename )
{
const WCHAR *build_dir = _wgetenv( L"WINEBUILDDIR" );
const WCHAR *path;
Expand Down Expand Up @@ -473,11 +473,94 @@ static void *load_fake_dll( const WCHAR *name, SIZE_T *size )
}

done:
if (res == 1)
{
*out_filename = HeapAlloc( GetProcessHeap(), 0, (wcslen( ptr ) + 1) * sizeof(WCHAR) );
wcscpy( *out_filename, ptr );
HeapFree( GetProcessHeap(), 0, file );
return data;
}
HeapFree( GetProcessHeap(), 0, file );
if (res == 1) return data;
return NULL;
}

/* Check if the 2 files are already the same */
static BOOL fake_dll_matches( const WCHAR *source, const WCHAR *dest )
{
WIN32_FILE_ATTRIBUTE_DATA data1, data2;
HANDLE h;
char *buf;
DWORD size, bytesread;
BOOL result;

if (!GetFileAttributesExW( source, GetFileExInfoStandard, &data1 ))
return FALSE;

if (!GetFileAttributesExW( dest, GetFileExInfoStandard, &data2 ))
return FALSE;

if ((data2.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT)
/* If it's a symlink, assume it was put there by the proton script and is therefore correct */
return TRUE;

if (data1.nFileSizeHigh != 0 ||
data2.nFileSizeHigh != 0 ||
data1.nFileSizeLow != data2.nFileSizeLow)
{
return FALSE;
}

size = data1.nFileSizeLow;

/* If size and mtime matches, don't bother comparing contents */
if ((data1.ftLastWriteTime.dwLowDateTime != 0 || data1.ftLastWriteTime.dwHighDateTime != 0) &&
data1.ftLastWriteTime.dwLowDateTime == data2.ftLastWriteTime.dwLowDateTime &&
data1.ftLastWriteTime.dwHighDateTime == data2.ftLastWriteTime.dwHighDateTime)
return TRUE;

buf = HeapAlloc( GetProcessHeap(), 0, size * 2 );

if (!buf)
return FALSE;

h = CreateFileW( source, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
if (h == INVALID_HANDLE_VALUE)
{
HeapFree( GetProcessHeap(), 0, buf );
return FALSE;
}

if (!ReadFile( h, buf, size, &bytesread, NULL ) || bytesread != size)
{
CloseHandle( h );
HeapFree( GetProcessHeap(), 0, buf );
return FALSE;
}

CloseHandle( h );

h = CreateFileW( dest, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
if (h == INVALID_HANDLE_VALUE)
{
HeapFree( GetProcessHeap(), 0, buf );
return FALSE;
}

if (!ReadFile( h, buf + size, size, &bytesread, NULL ) || bytesread != size)
{
CloseHandle( h );
HeapFree( GetProcessHeap(), 0, buf );
return FALSE;
}

CloseHandle( h );

result = !memcmp( buf, buf + size, size );

HeapFree( GetProcessHeap(), 0, buf );
return result;
}

/* create the fake dll destination file */
static HANDLE create_dest_file( const WCHAR *name, BOOL delete )
{
Expand Down Expand Up @@ -928,7 +1011,11 @@ static int install_fake_dll( WCHAR *dest, WCHAR *file, BOOL delete, struct list
destname[len] = 0;
if (!add_handled_dll( destname )) ret = -1;

if (ret != -1)
if (ret != -1 && fake_dll_matches( file, dest ))
{
register_fake_dll( dest, data, size, delay_copy );
}
else if (ret != -1)
{
HANDLE h = create_dest_file( dest, delete );

Expand Down Expand Up @@ -971,6 +1058,13 @@ static void delay_copy_files( struct list *delay_copy )
LIST_FOR_EACH_ENTRY_SAFE( copy, next, delay_copy, struct delay_copy, entry )
{
list_remove( &copy->entry );

if ( fake_dll_matches( copy->src, copy->dest ) )
{
HeapFree( GetProcessHeap(), 0, copy );
continue;
}

ret = read_file( copy->src, &data, &size );
if (ret != 1)
{
Expand Down Expand Up @@ -1080,6 +1174,7 @@ BOOL create_fake_dll( const WCHAR *name, const WCHAR *source )
BOOL ret;
SIZE_T size;
const WCHAR *filename;
WCHAR *source_filename;
void *buffer;
BOOL delete = !wcscmp( source, L"-" ); /* '-' source means delete the file */

Expand All @@ -1096,25 +1191,55 @@ BOOL create_fake_dll( const WCHAR *name, const WCHAR *source )

add_handled_dll( filename );

if (!(h = create_dest_file( name, delete ))) return TRUE; /* not a fake dll */
if (h == INVALID_HANDLE_VALUE) return FALSE;
if (delete)
{
if (!(h = create_dest_file( name, delete ))) return TRUE; /* not a fake dll */
if (h == INVALID_HANDLE_VALUE) return FALSE;

/* '-' source means delete the file */
TRACE( "deleting %s\n", debugstr_w(name) );
ret = FALSE;

if ((buffer = load_fake_dll( source, &size )))
CloseHandle( h );
DeleteFileW( name );
}
else if ((buffer = load_fake_dll( source, &size, &source_filename )))
{
DWORD written;
if (fake_dll_matches( source_filename, name ))
{
HeapFree( GetProcessHeap(), 0, source_filename );

register_fake_dll( name, buffer, size, &delay_copy );
ret = TRUE;
}
else
{
DWORD written;

HeapFree( GetProcessHeap(), 0, source_filename );

ret = (WriteFile( h, buffer, size, &written, NULL ) && written == size);
if (ret) register_fake_dll( name, buffer, size, &delay_copy );
else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name), GetLastError() );
if (!(h = create_dest_file( name, FALSE ))) return TRUE; /* not a fake dll */
if (h == INVALID_HANDLE_VALUE) return FALSE;

ret = (WriteFile( h, buffer, size, &written, NULL ) && written == size);
if (ret) register_fake_dll( name, buffer, size, &delay_copy );
else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name), GetLastError() );

CloseHandle( h );
if (!ret) DeleteFileW( name );
}
}
else
{
if (!(h = create_dest_file( name, FALSE ))) return TRUE; /* not a fake dll */
if (h == INVALID_HANDLE_VALUE) return FALSE;

WARN( "fake dll %s not found for %s\n", debugstr_w(source), debugstr_w(name) );
ret = build_fake_dll( h, name );
}

CloseHandle( h );
if (!ret) DeleteFileW( name );
CloseHandle( h );
if (!ret) DeleteFileW( name );
}

delay_copy_files( &delay_copy );
return ret;
Expand Down

0 comments on commit 3caf432

Please sign in to comment.