http://bugs.winehq.org/show_bug.cgi?id=10601
--- Comment #15 from Anastasius Focht focht@gmx.net 2008-03-29 06:19:18 --- Hello,
if you want to use default "Windows XP" config for .NET 2.0 installers there are two ways to get it work.
The .NET 2.0 Framework installer checks if the target volume is NTFS filesystem type and then uses the FSCTL_SET_REPARSE_POINT ioctl (used for mount points and junctions) to create junction points for each registered assembly in Windows SxS directory to GAC assembly directory (link target). Basically the junction point is used to redirect access from one directory to another.
--- trace --- 0033:Call KERNEL32.GetVolumeInformationW(7eb5e3d4 L"C:\",00000000,00000000,00000000,7eb5e1c4,7eb5e1c4,7eb5e1c8,00000104) ret=7a13f5bc 0033:trace:vxd:DeviceIoControl (0x284,24000,(nil),0,0x7eb5ddb2,804,0x7eb5e0e8,(nil)) 0033:Ret KERNEL32.GetVolumeInformationW() retval=00000001 ret=7a13f5bc --- trace ---
I first thought they would look at the returned filesystem flags field (flags & FILE_SUPPORTS_REPARSE_POINTS) - but that's not the case. Instead they look directly at returned filesystem name string and compare it to "NTFS". Junction points were introduced with NTFS v3.0 - Windows 2000 and later. There is a check for windows version >= Windows 2000 so NT4 NTFS 2.x targets won't get junctions requests.
The quick fix is to not pretend that target is NTFS volume (fall back to FAT32):
--- snip dlls/kernel32/volume.c ---
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c index 74397a9..5c78fbd 100644 --- a/dlls/kernel32/volume.c +++ b/dlls/kernel32/volume.c @@ -619,7 +619,7 @@ fill_fs_info: /* now fill in the information that depends on the file system ty if (flags) *flags = FILE_CASE_PRESERVED_NAMES; /* FIXME */ break; default: - if (fsname) lstrcpynW( fsname, ntfsW, fsname_len ); + if (fsname) lstrcpynW( fsname, fat32W, fsname_len ); if (filename_len) *filename_len = 255; if (flags) *flags = FILE_CASE_PRESERVED_NAMES; break;
--- snip dlls/kernel32/volume.c ---
The long one: add NTFS junction support to wine (boils down to creation of *nix symlink).
--- snip --- 0049:Call KERNEL32.CreateFileW(7e9fd2fc L"C:\windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a",c0000000,00000003,00000000,00000003,02200000,00000000) ret=79ea0464 0049:Ret KERNEL32.CreateFileW() retval=0000028c ret=79ea0464 0049:Call KERNEL32.lstrlenW(7e9fbfe4 L"C:\windows\WinSxS\x86_System.EnterpriseServices_b03f5f7f11d50a3a_2.0.0.0_x-ww_7d5f3790") ret=7a13f794 0049:Ret KERNEL32.lstrlenW() retval=00000056 ret=7a13f794 0049:Call KERNEL32.lstrlenW(7e9fbdd8 L"\??\C:\windows\WinSxS\x86_System.EnterpriseServices_b03f5f7f11d50a3a_2.0.0.0_x-ww_7d5f3790") ret=7a13f79e 0049:Ret KERNEL32.lstrlenW() retval=0000005a ret=7a13f79e 0049:Call KERNEL32.GetLastError() ret=79e85f0a 0049:Ret KERNEL32.GetLastError() retval=00000000 ret=79e85f0a 0049:Call ntdll.RtlAllocateHeap(00110000,00000000,00000174) ret=79e78360 0049:Ret ntdll.RtlAllocateHeap() retval=00d38dc0 ret=79e78360 0049:Call KERNEL32.DeviceIoControl(0000028c,000900a4,00d38dc0,00000174,00000000,00000000,7e9fbdc4,00000000) ret=7a13f846 0049:fixme:ntdll:server_ioctl_file Unsupported ioctl 900a4 (device=9 access=0 func=29 method=0) 0049:Ret KERNEL32.DeviceIoControl() retval=00000000 ret=7a13f846 0049:Call KERNEL32.GetLastError() ret=7a13f856 0049:Ret KERNEL32.GetLastError() retval=00000032 ret=7a13f856 --- snip ---
"\??\C:\windows\WinSxS\x86_System.EnterpriseServices_b03f5f7f11d50a3a_2.0.0.0_x-ww_7d5f3790" is the native name for the junction.
"C:\windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a" is the redirect (link) target
My first approach was to stub FSCTL_SET_REPARSE_POINT in ntdll.NtFsControlFile() (like FSCTL_LOCK_VOLUME) but this was not enough.
NOTE: the wine definitions of FSCTL_SET_REPARSE_POINT and FSCTL_DELETE_REPARSE_POINT are incorrect or at least not valid for W2K, XP and later. Access type has to be FILE_ANY_ACCESS (0) when building the ioctl code. E.g.: #define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS) -> 0x900a4
--- snip --- 0033:Call KERNEL32.DeviceIoControl(00000284,000900a4,00d3b180,00000174,00000000,00000000,7eb5ddc4,00000000) ret=7a13f846 0033:trace:vxd:DeviceIoControl (0x284,900a4,0xd3b180,372,(nil),0,0x7eb5ddc4,(nil)) 0033:fixme:ntdll:NtFsControlFile stub! return success - Unsupported fsctl 900a4 (device=9 access=0 func=29 method=0) 0033:Ret KERNEL32.DeviceIoControl() retval=00000001 ret=7a13f846 0033:Call KERNEL32.CloseHandle(00000284) ret=7a13f7ca 0033:Ret KERNEL32.CloseHandle() retval=00000001 ret=7a13f7ca 0033:Call KERNEL32.GetLastError() ret=79e782be 0033:Ret KERNEL32.GetLastError() retval=00000000 ret=79e782be .. 0033:Call KERNEL32.lstrlenW(00d3a4f8 L"C:\windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a") ret=79f6d793 0033:Ret KERNEL32.lstrlenW() retval=0000004e ret=79f6d793 0033:Call shlwapi.PathAddBackslashW(00d3a4f8 L"C:\windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a") ret=79f6d7a9 0033:Ret shlwapi.PathAddBackslashW() retval=00d3a596 ret=79f6d7a9 0033:Call KERNEL32.GetFileAttributesExW(00d3a730 L"C:\windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll",00000000,7eb5e82c) ret=7a143d7c 0033:Ret KERNEL32.GetFileAttributesExW() retval=00000000 ret=7a143d7c 0033:Call KERNEL32.GetLastError() ret=7a143d88 0033:Ret KERNEL32.GetLastError() retval=00000002 ret=7a143d88 --- snip ---
Unfortunately after pretending that the junction was created, there is a check if the redirection succeeds by retrieving file attributes for each assembly - so there has to be a real link...
The main problem is actually the conversion of supplied handle to something meaningful for symlink(2). There is no reliable way to get that path name back from the file descriptor. Wine doesn't store this information (object name) anywhere.
So it boils down to unix style file descriptor (and associated inode) vs. systems calls that expect path names. Actually it would be easier if there is *nix symlink() which accepts fd's or inodes as parameter type :-( Maybe the name/path information can be stored in wine server on object creation to be later retrieved by various NtQueryXXX.
Regards