I have name provider functions in my minifilter.
My generate-name function calls:
FltGetFileNameInformation
and then modifies the returned path to re-write server/share info.
This is NOT called when an IRP_MJ_CREATE is processed - maybe because
that could also call IRP_MJ_CREATE and recurse - so no problem, I fixup
filenames directly when processing an IRP_MJ_CREATE.
But during an IRP_MJ_SET_INFORMATION for rename, still my name provider
functions are never called.
But I was expecting that as the rename was processed, that my name
provider functions would get called at least for the target.
Q1. So whats the point of me registering name provider routines if they
only get called when I call them myself directly?
(My normalize function is not being called at all).
So for rename operations too I manually generate a re-written filename
for the source filename and also the destination filename.
On input, the destination filename has the form:
??\p:\path\file.ext
or
??\UNC\server\share\path\file.ext
(I note with interest the contrast between that and normal OPENED
filenames).
But whatever filenames I can think to fix the destination file to,
rename.exe always gives the error:
The process cannot access the file because it is being used by
another process.
A wireshark trace shows exactly the same behaviour as for a working
rename, except that the rename operation is missing, so I presume that
the windows system itself decided that “the” (I guess destination) file
was in use - but based on what I don’t know.
Q2. Any ideas? Or tips on fixups for a rename?
Sam
Hi Sam,
The name provider callbacks are only used by filter manager when a minifilter requests a name. So for a minifilter that wants to virtualize the namespace in any way it needs to do two very different things: it needs to implement proper file system semantics and then it needs to implement name provider callbacks.
In this case, to properly support the rename operation you need to implement proper support for IRP_MJ_CREATE (paying close attention to the SL_OPEN_TARGET_DIRECTORY flag) and then the IRP_MJ_SET_INFORMATION operation. While implementing these you might or might not make use of FltGetFileNameInformation with the FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER flag (meaning that you might use your own name provider callbacks to keep the name mapping logic in one place), depending on your implementation. But the main point of registering name provider callbacks is to work well with other filters that call FltGetFileNameInformation above your filter.
The information you have here is not sufficient for me to be able to figure out exactly what you’re doing wrong. However I have a couple of pointers: a lot of the rename logic relies on properly redirecting IRP_MJ_CREATE to the right file, especially when SL_OPEN_TARGET_DIRECTORY is present. Be aware that when SL_OPEN_TARGET_DIRECTORY is set, FltGetFileNameInformation will not return the full path but the path to the parent directory (i.e. if you see an IRP_MJ_CREATE for “\foo\bar\file.txt” and SL_OPEN_TARGET_DIRECTORY is set, FltGetFileNameInformation will return “\foo\bar” and if your filter simply virtualizes “\foo\bar” to “\virt\foo\bar” and sends the IRP_MJ_CREATE down, now the file system will understand this as a request to open “\virt\foo” because of the SL_OPEN_TARGET_DIRECTORY; what you need to do is remove SL_OPEN_TARGET_DIRECTORY before calling FltGetFileNameInformation so you get the real name, then build your virtualized name to “\virt\foo\bar\file.txt” and then set SL_OPEN_TARGET_DIRECTORY back so that the file system will open the parent directory of file.txt, as desired by the user). This thing tends to make virtualization filters slightly more complicated but makes life easier for all other minifilters so there you have it.
Another thing you simply MUST to do is test with more minifilters that query and DbgPrint names (not necessarily for ALL operations, but at least for IRP_MJ_CREATE and IRP_MJ_SET_INFORMATION) both above and below your filter and log everything they say so you can figure out that everything looks good both above and below your filter. You need to do this as early in the development cycle as possible since issues you’ll find here will often require re-architecting the minifilter. I know I said this in the my other mail but this is important enough that it is worth repeating. This will also give you a lot more information than wireshark and should make debugging easier.
Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.
To my great surprise, when I respect SL_OPEN_TARGET_DIRECTORY, I find
that renames work fine even WITHOUT me fixing up the destination
filename, even though the filename is clearly wrong when I examine it as
it passes through my filter.
It’s great news that the rename still works, but will other filters
maybe will choke because FltGetDestinationFileNameInformation can fail
if the destination directories don’t exist in the un-fixed up
destination server/share?
e.g. if \server\share is reparsed as \localserver\other-share
then \server\share\dir\file will get reparsed as
\localserver\other-share\dir\file
if \dir does not exist on \server\share then
FltGetDestinationFileNameInformation will fail when called on a
destination path of ??\UNC\server\share (as it will appear during
IRP_SET_INFORMATION for a rename).
Sam
* Alexandru Carp wrote, On 30/10/09 16:26:
Hi Sam,
The name provider callbacks are only used by filter manager when a minifilter requests a name. So for a minifilter that wants to virtualize the namespace in any way it needs to do two very different things: it needs to implement proper file system semantics and then it needs to implement name provider callbacks.
In this case, to properly support the rename operation you need to implement proper support for IRP_MJ_CREATE (paying close attention to the SL_OPEN_TARGET_DIRECTORY flag) and then the IRP_MJ_SET_INFORMATION operation. While implementing these you might or might not make use of FltGetFileNameInformation with the FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER flag (meaning that you might use your own name provider callbacks to keep the name mapping logic in one place), depending on your implementation. But the main point of registering name provider callbacks is to work well with other filters that call FltGetFileNameInformation above your filter.
The information you have here is not sufficient for me to be able to figure out exactly what you’re doing wrong. However I have a couple of pointers: a lot of the rename logic relies on properly redirecting IRP_MJ_CREATE to the right file, especially when SL_OPEN_TARGET_DIRECTORY is present. Be aware that when SL_OPEN_TARGET_DIRECTORY is set, FltGetFileNameInformation will not return the full path but the path to the parent directory (i.e. if you see an IRP_MJ_CREATE for “\foo\bar\file.txt” and SL_OPEN_TARGET_DIRECTORY is set, FltGetFileNameInformation will return “\foo\bar” and if your filter simply virtualizes “\foo\bar” to “\virt\foo\bar” and sends the IRP_MJ_CREATE down, now the file system will understand this as a request to open “\virt\foo” because of the SL_OPEN_TARGET_DIRECTORY; what you need to do is remove SL_OPEN_TARGET_DIRECTORY before calling FltGetFileNameInformation so you get the real name, then build your virtualized name to “\virt\foo\bar\file.txt” and th
en set SL_OPEN_TARGET_DIRECTORY back so that the file system will open the parent directory of file.txt, as desired by the user). This thing tends to make virtualization filters slightly more complicated but makes life easier for all other minifilters so there you have it.
Another thing you simply MUST to do is test with more minifilters that query and DbgPrint names (not necessarily for ALL operations, but at least for IRP_MJ_CREATE and IRP_MJ_SET_INFORMATION) both above and below your filter and log everything they say so you can figure out that everything looks good both above and below your filter. You need to do this as early in the development cycle as possible since issues you’ll find here will often require re-architecting the minifilter. I know I said this in the my other mail but this is important enough that it is worth repeating. This will also give you a lot more information than wireshark and should make debugging easier.
Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.
NTFSD is sponsored by OSR
For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
Hello Sam,
You need to fix the destination filename in the FILE_RENAME_INFORMATION structure as well.
In order for the FltGetDestinationFileNameInformation to work properly you need to implement name provider callbacks.
Once you do both then renames and FltGetDestinationFileNameInformation will work properly.
Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.
What puzzles me is that renames (with destination name not rootdir handle) are working without any special handling.
However I have the destination handling code standing by in another branch which I can use.
And doing name provider makes sense so the upper layers see the right name, thanks fr that.
Sam
-----Original Message-----
From: Alexandru Carp
Sent: 02 November 2009 19:06
To: Windows File Systems Devs Interest List
Subject: RE: [ntfsd] relationship between name provider and rename operation
Hello Sam,
You need to fix the destination filename in the FILE_RENAME_INFORMATION structure as well.
In order for the FltGetDestinationFileNameInformation to work properly you need to implement name provider callbacks.
Once you do both then renames and FltGetDestinationFileNameInformation will work properly.
Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.
—
NTFSD is sponsored by OSR
For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
* Alexandru Carp wrote, On 02/11/09 19:06:
Hello Sam,
You need to fix the destination filename in the FILE_RENAME_INFORMATION structure as well.
In order for the FltGetDestinationFileNameInformation to work properly you need to implement name provider callbacks.
Once you do both then renames and FltGetDestinationFileNameInformation will work properly.
I should make clear that I issue a STATUS_REPARSE for the target
(source) filename. Up until the point where I issue the reparse the
source and destination filename will both have passed by some minifilters.
If I implement name provider callbacks and any earlier minifilters call
FltGetDestinationFileNameInformation for the rename, then they will get
the un-reparsed source name but get the re-written destination name.
After the rename request hits my minifilter and I issue STATUS_REPARSE
(replacing destination name? Will it do any good at this point?) then
the rename will traverse the minifilters again, this time with the
source and destination being on the same volume - but this may not be
sufficient if earlier minifilters had already taken action based on the
source and dest being in different volumes.
In the case where RootDir != NULL we also get a problem; RootDir will
already have been re-parsed before being opened, so then earlier filters
will first see a rename with source and dest being on different volumes
until I issue a STATUS_REPARSE for the rename.
I can’t see how to present a consistent picture to other minifilters if
I use STATUS_REPARSE.
Also; if I implement name service providers do I want to issue a
STATUS_REPARSE? And if I implement name service providers should I stop
the names being cached?
For I don’t want to forever mask access to the hidden volumes, only to
re-write access to them in certain cases (which may depend on which
mapped driver letter is being used to access them, and if we manage it,
the security token properties (registry settings of the user) of the
calling process.
I think a name provider gives canonical equivalences based solely on the
file-name and without reference to these other properties.
Sam
* Sam Liddicott wrote, On 03/11/09 08:30:
* Alexandru Carp wrote, On 02/11/09 19:06:
> Hello Sam,
> You need to fix the destination filename in the
> FILE_RENAME_INFORMATION structure as well.
> In order for the FltGetDestinationFileNameInformation to work properly
> you need to implement name provider callbacks.
> Once you do both then renames and FltGetDestinationFileNameInformation
> will work properly.
I should make clear that I issue a STATUS_REPARSE for the target
(source) filename. Up until the point where I issue the reparse the
source and destination filename will both have passed by some minifilters.
If I implement name provider callbacks and any earlier minifilters call
FltGetDestinationFileNameInformation for the rename, then they will get
the un-reparsed source name but get the re-written destination name.
What rubbish I talk. They will also get a re-written source name via the
name provider mechanism.
The questions still remain regarding the cachability of these names if
the re-writing is to depend on things like mapped driver letter (which I
could drop if I had to) or per-user re-write rules.
Also; if I implement name service providers do I want to issue a
STATUS_REPARSE? And if I implement name service providers should I stop
the names being cached?
For I don’t want to forever mask access to the hidden volumes, only to
re-write access to them in certain cases (which may depend on which
mapped driver letter is being used to access them, and if we manage it,
the security token properties (registry settings of the user) of the
calling process.
I think a name provider gives canonical equivalences based solely on the
file-name and without reference to these other properties.
Sam
The main difference (at least one of the main differences) between returning STATUS_REPARSE and implementing “full” virtualization is that in the case of STATUS_REPARSE your minifilter will see requests coming down on BOTH paths (i.e. if you redirect from \a\b to \x\y, in a STATUS_REPARSE minifilter you will see operations on both \a\b (which you will reparse but still should see creates and renames on that path) and \x\y; in a full virtualization filter the \x\y path is usually invisible and only exposed through \a\b so you will never see operations coming down to your minifilter on x\y).
Incidentally, this choice has bearing on how names are cached because on a full virtualization filter a FILE_OBJECT has two names (\a\b\foo above the minifilter and \x\y\foo below the minifilter) which requires some crafty usage of the cache (yes we are working on a sample). In a STATUS_REPARSE virtualizer, there is no FILE_OBJECT for \a\b\foo (since the filter will complete the creates with STATUS_REPARSEs, which means the stream is never actually opened) and the FILE_OBJECTs where things happen have the full name “\x\y\foo” from the top of the IO stack to the bottom (well, at least to the filter… there can always be a virtualization minifilter below yours :). So in this case the name provider doesn’t need to worry about the cache (i.e. always use the cache) and things should just work.
Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.