Is OBJ_DONT_REPARSE supported by user-mode NtCreateFile with a directory-relative name?

Chris Terrell 120 Reputation points
2026-09-13T07:07:27.6633333+00:00

This brief concerns published API contracts for an initial file acquisition before content inspection. It requests clarification of documentation, without asserting anything about a particular host.

The proposed inspection requires an independently established relationship between an eligible subject, permitted metadata resolution, and the object reached. Opening and querying are access operations. Legitimate supply, access eligibility and a trusted starting object remain separate prerequisites.

The documentation basis is the retained official material retrieved on 2026-09-13 UTC / September 12 Central. Quoted phrases below are direct excerpts; other descriptions are paraphrases. The question below is a proposed inquiry.

The NtCreateFile Parameters → ObjectAttributes.Attributes description says: “This value can be zero or OBJ_CASE_INSENSITIVE.” The general OBJECT_ATTRIBUTES Members → Attributes description says OBJ_DONT_REPARSE means “no reparse points will be followed when parsing the name of the associated object.” NtCreateFile, OBJECT_ATTRIBUTES

For user-mode NrCreateFIle, with an existing directory handle as RootDirectory and one relative component as ObjectName, is OBJ_DONT_REPARSE supported? How should these descriptions be reconciled? Please identify the applicable published contract, refusal scope and platform conditions.

An affirmative answer would not establish legitimate subject supply, an eligible starting object, environmental conditions or authorization to acquire anything. Nor would it establish that a native-acquired handle satisfies ReOpenFile’s requirements or completes a reader method. The intended later observation compares two returned byte sequences; it does not claim snapshot semantics or continuous immutability.

Please identify the applicable published sections or any unresolved documentation discrepancy. No particular implementation or favorable answer is presumed.

Windows development | Windows API - Win32
0 comments No comments

Answer accepted by question author
Taki Ly (WICLOUD CORPORATION) 5,880 Reputation points Microsoft External Staff Moderator
2026-09-14T06:31:22.2633333+00:00

Hello @Chris Terrell ,

I tested this on Windows 11 (build 26200) and OBJ_DONT_REPARSE is honored by user-mode NtCreateFile even when you pass a RootDirectory handle plus a single relative ObjectName. It behaves exactly the same as when you pass a fully-qualified path.

My reading is that the two doc pages aren't really contradicting each other; one of them is just out of date. The real definition of the flag lives on the OBJECT_ATTRIBUTES page, and it says:

OBJ_DONT_REPARSE: If this flag is set, no reparse points will be followed when parsing the name of the associated object. If any reparses are encountered the attempt will fail and return a STATUS_REPARSE_POINT_ENCOUNTERED result. This can be used to determine if there are any reparse points in the object's path, in security scenarios.

Attributes is a generic object-manager bitmask that gets processed while the name is being parsed, so it applies to the Nt*File routines in general, not just to whatever a single page happens to list. The line on the NtCreateFile page saying Attributes "can be zero or OBJ_CASE_INSENSITIVE" reads to me as old, simplified wording that predates this flag. If you'd like it corrected, the quickest way is to use the "Was this page helpful?" thumbs-up/thumbs-down control in the right-hand column (just under the "In this article" outline) and note that Attributes also accepts the object-attribute flags from OBJECT_ATTRIBUTES (such as OBJ_DONT_REPARSE); that feedback goes to the docs team who own the page.

Below is what I actually saw. I made a directory junction link pointing at real with mklink /J, opened the parent directory with FILE_FLAG_BACKUP_SEMANTICS to use as RootDirectory, then called ntdll!NtCreateFile a few different ways:

  • Opening the junction by relative name (RootDirectory + link) with OBJ_DONT_REPARSE failed with STATUS_REPARSE_POINT_ENCOUNTERED (0xC000050B). Without the flag it succeeded and followed the junction.
  • Opening the exact same junction by its fully-qualified \??\...\link path with the flag gave the identical STATUS_REPARSE_POINT_ENCOUNTERED, so relative vs fully-qualified made no difference.
  • Opening a plain directory that isn't a reparse point, with the flag set, succeeded, so the flag only bites when there's actually a reparse point to cross.
  • I also put the reparse point in the middle of the path (link\inside.txt) and it still failed with the flag and succeeded without it, which lines up with "any reparse in the path," not just the final component.

For contrast, FILE_OPEN_REPARSE_POINT did the opposite of OBJ_DONT_REPARSE: it opened the reparse point itself and returned success. So the two are for different goals, one opens the link, the other refuses if a link is anywhere in the way.

One thing worth calling out is that STATUS_REPARSE_POINT_ENCOUNTERED (0xC000050B) is not the same as STATUS_REPARSE (0x00000104). The "NtCreateFile never returns STATUS_REPARSE" note on the doc page is talking about that other status, not about this failure.

