https://bugs.winehq.org/show_bug.cgi?id=45930
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Component|-unknown |fusion
--- Comment #2 from Anastasius Focht focht@gmx.net --- Hello Louis,
--- quote --- Do I get it right that you're suggesting here that adding the creation of this dir to wine.inf is not a correct fix? If so, maybe a wine.inf patch would still be ok for Staging? --- quote ---
this directory doesn't exist on old Windows versions (Windows XP) without any .NET Frameworks installed. Newer Windows versions (Vista/7+) already ship certain versions of .NET Frameworks pre-installed "OS component":
https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/versions-a...
The MSI installer triggers the creation of this legacy GAC root path. Searching the Shared Source CLI 2.0 repository on Github I found one possible location:
https://github.com/fixdpt/shared-source-cli-2.0/blob/d63349c09c2e93e4bfc4c8b...
--- snip --- HRESULT LockCacheDir(CACHE_FLAGS dwCacheFlags, LPCWSTR pwzLockFile, HANDLE *phLock) { HRESULT hr = S_OK; DWORD dwErr = 0; HANDLE hLock = INVALID_HANDLE_VALUE; DWORD dwWaitTime = 0; DWORD dwFileFlags = 0; DWORD dwRetry = 0;
_ASSERTE(IsGacType(dwCacheFlags) || (dwCacheFlags == CACHE_DOWNLOAD)); _ASSERTE(pwzLockFile); _ASSERTE(*pwzLockFile); _ASSERTE(phLock);
if (IsGacType(dwCacheFlags)) { hr = CreateFilePathHierarchy(pwzLockFile); if (FAILED(hr)) { goto Exit; } } --- snip ---
CreateFilePathHierarchy() -> https://github.com/fixdpt/shared-source-cli-2.0/blob/d63349c09c2e93e4bfc4c8b... -> will create the GAC root folder due to lock file creation.
LockCacheDir() is called by Lock() -> https://github.com/fixdpt/shared-source-cli-2.0/blob/d63349c09c2e93e4bfc4c8b...
Lock() is member of CMutex class which is used in many places as scoped lock.
I looked again multiple times at the trace log and finally it made *click*.
--- snip --- ... 00b2:Call KERNEL32.LoadLibraryW(007a0dc0 L"C:\windows\Microsoft.NET\Framework\v4.0.30319\fusion.dll") ret=1001233c 00b2:Call PE DLL (proc=0xf7b8a830,module=0xf7b80000 L"fusion.dll",reason=WINE_PREATTACH,res=(nil)) 00b2:Ret PE DLL (proc=0xf7b8a830,module=0xf7b80000 L"fusion.dll",reason=WINE_PREATTACH,res=(nil)) retval=1 ... 00b2:Call PE DLL (proc=0xf7b8a830,module=0xf7b80000 L"fusion.dll",reason=PROCESS_ATTACH,res=(nil)) ... 00b2:Ret PE DLL (proc=0xf7b8a830,module=0xf7b80000 L"fusion.dll",reason=PROCESS_ATTACH,res=(nil)) retval=1 00b2:Ret KERNEL32.LoadLibraryW() retval=f7b80000 ret=1001233c 00b2:Call KERNEL32.GetProcAddress(f7b80000,10004a8c "CreateAssemblyCache") ret=10012384 00b2:Ret KERNEL32.GetProcAddress() retval=f7b83c58 ret=10012384 00b2:Call fusion.CreateAssemblyCache(0045f280,00000000) ret=100123b2 ... 00b2:Call KERNEL32.CreateMutexW(00000000,00000000,f7b8b080 L"__WINE_FUSION_CACHE_MUTEX__") ret=f7b8589d 00b2:Ret KERNEL32.CreateMutexW() retval=00000070 ret=f7b8589d 00b2:Ret fusion.CreateAssemblyCache() retval=00000000 ret=100123b2 --- snip ---
That's of course Wine's builtin fusion at work here.
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/fusion/asmcache.c#l41...
IAssemblyCacheImpl_InstallAssembly -> get_assembly_directory() -> create_full_path()
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/fusion/asmcache.c#l10...
The .NET CLR installer expects its own fusion implementation (CLR Fusion, see shared-source-cli-2.0) to be loaded here and do the work which creates also the legacy GAC roots/caches (for native images).
Preventing builtin from being loaded shows indeed:
--- snip --- $ WINEDLLOVERRIDES=fusion=n WINEDEBUG=+seh,+relay,+msi wine ./dotNetFx40_Full_x86_x64.exe >>log.txt 2>&1 ... 00b2:Ret PE DLL (proc=0x604a321f,module=0x604a0000 L"fusion.dll",reason=PROCESS_ATTACH,res=(nil)) retval=1 00b2:Ret KERNEL32.LoadLibraryW() retval=604a0000 ret=1001233c 00b2:Call KERNEL32.GetProcAddress(604a0000,10004a8c "CreateAssemblyCache") ret=10012384 00b2:Ret KERNEL32.GetProcAddress() retval=008b0033 ret=10012384 ... 00b2:Call KERNEL32.LoadLibraryExW(0045ef94 L"C:\windows\Microsoft.NET\Framework\v4.0.30319\clr.dll",00000000,00000008) ret=604a2b07 00b2:Call PE DLL (proc=0x790851d4,module=0x79060000 L"MSVCR100_CLR0400.dll",reason=PROCESS_ATTACH,res=(nil)) ... 00b2:Call PE DLL (proc=0x791f58f0,module=0x79140000 L"clr.dll",reason=PROCESS_ATTACH,res=(nil)) ... 00b2:Call KERNEL32.CreateFileW(00160fe0 L"C:\windows\Microsoft.NET\Framework\v4.0.30319\ISymWrapper.dll",80000000,00000005,00000000,00000003,00000080,00000000) ret=792e90be 00b2:Ret KERNEL32.CreateFileW() retval=00000070 ret=792e90be ... 00b2:Call KERNEL32.CreateDirectoryW(0045e13c L"C:\windows\assembly",00000000) ret=7927aacc 00b2:Ret KERNEL32.CreateDirectoryW() retval=00000001 ret=7927aacc 00b2:Call KERNEL32.CreateFileW(0045e384 L"C:\windows\assembly\GACLock.dat",40000000,00000000,00000000,00000002,04000104,00000000) ret=7926e15d 00b2:Ret KERNEL32.CreateFileW() retval=0000007c ret=7926e15d ... --- snip ---
Installer custom action dll 'InstallAssembly' -> fusion.CreateAssemblyCache -> clr.CreateAssemblyCache ...
There we go - legacy GAC root created as expected, triggered by GAC lock file (corresponding to source).
It fails later though:
--- snip --- ... 00b6:Call KERNEL32.CreateFileW(0045e69c L"C:\windows\Microsoft.Net\assembly\GAC_32\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a",c0000000,00000003,00000000,00000003,02200000,00000000) ret=794b1d64 00b6:Ret KERNEL32.CreateFileW() retval=00000080 ret=794b1d64 ... 00b6:Call KERNEL32.DeviceIoControl(00000080,000900a4,0016c4b0,00000174,00000000,00000000,0045d164,00000000) ret=794b1e60 00b6:fixme:ntdll:server_ioctl_file Unsupported ioctl 900a4 (device=9 access=0 func=29 method=0) 00b6:Ret KERNEL32.DeviceIoControl() retval=00000000 ret=794b1e60 00b6:Call KERNEL32.GetLastError() ret=794b1e6e 00b6:Ret KERNEL32.GetLastError() retval=00000032 ret=794b1e6e ... 0079:trace:msi:MSI_ProcessMessageVerbatim Calling UI handler 0x1004bf8a(pvContext=0x103fcd8, iMessageType=04000000, szMessage=L"Info 0.10/08/18 21:25:05 DDSet_Error: Failed to install assembly 'C:\windows\Microsoft.NET\Framework\v4.0.30319\System.EnterpriseServices.dll' because of system error: Request not supported.\r\n") ... 00b6:Call msi.MsiRecordSetStringW(00000001,00000000,0045e394 L"There is a problem with this Windows Installer package. Please refer to the setup log for more information.\r\n") ret=1002bae1 ... 0079:trace:msi:MSI_ProcessMessageVerbatim Calling UI handler 0x1004bf8a(pvContext=0x103fcd8, iMessageType=04000000, szMessage=L"Info 0.10/08/18 21:25:05 DDSet_Exit: InstallAssembly ended with return value 1603") ... 0031:err:msi:execute_script Execution of script 0 halted; action L"[C:\windows\Microsoft.NET\Framework\v4.0.30319\;C:\windows\Microsoft.NET\Framework\v4.0.30319\System.EnterpriseServices.dll;246128<=>S-1-5-21-0-0-0-1000<=>{3C3901C5-3455-3E0A-A214-0B093A5070A6}]CA_InstallAssemblyDef.3643236F_FC70_11D3_A536_0090278A1BB8" returned 1603 ... 0031:err:msi:ITERATE_Actions Execution halted, action L"InstallFinalize" returned 1603 --- snip ---
Unfortunately we run into our old friend here: bug 12401 ("NET Framework 2.0, 3.0, 4.0 installers and other apps that make use of GAC API for managed assembly installation need reparse point/junction API support, i.e. DeviceIoCtl(FSCTL_SET_REPARSE_POINT/FSCTL_GET_REPARSE_POINT)").
A workaround/compromise could be that Wine's fusion also creates the legacy GAC cache/root folder by default so that scheduled native NGEN/mscorsvc runs will succeed on all assemblies.
Regards