I am working on minifilter driver, which is used for monitoring and reparse the files/folders. I am using the the function ‘FltGetFileNameInformation’ as per below.
But the issue is when my drive is installed and loaded and if i go for installations of multiple products randomly after some installations task managers starts showing CPU usage to 100% for executable likes TrustedInstaller.exe or for svchost.exe.
If I use the function ‘FltGetFileNameInformation’ as per below.
Everything is fine no CPU usage goes to 100%, but in this case as ‘FLT_FILE_NAME_OPENED’ could give some file path in short name format (eg:-c:\admi~1\test) where as I wanted them as in long name format (eg:-c:\administrator\test).
My requirement is that to get the file path in long name format in all the above callbacks, please let me know whether I should go for ‘FLT_FILE_NAME_NORMALIZED’ or ‘FLT_FILE_NAME_OPENED’ or there is any other way to get it. Currently I am working on Windows 7 - 32 bit OS.
I don’t know how expensive is FltGetFilenameInformation routine.
Instead of querying filename information for each callback, why don’t you just query it on PreCreateCallback once and store the filename on stream context. For other callbacks, you just need to get the stream context back.
I have tried to create the file context in PreCreateCallback and found that it function 'FltSetFileContext' always fails with return value 'STATUS_NOT_SUPPORTED'. Then after I have found the WDK documentation as per below.
"Be aware that FltSetFileContext cannot be called on an unopened FileObject. Hence FltSetFileContext cannot be called from a pre-create callback for a stream because the stream has not been opened at that point. A minifilter driver can, however, allocate and set up the stream file context in the pre-create callback, pass it to the post-create callback using the completion context parameter and set the stream file context on the file corresponding to that stream in the post-create callback."
And in my case as I am reparsing the new creating files in PreCreateCallback and completing the callback as per below
“For file systems (such as FAT) that support only a single data stream per file, file contexts are equivalent to stream contexts”
During PreCreate, you should get the filename and either return STATUS_REPARSE or FLT_PREOP_SUCCESS_WITH_CALLBACK depends on some checks of your own whether the file has been reparsed or not. When filter manager sees STATUS_REPARSE, it will reissue the same IRP_MJ_CREATE with new filename you set. Then return FLT_PREOP_SUCCESS_WITH_CALLBACK and pass the filename to PostCreate using CompletionContext.
On PostCreate, check your create IoStatus and set your stream context there.
I’m not sure a context will help you since FltMgr has a name cache that does pretty much what you’re trying to do, complete with invalidation at the appropriate times and so on. Personally I would do this differently, where instead of getting the file name every time I would instead record the operations per FILE_OBJECT and when actually writing the log I would use the FILE_OBJECT as a key into a hash of names (or something along those lines).
Also please note that you don’t really return STATUS_REPARSE from the preCreate callback, instead you set the FLT_CALLBACK_DATA->IoStatus.Status to STATUS_REPARSE and return FLT_PREOP_COMPLETE. There is also a WDK sample that shows how this is done.
Thanks,
Alex.
On Jun 13, 2013, at 7:41 AM, Syahmi Azhar wrote:
> Hi Pravin, > > I didn’t explain well before. > > You should instead use stream context, not file context. I quote some text from here: > http://msdn.microsoft.com/en-us/library/windows/hardware/ff540438(v=vs.85).aspx > > “For file systems (such as FAT) that support only a single data stream per file, file contexts are equivalent to stream contexts” > > During PreCreate, you should get the filename and either return STATUS_REPARSE or FLT_PREOP_SUCCESS_WITH_CALLBACK depends on some checks of your own whether the file has been reparsed or not. When filter manager sees STATUS_REPARSE, it will reissue the same IRP_MJ_CREATE with new filename you set. Then return FLT_PREOP_SUCCESS_WITH_CALLBACK and pass the filename to PostCreate using CompletionContext. > > On PostCreate, check your create IoStatus and set your stream context there. > > > Syahmi > > — > NTFSD is sponsored by OSR > > OSR is hiring!! Info at http://www.osr.com/careers > > For our schedule of debugging and file system seminars 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
FLT_FILE_NAME_NORMALIZED name queries are horrifically expensive - especially for paths that contain a lot of subfolders or for network drives. As Alex pointed out - the cost is typically incurred on the first call since subsequent queries will read from the name cache. I say typically because there are some scenarios when name caching may be disabled for one or more volumes. This would be the case for example when there is a legacy filter between filter manager and the filesystem.
There are functions that you can use to query for long names (both in usermode and kernel mode) but be aware that these might be no better - the normalized query is expensive for a reason after all. At least using one of these might allow you to only query for the long name in the relatively rare cases when the opened name returns the short name so you can call it condtionally rather than always querying for the normalized name ??
“FLT_FILE_NAME_NORMALIZED name queries are horrifically expensive” - for the archives I’d like to point out that in Win8 the performance is significantly better, on par with opened names. Also performance can be worse in some cases when querying the name in preCreate and the cache isn’t available in preCreate either, so it might be worth trying very hard to only query the name after the file is opened (postCreate and after?) (for example in your case perhaps you could wait until postCreate to query the normalized name and try to do the reparse just with the opened name?).
In terms of querying the opened name and only querying the normalized name when necessary, if I remember correctly this is also how FltMgr does things (in other words it won’t normalize things that simply cannot be short names).
Thanks,
Alex.
On Jun 14, 2013, at 12:53 PM, xxxxx@gmail.com wrote:
FLT_FILE_NAME_NORMALIZED name queries are horrifically expensive - especially for paths that contain a lot of subfolders or for network drives. As Alex pointed out - the cost is typically incurred on the first call since subsequent queries will read from the name cache. I say typically because there are some scenarios when name caching may be disabled for one or more volumes. This would be the case for example when there is a legacy filter between filter manager and the filesystem.
There are functions that you can use to query for long names (both in usermode and kernel mode) but be aware that these might be no better - the normalized query is expensive for a reason after all. At least using one of these might allow you to only query for the long name in the relatively rare cases when the opened name returns the short name so you can call it condtionally rather than always querying for the normalized name ??
In my case i am using ‘FltGetFileNameInformation’ along with ‘FLT_FILE_NAME_OPENED’ and its working fine for me. Only the few cases like, some time i am getting file/folder path in short name format(eg:- c:\admi~1\test). So for these cases i am converting the short name into long name using function ‘ZwQueryDirectoryFile’.
I construct the path manually in pre-create, because
FltGetFileNameInformation with FLT_FILE_NAME_OPENED, I think, converts
network DeviceObjects to little different paths (e.g. user opens
\Device\LanmanRedirector, \Device\Mup; or ;X:00…0\computer\share\realpath, but FltGetFileNameInformation returns unified format, or strips something from these paths or from RelatedFileObject’s path). I don’t remember if it’s XP or Vista+ thing, but it was the reason I do that manually.
As for short path components, I find SFN separator (e.g. progra~1) and convert the path component to LFN (with ZwQueryDirectoryFile). Some drivers call FltGetFileNameInformation with FLT_FILE_NAME_NORMALIZED flag in this case, I’m not sure what’s faster. I check SFNs only on volumes which can actually use them. In Windows 7 you can enable/disable SFNs on a per-volume basis, but Windows 8 disables SFNs on all volumes except the boot volume (however these volumes must be formatted under Win8).
You can check this policy in InstanceSetup callback (maybe it’s little complicated, because you need to check global NtfsDisable8dot3NameCreation flag and per-volume settings) or when you set SFN (if you do that), you’ll get STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME error and you know SFNs are disabled on the volume. I use the second method.
[Petr]:
I construct the path manually in pre-create, because FltGetFileNameInformation with FLT_FILE_NAME_OPENED, I think, converts network DeviceObjects to little different paths (e.g. user opens \Device\LanmanRedirector, \Device\Mup; or ;X:00..0\computer\share\realpath, but FltGetFileNameInformation returns unified format, or strips something from these paths or from RelatedFileObject's path). I don't remember if it's XP or Vista+ thing, but it was the reason I do that manually.
What do you mean "I construct the path manually". Is it mean that you get the volume name using "FltGetVolumeName()" and then append it with "FltObjects->FileObject->FileName". Where FltObjects is "PCFLT_RELATED_OBJECTS FltObjects".
Or you use any other way to construct the path manually. Please can you explain it. Thanks for your help.