So the bottom line, on the configuration I tested, is that OBJ_DONT_REPARSE works with a directory-relative name. You get STATUS_SUCCESS if there's no reparse point in the path, and STATUS_REPARSE_POINT_ENCOUNTERED if there is one. I didn't hit any version or file-system dependency in my testing (verified on Windows 11 build 26200); in my reading the governing text is the OBJECT_ATTRIBUTES page, and the NtCreateFile wording is just stale. See below for where the documentation stops.

Exact test configuration

Directory junction link pointing at real, made with mklink /J, on a local NTFS volume (C:). The parent directory was opened once with Win32 CreateFile requesting FILE_LIST_DIRECTORY | SYNCHRONIZE with FILE_FLAG_BACKUP_SEMANTICS, and that handle was passed as RootDirectory. I did not read back that handle's granted mask in this test, so only the requested access is known here.

Each case was one ntdll!NtCreateFile call. Shared arguments:

DesiredAccess     = FILE_LIST_DIRECTORY | SYNCHRONIZE | READ_CONTROL        (0x00120001)
ShareAccess       = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE  (0x00000007)
CreateDisposition = FILE_OPEN                                               (0x00000001)
AllocationSize = NULL, FileAttributes = 0, EaBuffer = NULL, EaLength = 0

Constants (ntdef.h / winternl.h, Windows SDK 10.0.26100.0): OBJ_CASE_INSENSITIVE (CI) = 0x00000040, OBJ_DONT_REPARSE = 0x00001000, FILE_DIRECTORY_FILE = 0x00000001, FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020, FILE_OPEN_REPARSE_POINT = 0x00200000.

Per-case parameters and recorded results:

[A] root=parent name=link            attr=0x00001040 (OBJ_DONT_REPARSE|CI) opts=0x00000021  -> 0xC000050B STATUS_REPARSE_POINT_ENCOUNTERED
[B] root=parent name=link            attr=0x00000040 (CI)                  opts=0x00000021  -> 0x00000000 STATUS_SUCCESS
[C] root=NULL   name=\??\...\link    attr=0x00001040 (OBJ_DONT_REPARSE|CI) opts=0x00000021  -> 0xC000050B STATUS_REPARSE_POINT_ENCOUNTERED
[D] root=parent name=real            attr=0x00001040 (OBJ_DONT_REPARSE|CI) opts=0x00000021  -> 0x00000000 STATUS_SUCCESS
[E] root=parent name=link            attr=0x00000040 (CI)                  opts=0x00200021  -> 0x00000000 STATUS_SUCCESS
[F] root=parent name=link\inside.txt attr=0x00001040 (OBJ_DONT_REPARSE|CI) opts=0x00000020  -> 0xC000050B STATUS_REPARSE_POINT_ENCOUNTERED
[G] root=parent name=link\inside.txt attr=0x00000040 (CI)                  opts=0x00000020  -> 0x00000000 STATUS_SUCCESS

opts 0x00000021 = FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
opts 0x00200021 = FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT
opts 0x00000020 = FILE_SYNCHRONOUS_IO_NONALERT (F and G target a file, not a directory)

A is the directory-relative case; C is its fully-qualified counterpart; E is the separate FILE_OPEN_REPARSE_POINT call with no OBJ_DONT_REPARSE; F puts the reparse point in an intermediate component.

Correction. My September 17 comment listed the case A attribute value as 0x00040040. That was a transcription error in the write-up; the value passed was 0x00001040, as shown above. On September 18 I re-ran case A both ways: 0x00001040 returns STATUS_REPARSE_POINT_ENCOUNTERED, and the literal 0x00040040 returns STATUS_INVALID_PARAMETER (0xC000000D), so the recorded result came from the correct flag.

Where the documentation stops

Keeping three things separate:

  • Express documentation: OBJECT_ATTRIBUTES defines what OBJ_DONT_REPARSE does, and its RootDirectory description says relative naming is supported in general. Neither statement is qualified by relative versus fully-qualified, by the FILE_OPEN_REPARSE_POINT interaction, or by platform. The NtCreateFile page's "zero or OBJ_CASE_INSENSITIVE" line is the express text there.
  • My interpretation: because Attributes is a generic object-manager field processed while the name is parsed, the flag applies the same way whether the name is relative or fully-qualified, and the NtCreateFile wording is stale. That is a reading of the general wording, not a separately documented statement about the relative case.
  • Measured behavior: the runs above confirm that reading on Windows 11 build 26200, local NTFS.

I am not aware of a published provision, or a clarification from the documentation owners, that expressly addresses this user-mode, directory-relative use or states its platform limits. No page I can find expressly documents (a) the directory-relative case as such, (b) the OBJ_DONT_REPARSE and FILE_OPEN_REPARSE_POINT interaction, or (c) version or file-system conditions for this combination. Those parts rest on the general OBJECT_ATTRIBUTES wording, my reading of it, and the measured result, not on an express provision.

Thank you.

Was this answer helpful?

1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.