Driver Problems? Questions? Issues?
Put OSR's experience to work for you! Contact us for assistance with:
  • Creating the right design for your requirements
  • Reviewing your existing driver code
  • Analyzing driver reliability/performance issues
  • Custom training mixed with consulting and focused directly on your specific areas of interest/concern.
Check us out. OSR, the Windows driver experts.

OSR Seminars


Go Back   OSR Online Lists > ntfsd
Welcome, Guest
You must login to post to this list
  Message 1 of 8  
23 Jan 18 01:52
Jorgen Lundman
xxxxxx@lundman.net
Join Date: 09 Nov 2017
Posts To This List: 10
Case sensitivity crossing reparse points

Hello list, Thanks to earlier assistance, I can now mount my filesystem as a "named mount" as opposed to a drive letter. C:\POOL Where "C:\" is standard NTFS OS drive, and "POOL" is the reparse point for my filesystem. Inside the "POOL" directory there is a "HelloWorld" directory. I can see this directory fine, however in attempting to enter it I get failures. It appears to try to IRP_MJ_CREATE on "HELLOWORLD", which will fail as my filesystem is case-sensitive. When my filesystem has a drive letter everything works fine, so it feels like.. .. because C: is case-insensitive, it fails to notice the reparsepoint target is now case-sensitive. Does it not handle changes in capability when crossing reparse-points, or am I not setting it clearly enough somewhere. Is that the case? Is there any way around it? I claim sensitivity with: FILE_FS_ATTRIBUTE_INFORMATION *ffai = Irp->AssociatedIrp.SystemBuffer; ffai->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH | FILE_NAMED_STREAMS | FILE_PERSISTENT_ACLS | /*FILE_SUPPORTS_OBJECT_IDS |*/ FILE_SUPPORTS_SPARSE_FILES | FILE_VOLUME_QUOTAS | FILE_SUPPORTS_REPARSE_POINTS; Lund -- Jorgen Lundman | <xxxxx@lundman.net> Unix Administrator | +81 (0)90-5578-8500 Shibuya-ku, Tokyo | Japan
  Message 2 of 8  
24 Jan 18 22:03
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 989
List Moderator
Case sensitivity crossing reparse points

I keep trying to think of a good response to this, but in reality you?re probably one of very few (if not the first) people to try to mount a case sensitive file system as a reparse point in Windows. If Explorer isn?t handling this properly then you?re probably just out of luck. I can?t think of any reason why it would arbitrarily upcase the name of the folder, but I also don?t really understand anything the shell does on Windows (or any other OS, for that matter)... Presumably you can get to this properly via the command prompt? -scott OSR @OSRDrivers
  Message 3 of 8  
24 Jan 18 22:12
Jorgen Lundman
xxxxxx@lundman.net
Join Date: 09 Nov 2017
Posts To This List: 10
Case sensitivity crossing reparse points

Yeah I might be doing something new. I did notice that IRP_MJ_CREATE could maybe be called without SL_CASE_SENSITIVE - so maybe I can at least detect when this would happen, and pass it down to internal name comparison routines. Or just tell ZFS users on Windows to use casesensitivity=insensitive. For now I'll put it on TODO, most people will probably mount ZFS as its own drive letter, and everything works normally then. Next big challenge is mapping Unix UID to Windows SIDs (or whatever it uses). But first I'll have to go read about it and see if I can figure it out :) Lund xxxxx@osr.com wrote: > I keep trying to think of a good response to this, but in reality you?re > probably one of very few (if not the first) people to try to mount a > case sensitive file system as a reparse point in Windows. If Explorer > isn?t handling this properly then you?re probably just out of luck. I > can?t think of any reason why it would arbitrarily upcase the name of > the folder, but I also don?t really understand anything the shell does > on Windows (or any other OS, for that matter)... > > Presumably you can get to this properly via the command prompt? > <...excess quoted lines suppressed...> -- Jorgen Lundman | <xxxxx@lundman.net> Unix Administrator | +81 (0)90-5578-8500 Shibuya-ku, Tokyo | Japan
  Message 4 of 8  
28 Jan 18 21:48
Malcolm Smith
xxxxxx@operamail.com
Join Date: 12 Sep 2007
Posts To This List: 123
Case sensitivity crossing reparse points

