2

I am trying to use Windows API functions compatible with Windows XP and up to find the target of a junction or symbolic link. I am using CreateFile to get a handle to the reparse point, then DeviceIoControl with the FSCTL_GET_REPARSE_POINT flag to read the reparse data into a REPARSE_DATA_BUFFER. Then, I use the offsets and lengths in the buffer to extract the SubstituteName and PrintName strings.

In Windows 8, extracting the PrintName works perfectly, giving me a normal path (ie c:\filename.ext), but in XP the PrintName section of the REPARSE_DATA_BUFFER seems to always have a length of 0, leaving me with an empty string.

Using the SubsituteName seems to work in both, but I always end up with a prefix of \??\ on the beginning of the file path (ie \??\c:\filename.ext). (as a side note, fsutil reparsepoint query shows the \??\ prefix as well).

I've read through much of the documentation on MSDN, but I can't find any explanation of this prefix. If the prefix is guaranteed to begin every SubstituteName, then I can just exclude the first four characters when I copy the file path from the buffer, but I'm not sure that this is the case. I would love to know if the "\??\" prefix appears in the SubstituteName for all Microsoft reparse points and why.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
qdet
  • 115
  • 3

2 Answers2

0

The \??\ prefix means the path is not parsed. It is not guaranteed on every name, so you will have to look for the prefix on a per-name basis and skip it if present.

Update: I could not find any definitive documentation explaining exactly that \??\ actually represents, but here are some links that mention the \??\ prefix in action:

http://www.flexhex.com/docs/articles/hard-links.phtml

Note that szTarget string must contain the path prefixed with the "non-parsed" prefix "\??\", and terminated with the backslash character, for example "\??\C:\Some Dir\".

http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/908b3927-1ee9-4e03-9922-b4fd49fc51a6

http://mjunction.googlecode.com/svn-history/r5/trunk/MJunction/MJunction/JunctionPoint.cs

This prefix indicates to NTFS that the path is to be treated as a non-interpreted path in the virtual file system.

Private Const NonInterpretedPathPrefix As String = "\??\"

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • You're mixing up \\?\ with \??\, I think. – user541686 Jan 15 '13 at 04:03
  • No, I'm not mixing them up. I know what `"\\?\"` is. I did some research before posting my answer. The `"\??\"` prefix is used as a "not-parsed" flag on reparse points. – Remy Lebeau Jan 15 '13 at 04:55
  • Oh I see... do you have a link by any chance? I'm having a hard time searching for question marks. :( – user541686 Jan 15 '13 at 05:00
  • "\??\" is the caller's local device directory (e.g. "\Sessions\0\DosDevices\"), which shadows the caller's global device directory (e.g. "\Global??"). Since XP, "\DosDevices" is just an object symbolic link to "\??". Prior to the introduction of terminal services (hydra), it was the real device mountpoint directory, and there was no local vs global distinction. In NT 4 (w/ hydra) and Windows 2000, they copied over separate "DosDevices" directories per terminal session, and those directories are still there, but now only session 0 is used, with shadow directories per logon. – Eryk Sun Aug 05 '19 at 13:50
  • The Windows API normalizes all fully-qualified DOS paths (as well as some relative paths, if they're below the working directory) as "\??\" NT device paths. It also supports two prefixes, "\\.\" and "\\?\", that directly map to "\??\". Of the two, only "\\.\" paths get normalized, which replaces slash with backslash, strips trailing dots and spaces from the final component, and is limited to `MAX_PATH` if long-path support isn't enabled for the process (i.e. Windows 10 with both the "LongPathsEnabled" policy enabled and the application manifest declaring itself as "longPathAware"). – Eryk Sun Aug 05 '19 at 13:54
  • Since a "\\?\" path isn't normalized, it can use only backslash as the path separator, and take care to avoid creating files with trailing dots and spaces that won't be accessible with regular DOS paths. Even with "\\.\" paths we have to be careful to avoid using reserved DOS device names, including NUL, CON, CONIN$, CONOUT$, AUX, PRN, COM[1-9], and LPT1[1-9], plus trailing colons, spaces, dots, and an extension (e.g. "nul : .txt" is reserved). In DOS drive-letter and relative paths, these device names in the final component get translated to "\\.\" device paths such as "\\.\nul". – Eryk Sun Aug 05 '19 at 14:03
  • Also, to get the non-normalized behavior, the "\\?\" prefix must use only backslash. Any other combination of forward slashes and backslashes (e.g. "//?/", "\\?/", etc) is treated exactly the same as "\\.\" (or "//./", "\\./", etc). – Eryk Sun Aug 05 '19 at 14:06
  • @eryksun all of that informative should have been posted as a new answer, not as comments – Remy Lebeau Aug 05 '19 at 16:23
  • It could be, and I might. But I was mostly concerned with conveying it to you since you're an information hub that answers far more questions than I ever would or could. – Eryk Sun Aug 05 '19 at 19:28
0

The Windows kernel has a "DOS Devices namespace" \DosDevices\ which is basically where anything you can open with CreateFile resides. (QueryDosDevice is a function which gives you all the members of that namespace.)

Because it's such a commonly used path, \??\ also redirects to that namespace. So, to the kernel, the path C:\Windows is invalid -- it should really be written as something like \??\C:\Windows. That's where this notation comes from.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Some more searching on the "DOS Devices namespace" turned up this article (http://www.nynaeve.net/?p=92) which has a section expanding on your (very helpful) explanation. This explanation seems to indicate that any reparse point accessed with CreateFile will include the "\??\" prefix. Is that a safe assumption? – qdet Jan 16 '13 at 00:44
  • @user1978885: No -- it might work for 95% of cases, but it would be very fragile and could easily fail on a not-very-typical system. I should also tell you that the story I told you is actually not the full story, because there is also something called a "local" namespace and a "global" namespace... and also there are sessions... it's quite complicated, and even I don't know all the details. What are you trying to do, though? Is your goal to convert the NT path to a Win32 path (by getting rid of the prefix)? If so, then there might be other, more "correct" ways to do it... what's your goal? – user541686 Jan 16 '13 at 01:10
  • My immediate goal is to convert the NT path to a Win32 path so that it can be printed to the console in a "normal" format. I would also like to use that Win32 path string to create a boost::filesystem::path object for other manipulation. I can solve the issue by testing the first four characters before skipping them, but if there is a more efficient or "correct" way to handle this, I would prefer to do it that way. Thanks. – qdet Jan 16 '13 at 02:19
  • @qdet: Ok... this is complicated: I suggest having a series of fallbacks, because each approach has its own advantage (speed): (1) Look for the \??\ prefix and remove it; if it's there, you're done. If not, (2) Try the same thing with \DosDevices\; if that didn't work, then take an undocumented route -- use [`IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH` on the Mount Manager](http://stackoverflow.com/a/5286888/541686) for every possible prefix of the path which ends with a backslash, until it successfully returns a drive letter; then replace the prefix with the drive letter and return the result. – user541686 Jan 16 '13 at 02:45
  • @qdet: And *if all of those fail* for some reason (it *is* possible; some drivers avoid the Mount Manager), *then* (5) try the approaches listed [here](http://www.drdobbs.com/nt-handle-to-path-conversion/184416255). (Yes, it's complicated, sorry.) – user541686 Jan 16 '13 at 02:48
  • Thank you for your help. This solution makes sense and should serve my purposes perfectly. – qdet Jan 16 '13 at 23:26
  • @Mehrdad: These can all fail in the end. I discovered that absolute path symbolic links and network shares do other than what I would have wanted. – Joshua Oct 02 '18 at 02:28
  • @Joshua: I think that's what I emphasized too, right? I was saying all of these can fail. – user541686 Oct 02 '18 at 03:46