Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Internals & Software Drivers | 19-23 June 2023 | Live, Online |
Writing WDF Drivers | 10-14 July 2023 | Live, Online |
Kernel Debugging | 16-20 October 2023 | Live, Online |
Developing Minifilters | 13-17 November 2023 | Live, Online |
Comments
Presumably you can get to this properly via the command prompt?
-scott
OSR
@OSRDrivers
-scott
OSR
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
[email protected] 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?
>
> -scott OSR @OSRDrivers
>
> --- NTFSD is sponsored by OSR
>
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers! Details at <http://www.osr.com/seminars>
>
> To unsubscribe, visit the List Server section of OSR Online at
> <http://www.osronline.com/page.cfm?name=ListServer>
>
--
Jorgen Lundman | <[email protected]>
Unix Administrator | +81 (0)90-5578-8500
Shibuya-ku, Tokyo | Japan
searched for FILE_CASE_SENSITIVE_SEARCH was:
http://www.nicklowe.org/2012/02/understanding-case-sensitivity-in-windows-obcaseinsensitive-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.
>
> 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
>
> [email protected] 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?
>>
>> -scott OSR @OSRDrivers
>>
>> --- NTFSD is sponsored by OSR
>>
>>
>> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
>> software drivers! Details at <http://www.osr.com/seminars>
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> <http://www.osronline.com/page.cfm?name=ListServer>
>>
>
--
http://www.malsmith.net
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
way to work around it. I especially appreciate the "concrete example" at end.
Lund
[email protected] 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
> 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
>
>
> ---
> NTFSD is sponsored by OSR
>
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
> Details at <http://www.osr.com/seminars>
>
> To unsubscribe, visit the List Server section of OSR Online at <http://www.osronline.com/page.cfm?name=ListServer>
>
--
Jorgen Lundman | <[email protected]>
Unix Administrator | +81 (0)90-5578-8500
Shibuya-ku, Tokyo | Japan
Craig [MSFT]
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Jorgen Lundman <[email protected]>
Sent: Sunday, February 4, 2018 3:49 PM
To: Windows File Systems Devs Interest List <[email protected]>
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
[email protected] 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 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://na01.safelinks.protection.outlook.com/?url=https://i.img
> ur.com%2FfUUFRWM.png&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df
> 754d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C
> 636533849802526307&sdata=9z5SNgIe6qB47uxjSy6cDBatM8l3Etd8a4tqdII90%2F4
> %3D&reserved=0
> https://na01.safelinks.protection.outlook.com/?url=https://paste
> bin.com%2FnRpZrZtJ&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df75
> 4d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C63
> 6533849802526307&sdata=rCSNHNa1py%2Bmci3viCgiLXGOFoqDuoZrWa29wk0l%2FCw
> %3D&reserved=0
> https://na01.safelinks.protection.outlook.com/?url=https://i.img
> ur.com%2FW3ywGUw.png&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df
> 754d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C
> 636533849802536315&sdata=Z%2B8vMxfVz0DriU%2BJwPaNQxNat2%2FxTVsHdPgyT0%
> 2F7880%3D&reserved=0
> https://na01.safelinks.protection.outlook.com/?url=https://paste
> bin.com%2FkCvzMRyi&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df75
> 4d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C63
> 6533849802536315&sdata=yunEmYl4dODe7rtkNw%2Fh05AELIPiEJ6z9RQ%2Blhmc39Q
> %3D&reserved=0
> https://na01.safelinks.protection.outlook.com/?url=https://i.img
> ur.com%2F2k0dARs.png&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df
> 754d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C
> 636533849802536315&sdata=9JncSZMoRFshzR3SWOr1RscdJKemv%2B1Mj1OxYh9tpAY
> %3D&reserved=0
> https://na01.safelinks.protection.outlook.com/?url=https://paste
> bin.com%2FgeHM893X&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df75
> 4d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C63
> 6533849802536315&sdata=PftwONtVlH%2BJOyStjTaXuY86m2Oe6dmvcb1bCdrbJNM%3
> D&reserved=0
>
>
> ---
> NTFSD is sponsored by OSR
>
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
> Details at
> sr.com%2Fseminars&data=02%7C01%7Ccraigba%40microsoft.com%7Ca13f04df754
> d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589bcd847f1c277%7C1%7C0%7C636
> 533849802536315&sdata=ZhlqIYZUiXgDEdLYtLNjVQwdLEWBXfOyO%2BZ7yJp4Mgc%3D
> &reserved=0>
>
> To unsubscribe, visit the List Server section of OSR Online at
> sronline.com%2Fpage.cfm%3Fname%3DListServer&data=02%7C01%7Ccraigba%40m
> icrosoft.com%7Ca13f04df754d4d70006908d56c29f3c8%7Cee3303d7fb734b0c8589
> bcd847f1c277%7C1%7C0%7C636533849802536315&sdata=xvEuE0OkCs2RKYPO7L3iP0
> lLpGyV6GEtbS9jQoSV1nA%3D&reserved=0>
>
--
Jorgen Lundman | <[email protected]>
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://www.osr.com/seminars&data=02|01|[email protected]|a13f04df754d4d70006908d56c29f3c8|ee3303d7fb734b0c8589bcd847f1c277|1|0|636533849802536315&sdata=ZhlqIYZUiXgDEdLYtLNjVQwdLEWBXfOyO+Z7yJp4Mgc=&reserved=0>
To unsubscribe, visit the List Server section of OSR Online at <https://na01.safelinks.protection.outlook.com/?url=http://www.osronline.com/page.cfm?name=ListServer&data=02|01|[email protected]|a13f04df754d4d70006908d56c29f3c8|ee3303d7fb734b0c8589bcd847f1c277|1|0|636533849802536315&sdata=xvEuE0OkCs2RKYPO7L3iP0lLpGyV6GEtbS9jQoSV1nA=&reserved=0>