Case sensitivity on Windows is a bit of a mess. The first result when I searched for FILE_CASE_SENSITIVE_SEARCH was: http://www.nicklowe.org/2012/02/understanding-case-sensitivity-in-windows-obcasei nsensitive-file_case_sensitive_search/ Which seems like good background reading. I guess I'd say though that there's three levels of case insensitivity: 1. The system can be forced to cause all toplevel creates to be case insensitive via the obcaseinsensitive regkey. (Note there is no inverse that forces all to be case sensitive.) 2. The file system/volume can indicate that it will process all creates as case insensitive via the absence of FILE_CASE_SENSITIVE_SEARCH. (Note there is no inverse that indicates the volume will process all opens case sensitively.) 3. The thing opening a file can indicate that it wants case sensitive semantics if (1) and (2) allow it to. (Note there is no inverse to insist that all creates will be case sensitive.) There's plenty of code in Windows/Win32/the application ecosystem that assumes case insensitivity. Interpreting opens case sensitively when that behavior was not requested is a flat out bug that will break things. It will break things in the most subtle ways too, like causing fltmgr to incorrectly assume two names resolve to the same name cache entry, and start confusing other filters operating in the stack. Since (1) is set to force case insensitivity by default, it's highly unlikely that any create is set to case sensitive, unless it's coming from the Linux subsystem, which is special. In the specific case here, things are even worse because the create is firstly issued to the volume containing the reparse point and there's no way to indicate that the create should be case insensitive up to the reparse point and case sensitive thereafter. But I think the real issue here is that the create was always a case insensitive create, and that means anything in the stack is entitled to change case. - M On 01/24/2018 07:12 PM, Jorgen Lundman wrote: > > Yeah I might be doing something new. I did notice that IRP_MJ_CREATE could > maybe be called without SL_CASE_SENSITIVE - so maybe I can at least detect > when this would happen, and pass it down to internal name comparison routines. > > Or just tell ZFS users on Windows to use casesensitivity=insensitive. > > For now I'll put it on TODO, most people will probably mount ZFS as its own > drive letter, and everything works normally then. > <...excess quoted lines suppressed...> -- http://www.malsmith.net
  Message 5 of 8  
03 Feb 18 14:37
rbmm
xxxxxx@gmail.com
Join Date: 26 May 2017
Posts To This List: 7
Case sensitivity crossing reparse points

Is there any way around it? yes, but undocumented and only in case IO_REPARSE_TAG_MOUNT_POINT (but not in case IO_REPARSE_TAG_SYMLINK) first of all - why this happens ? this is done by NTFS in NtfsFindStartingNode procedure NTFS uppercase file name during parsing in NtfsFindStartingNode for calculate hash which than used in NtfsFindPrefixHashEntry. also if PrefixHashEntry found - NTFS revert file name component back, by call memmove from NtfsFindPrefixHashEntry. so NTFS usual temporary uppercase file name and than revert it to original form but in case reparse point found - uppercase whole name, but revert back only until reparse name. part after reparse file name left in uppercase in case say \Pool\HelloWorld\XxXx NTFS first convert name to \POOL\HELLOWORLD\XXXX, then revert back to \Pool\HELLOWORLD\XXXX and return STATUS_REPARSE with IO_REPARSE_TAG_MOUNT_POINT in your case and return Tail.Overlay.AuxiliaryBuffer will point to REPARSE_DATA_BUFFER assume that in REPARSE_DATA_BUFFER will be \Pool -> \MyDevice[\SomePath] based on this info IopParseDevice transorm file name and new Irp will be sendto \MyDevice device new file name will be [\SomePath]\HELLOWORLD\XXXX before win7 (or vista - i not check here) when you view request to [\SomePath]\HELLOWORLD\XXXX you can not even know - are user direct open \MyDevice[\SomePath]\HELLOWORLD\XXXX or open via reparse \??\c:\Pool\HELLOWORLD\XXXX but after extra create parameter (ECP) appeared, situation is changed. begin how minimum win7 (i not check on vista) special IopSymlinkECPGuid exist in kernel: struct __declspec(uuid("73d5118a-88ba-439f-92f4-46d38952d250")) IopSymlinkECPGuid; and IopParseDevice attach ECP context of type IopSymlinkECPGuid to Irp after reparse. so now we can know exactly, are create request was via reparse - need check for IopSymlinkECPGuid PECP_LIST EcpList; SYMLINK_ECP_CONTEXT* EcpContext; if (0 <= FsRtlGetEcpListFromIrp(Irp, &EcpList) && EcpList && 0 <= FsRtlFindExtraCreateParameter(EcpList, &__uuidof(IopSymlinkECPGuid), (void**)&EcpContext, 0)){ //... } the context point to next structure: struct SYMLINK_ECP_CONTEXT { USHORT UnparsedNameLength; union { USHORT Flags; struct { USHORT MountPoint : 1; }; }; USHORT DeviceNameLength; USHORT Zero; SYMLINK_ECP_CONTEXT* Reparsed; UNICODE_STRING Name; }; the Flags i not exactly research - in case IO_REPARSE_TAG_MOUNT_POINT (a00000003) low bit is set to 1, Flags == 3 in case IO_REPARSE_TAG_SYMLINK (a000000c) Flags == 2 also exist special case for undocumented reparse tag 80000019 the Name always containing full path (including device name) to file Zero always init to 0 (padding field) DeviceNameLength containing length in bytes of device path in Name in case IO_REPARSE_TAG_MOUNT_POINT: Name containing original file path from open request UnparsedNameLength containing length in bytes of unparsed suffix (path after mount pount component) Reparsed point to linked SYMLINK_ECP_CONTEXT data with Flags = 0, Name containing reparsed file path in case IO_REPARSE_TAG_SYMLINK the UnparsedNameLength and Reparsed is always 0 and Name containing reparsed file path so in case IO_REPARSE_TAG_SYMLINK SYMLINK_ECP_CONTEXT containing much less info compare IO_REPARSE_TAG_MOUNT_POINT. let concrete example: on \Device\HarddiskVolume2 exist mount point : \Pool -> \MyDevice[\SomePath] and somebody try open file \Device\HarddiskVolume2\Pool\HelloWorld\XxXx ----- Irp #1 to \Device\HarddiskVolume2 -------- FileName = \Pool\HelloWorld\XxXx no IopSymlinkECPGuid context NTFS transform FileName to \Pool\HELLOWORLD\XXXX and return (STATUS_REPARSE, IO_REPARSE_TAG_MOUNT_POINT) ----- Irp #2 to \MyDevice -------- FileName = [\SomePath]\HELLOWORLD\XXXX exist IopSymlinkECPGuid context (Flags = 3): Name = \Device\HarddiskVolume2\Pool\HelloWorld\XxXx DeviceNameLength = size of L"\Device\HarddiskVolume2" (not including terminated 0) UnparsedNameLength = sizeof of L"\HelloWorld\XxXx" (not including terminated 0) Reparsed -> IopSymlinkECPGuid context (Flags = 0): Name = \MyDevice[\SomePath]\HELLOWORLD\XXXX DeviceNameLength = size of L"\MyDevice" UnparsedNameLength = 0 Reparsed = 0 so based on this info you can got original unparsed file name (in original case) - \HelloWorld\XxXx and modify file name from [\SomePath]\HELLOWORLD\XXXX to \HelloWorld\XxXx BOOLEAN RevertFileName(PIRP Irp) { PECP_LIST EcpList; SYMLINK_ECP_CONTEXT* EcpContext; if (0 <= FsRtlGetEcpListFromIrp(Irp, &EcpList) && EcpList && 0 <= FsRtlFindExtraCreateParameter(EcpList, &__uuidof(IopSymlinkECPGuid), (void**)&EcpContext, 0) && !FsRtlIsEcpFromUserMode(EcpContext) && EcpContext->MountPoint ) { if (USHORT UnparsedNameLength = EcpContext->UnparsedNameLength) { PUNICODE_STRING FileName = &IoGetCurrentIrpStackLocation(Irp)->FileObject->FileName; USHORT FileNameLength = FileName->Length; USHORT NameLength = EcpContext->Name.Length; if (UnparsedNameLength <= NameLength && UnparsedNameLength <= FileNameLength) { UNICODE_STRING us1 = { UnparsedNameLength, UnparsedNameLength, (PWSTR)RtlOffsetToPointer(FileName->Buffer, FileNameLength - UnparsedNameLength) }; UNICODE_STRING us2 = { UnparsedNameLength, UnparsedNameLength, (PWSTR)RtlOffsetToPointer(EcpContext->Name.Buffer, NameLength - UnparsedNameLength) }; if (RtlEqualUnicodeString(&us1, &us2, TRUE)) { memcpy(us1.Buffer, us2.Buffer, UnparsedNameLength); return TRUE; } } } } return FALSE; } some logs: https://i.imgur.com/fUUFRWM.png https://pastebin.com/nRpZrZtJ https://i.imgur.com/W3ywGUw.png https://pastebin.com/kCvzMRyi https://i.imgur.com/2k0dARs.png https://pastebin.com/geHM893X
  Message 6 of 8  
04 Feb 18 18:50
Jorgen Lundman
xxxxxx@lundman.net
Join Date: 09 Nov 2017
Posts To This List: 10
Case sensitivity crossing reparse points

Thanks, this is quite interesting and it is good to know the cause, and a way to work around it. I especially appreciate the "concrete example" at end. Lund xxxxx@gmail.com wrote: > Is there any way around it? yes, but undocumented and only in case IO_REPARSE_TAG_MOUNT_POINT (but not in case IO_REPARSE_TAG_SYMLINK) > > first of all - why this happens ? this is done by NTFS in NtfsFindStartingNode procedure > NTFS uppercase file name during parsing in NtfsFindStartingNode for calculate hash > which than used in NtfsFindPrefixHashEntry. also if PrefixHashEntry found - NTFS revert file name component back, > by call memmove from NtfsFindPrefixHashEntry. so NTFS usual temporary uppercase file name and than revert it to original form > but in case reparse point found - uppercase whole name, but revert back only until reparse name. > part after reparse file name left in uppercase > > in case say \Pool\HelloWorld\XxXx NTFS first convert name to \POOL\HELLOWORLD\XXXX, then revert back to \Pool\HELLOWORLD\XXXX <...excess quoted lines suppressed...> -- Jorgen Lundman | <xxxxx@lundman.net> Unix Administrator | +81 (0)90-5578-8500 Shibuya-ku, Tokyo | Japan
  Message 7 of 8  
04 Feb 18 19:33
rbmm
xxxxxx@gmail.com
Join Date: 26 May 2017
Posts To This List: 7
Case sensitivity crossing reparse points

i use RevertFileName from minifilter-precreate (with of course replace FsRtlGetEcpListFromIrp to FltGetEcpListFromCallbackData) and it always (in my test on win7,8,10) correct revert name case to original after mount point reparse.
  Message 8 of 8  
13 Feb 18 12:27
Craig Barkhouse
xxxxxx@microsoft.com
Join Date: 08 Feb 2012
Posts To This List: 13
Case sensitivity crossing reparse points

For what it's worth, in the upcoming Windows release (1803? not sure what it will be called), NTFS now correctly preserves the case of the unparsed path. Craig [MSFT] -----Original Message----- From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Jorgen Lundman <xxxxx@lundman.net> Sent: Sunday, February 4, 2018 3:49 PM To: Windows File Systems Devs Interest List <xxxxx@lists.osr.com> Subject: Re: [ntfsd] Case sensitivity crossing reparse points Thanks, this is quite interesting and it is good to know the cause, and a way to work around it. I especially appreciate the "concrete example" at end. Lund xxxxx@gmail.com wrote: > Is there any way around it? yes, but undocumented and only in case > IO_REPARSE_TAG_MOUNT_POINT (but not in case IO_REPARSE_TAG_SYMLINK) > > first of all - why this happens ? this is done by NTFS in > NtfsFindStartingNode procedure NTFS uppercase file name during parsing > in NtfsFindStartingNode for calculate hash which than used in > NtfsFindPrefixHashEntry. also if PrefixHashEntry found - NTFS revert > file name component back, by call memmove from NtfsFindPrefixHashEntry. so NTFS usual temporary uppercase file name and than revert it to original form but in case reparse point found - uppercase whole name, but revert back only until reparse name. > part after reparse file name left in uppercase > <...excess quoted lines suppressed...> -- Jorgen Lundman | <xxxxx@lundman.net> Unix Administrator | +81 (0)90-5578-8500 Shibuya-ku, Tokyo | Japan --- NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers! Details at <https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.osr.com%2Fse minars&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df754d4d70006908d56c29f3c8% 7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C636533849802536315&sdata=ZhlqIYZUiXg DEdLYtLNjVQwdLEWBXfOyO%2BZ7yJp4Mgc%3D&reserved=0> To unsubscribe, visit the List Server section of OSR Online at <https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.osronline.co m%2Fpage.cfm%3Fname%3DListServer&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04d f754d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C6365338498 02536315&sdata=xvEuE0OkCs2RKYPO7L3iP0lLpGyV6GEtbS9jQoSV1nA%3D&reserved=0>
Posting Rules  
You may not post new threads
You may not post replies
You may not post attachments
You must login to OSR Online AND be a member of the ntfsd list to be able to post.

All times are GMT -5. The time now is 15:41.


Copyright ©2015, OSR Open Systems Resources, Inc.
Based on vBulletin Copyright ©2000 - 2005, Jelsoft Enterprises Ltd.
Modified under license