Bill/Tony:
So far only NTFS implements everything I’m about to describe. Some of this has been mentioned at PlugFest, and I’m sure will be mentioned again at the next PlugFest. I’ll be on hand at the next PlugFest.
Non-empty directory reparse points simply means that 1) you can now create a reparse point on a non-empty directory; and 2) if you have a directory with a reparse point you can now create files in that directory.
We didn’t want apply this change retroactively to existing reparse tags being used on directories, as that could break expectations. So we designed a new class of reparse point that opts in on a tag by tag basis. It is essentially based on this new reparse tag flag:
// ±±±±±----------------------±------------------------------+
// |M|R|N|D| Reserved bits | Reparse Tag Value |
// ±±±±±----------------------±------------------------------+
//
// D is the directory bit. When set to 1, indicates that any directory
// with this reparse tag can have children. Has no special meaning when used
// on a non-directory file. Not compatible with the name surrogate bit.
//
//
// Macro to determine whether a directory with this reparse point can have
// children.
//
#define IsReparseTagDirectory(_tag) ( \
((_tag) & 0x10000000) \
)
However, it doesn’t map perfectly to that flag, because we had to grandfather in an existing reparse point tag that needs this behavior, and it’s possible we’ll do future tweaks to include/exclude certain tags. Hence we created an actual routine FsRtlIsNonEmptyDirectoryReparsePointAllowed to abstract the logic. Please call this routine and do not rely on the bit.
Incidentally if third parties want this new behavior, they can ask for it when requesting new reparse point tags.
Non-empty directory reparse points are related in a couple of ways to OPEN_REPARSE_ECP. 1) The OPEN_REPARSE_POINT_REPARSE_IF_CHILD_EXISTS, OPEN_REPARSE_POINT_REPARSE_IF_CHILD_NOT_EXISTS, and OPEN_REPARSE_POINT_REPARSE_IF_DIRECTORY_FINAL_COMPONENT flags only apply to this class of reparse points. 2) If you fill in an OPEN_REPARSE_ECP, you have full control over when/if NTFS reparses or not. But when we thought about “offline” scenarios (dual-boot, filter got uninstalled, etc.) we wanted these directories to act seamlessly, since they are in essence directories. You should be able to cd into them, dir them, etc. without having problems. So we put special behavior in NTFS, guided by FsRtlIsNonEmptyDirectoryReparsePointAllowed, when an OPEN_REPARSE_ECP is NOT present. I’m going to be lazy and just paste a comment from NTFS which describes this pretty well.
//
// Our decision whether to reparse or not depends on various factors such
// as what type of reparse tag we encountered, whether an OPEN_REPARSE
// ECP is present, whether this is a file or directory, etc.
//
//
// “OFFLINE” BEHAVIOR (OpenReparseTag == NULL):
// ------------------
//
// When a reparse point is encountered that is NOT a directory that may
// be non-empty (one whose reparse tag is recognized by
// FsRtlIsNonEmptyDirectoryReparsePointAllowed), then reparse. This is
// traditional file system behavior.
//
// The following flags control behavior when a reparse point is encountered
// that IS on a directory that may be non-empty (one whose reparse tag is
// recognized by FsRtlIsNonEmptyDirectoryReparsePointAllowed), then do not
// reparse. This is custom behavior for this class of reparse points.
//
//
// “ONLINE” BEHAVIOR (OpenReparseTag != NULL):
// -----------------
//
// When a reparse point is encountered that is NOT a directory that may
// be non-empty (one whose reparse tag is recognized by
// FsRtlIsNonEmptyDirectoryReparsePointAllowed), then do not reparse.
//
// The following flags control behavior when a reparse point is encountered
// that IS on a directory that may be non-empty (one whose reparse tag is
// recognized by FsRtlIsNonEmptyDirectoryReparsePointAllowed):
//
// OPEN_REPARSE_POINT_REPARSE_IF_CHILD_EXISTS -
// If the reparse point is on a directory that is not the final path
// component and the next path component exists, reparse on the directory.
//
// OPEN_REPARSE_POINT_REPARSE_IF_CHILD_NOT_EXISTS -
// If the reparse point is on a directory that is not the final path
// component and the next path component does not exist, reparse on the
// directory.
//
// OPEN_REPARSE_POINT_REPARSE_IF_DIRECTORY_FINAL_COMPONENT -
// If the reparse point is on a directory that is the final path
// component, reparse on the directory unless FILE_OPEN_REPARSE_POINT
// is specified.
//
// Specifying all three of the above flags is legal and simply means always
// reparse on any directory reparse point.
//
The main challenges implementing this in your own file system are structuring the code so that you can “peek” ahead into a directory to see if the next component exists, and also getting all of the flag combinations correct.
Craig (MSFT)
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@billz.fastmail.fm
Sent: Monday, September 19, 2016 6:00 PM
To: Windows File Systems Devs Interest List
Subject: RE:[ntfsd] File system testing and filter related heisenbugs
Interesting. The FsRtlIsNonEmptyDirectoryReparsePointAllowed API seems to return TRUE/FALSE based on the ReparseTag only. Perhaps there is a class of reparse points that are now allowed to be set on non-empty directories?
BTW, I am finding the comments you quoted on the documentation for the new OPEN_REPARSE_LIST_ENTRY:
https://msdn.microsoft.com/en-us/library/windows/hardware/mt734265(v=vs.85).aspx
So now one can supply an ECP with a list of reparse tags/guids that can be opened without getting STATUS_REPARSE. I am not sure what the relation to non-empty directories is though.
Bill
—
NTFSD is sponsored by OSR
MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:
To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:>