-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose reparse point tags #1908
Comments
I agree that it would be nice to have this, the trick is that we haven't fully rationalized how we want to expose platform specific data. As this impacts OneDrive scenarios as mentioned we should try and answer this in 5.0 if we can. |
@JeremyKuhne PowerShell 7.0 was released yesterday and I hope in next PowerShell milestone we will address OneDrive experience - this helps to understand how .Net Core could be enhanced. |
@carlossanlop I've implemented this myself in my own project for symlinks and directory junctions on Windows. I'd be happy to help with any of the following code relating to reparse points (not sure which other issues this is related to).
None of my code checks hard links properly as I've not looked into them. |
The conversation was growing in #24271, so I requested to move it here. There's interest in having a boolean @jozkee and I would prefer to have an enum that lists all the reparse tags. We initially described it in the second proposal, but we decided not to propose it in the API review meeting because there wasn't enough consensus. + public enum ReparseTag
+ {
+ None = -1, // Default, indicates the file is not a Reparse Point (zero is already reserved)
+ MountPoint = 0xA0000003, // Maps to IO_REPARSE_TAG_MOUNT_POINT, describes a Junction
+ Symlink = 0xA000000C, // Maps to IO_REPARSE_TAG_SYMLINK, the only value used by Unix
+ AppExecLink = 0x8000001B, // Maps to IO_REPARSE_TAG_APPEXECLINK
+ }
public abstract partial class FileSystemInfo
{
+ public ReparseTag ReparseTag { get; }
} We now have more information that confirms this proposal makes more sense:
@hamarb123 thank you for your offer to help. Sorry I didn't reply earlier. Let's first discuss what the proper course of action is, and then we can decide how we will implement it. |
That's fine. I'd also like to have the enum, since that's what my codebase would require. |
It is indeed insufficient for knowing what type of link, but it is important enough in its own right to know that something is file-system link, i.e. that it points to another path (which may itself be a link, though that's not typical). It is important if you want to inspect or modify the (ultimate) target item's properties, primarily, but not limited to, the ultimate name and directory location. In most cases, you do not care about the specific type of link:
The Even with the addition of a
Reparse points are one file system's (NTFS') implementation detail - it just so happens that the abstract concept of file-system links is implemented via them in NTFS, but they serve other, non-link purposes, and are generally thought of as opaque data to be interpreted only by the applications that define them and associated application-specific file-system filters - see the docs. In other words: A Further thoughts on reparse points: It strikes me as unlikely that additional general-purpose file-system links - as opposed to application-specific reparse points - will be introduced in the future: symbolic links on NTFS, a later addition, appear to the more flexible successors to the legacy link types called junctions / mount points. In other words: going forward, symbolic links cover all general-purpose file-system link needs, just as they do on Unix. The generally opaque nature of reparse data also means that the .NET APIs need to have specialized knowledge of each reparse-point type in order to interpret that data - and I don't think we want to play continuous catch-up with respect to adding support for new, application-specific reparse tags - even if they're tagged as name surrogates, i.e. links (which OneDrive reparse points are not, by the way). Instead, if general support for reparse points is really needed, the best option would be to expose the raw reparse-point data, so that any caller can interpret it itself. As for link detection: The name-surrogate bit being set unequivocally identifies a reparse points as a link, but in order to support AppX reparse points are an interesting hybrid case in that they do point to another (file) path, but there's more to their definition, namely a package family name and publisher ID - and in some cases (e.g. One challenge is that the abstract ability to detect an NTFS link - via the name-surrogate bit - will not necessary mean that inspecting / resolving the target will be supported (because it requires open-ended, type-specific data-format knowledge). |
+1
+1
Yes, when you determine |
Interesting, if underlying Windows API (which .Net uses) works with RPs as expected (in operations like create, delete, move, enumerate) then it is possible that we do not need an explicit API for RPs at all. |
After reading @mklement0 's comment, I think I'd agree that there should be some form of an
I would very much like this as I personally thought that all reparse points just had the data as the link's target, and so I'd like the ability to just copy the link data from one file to another (unless I recognise the link type), as not only would this be faster, but would work in almost all edge cases as well. |
What do you mean under raw data? Every RP is identified by unique mask. It is open list. However, we can simply expose this field as a property. But to interpret the RP (ex., get a target) we need more data - every RP has a specific struct with the data. It is not possible to publish this information without describing these structures in code beforehand, they may be undocumented. |
Seems most opinions are now leaning towards having a We want to make sure this API is useful enough for anyone asking for it here (particularly our PowerShell contributors). Is anyone against this request, or can I proceed to prepare the API proposal? (I'll open a separate issue). One more question - @mklement0 you mentioned the following:
What about OneDrive files? (the spec defines a bunch of
|
@carlossanlop I would also definitely like to be able to tell which type of link it is as well. For my code I'd very much like to be able to know what it is. The reason that I think we should also have the Without the |
@iSazonov I was under the impression that it could simply return a byte[] of the data. |
Let's keep this issue open to continue discussing how to expose the reparse tags specifically. I opened a separate API proposal for |
@carlossanlop, would |
@hamarb123 thanks for continuing the discussion about reparse tags. To answer your question: the property would return the value of the reparse tag (defined in the link you shared), even if that value is not yet included in the enum. @mklement0 raised some interesting points, and made me wonder: how useful would it be to a user to learn if a file has a particular reparse tag, like |
@carlossanlop I think that it would just allow anyone who knows what's meant to be there to be able to see if it's that or not. Also, would this proposal also allow a property to allow raw access to the reparse point data? (presumably as a byte[] or something similar). |
dir C:\temp\Test
Directory: C:\temp\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 4/14/2021 10:17 AM dir
l---- 6/2/2021 4:32 PM dirLink -> C:\temp\test\dir
d---- 4/21/2021 9:17 AM qq It is PowerShell NameString() method which uses GetTarget() method. Interesting GetTarget() can not be generic since there is used a specific struct for every RTPT kind. See https://github.com/PowerShell/PowerShell/blob/1ba2960f5c5df9de4c079c97644e9af7bf34385b/src/System.Management.Automation/namespaces/FileSystemProvider.cs#L8462-L8485 My intermediate conclusion is we need new API in FileSystemEntry class (see #52666 (comment)) and in FileSystemInfo class (no API proposal yet). |
Let me try to give a conceptual overview, which hopefully also answers your questions, @iSazonov and @carlossanlop:
|
I agree this is not possible, but I was under the impression that the reason we're doing it this way was to make it forwards compatible if say in 20 years we don't like symbolic links anymore and want to make a new better one, or something else like that. Also, I think that it is important to provide a "safe" API for links (ie. .NET knows what the link type is, how to determine the target etc., or it throws an error), but I think that it is also important to be able to provide an "unsafe" API as well to allow for reading/writing raw link data on any ReparseType so that the developers don't have to P/Invoke it on Windows (should also expose on Unix for symbolic links so there is definitely no resolution happening / can set it to anything if it is desired). Maybe we could have something like this: + public enum ReparseTag
+ {
+ None = -1, // Default, indicates the file is not a Reparse Point (zero is already reserved)
+ MountPoint = 0xA0000003, // Maps to IO_REPARSE_TAG_MOUNT_POINT, describes a Junction
+ Symlink = 0xA000000C, // Maps to IO_REPARSE_TAG_SYMLINK, the only value used by Unix
+ AppExecLink = 0x8000001B, // Maps to IO_REPARSE_TAG_APPEXECLINK
+ }
public abstract partial class FileSystemInfo
{
+ public ReparseTag ReparseTag { get; }
+ public string ReparseTarget { get; set; } //only works on supported .NET reparse points
+ public byte[] RawReparseData { get; set; } //throws when setting with ReparseTag.None
} and similar apis for creating etc. (having variants for both |
Sounds good in principle, @hamarb123, but I think it is important to keep the link and the reparse-point APIs separate. Note that the API approved in #24271 (comment) already includes a - notably read-only - I don't think a (read/write) |
It would probably make sense to add ref struct FileSystemEntry
{
public ReparseTag ReparseTag { get; }
} |
On Windows if we enumerating file system we should take into account reparse points and reparse point tags too - that is symbolic links, OneDrive and AppX.
For example, attempting to read OneDrive reparse point causes an unwanted file download from the Internet. AppX reparse point would be considered like symbolic link. (It seems the last does not taken into account in Directory.Delete())
FileSystemEntry exposes FileAttributes there we can check reparse point flag. But we don't have reparse point tags.
FileSystem also exposes only FileAttributes without reparse point tags.
The request comes from PowerShell Core repo. I am trying to utilize new FileSystemEnumerable and have to use extra P/Invoke to get reparse point tags.
It will be great to have reparse point tags in FileSystemEntry and FileSystem types or another way to work with the scenarios in a Core standard way.
/cc @JeremyKuhne
The text was updated successfully, but these errors were encountered: