Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Adding new methods to support handling hard links, junctions and symbolic links + Issue #212 #311

Closed
wants to merge 5 commits into from

Conversation

besoft
Copy link

@besoft besoft commented Mar 2, 2017

Currently, to determine the target path of a junction or directory symbolic link, one may call File.GetLinkTargetInfo, which is not intuitive
=> I added Directory.GetLinkTargetInfo that provides this functionality

Currently, if the path contains some junctions or symbolic links, you may have two completely different paths (e.g., D:\Temp\A\B and D:\Temp\C\B, whereas A is a symbolic link "..\C") pointing to the same directory and there is no way to detect it
=> I added Directory.GetDirectoryId and File.GetFileId that returns a unique identifier. To support ReFS file system (Windows 8+) this identifier is composed of 64-bit volume serial number and 128-bit file system entry identifier (see WINAPI structure FILE_ID_INFO and functions GetFileInformationByHandle and GetFileInformationByHandleEx - https://msdn.microsoft.com/cs-cz/library/windows/desktop/hh802691(v=vs.85).aspx)

Currently, if ContinueOnExceptions option is ON, the caller cannot handle the errors, if this option is OFF, the traversing of directories stops with an exception, there is nothing in betweeen. THIS is request #212
(Provide a way to retrieve errors when you choose to ContinueOnException #212).
=> I added a set of overloaded methods allowing you to pass the delegate to an exception filter method in which the user handles the errors and returns true/false whether the exception should be thrown or not

Currently, if one needs just files larger than some threshold, or created later than some date, the only way is to enumerate all the files and then filter them. Although this is simple achievable, it might present decrease in performance (especially, if the output are just names).
=> I added an option another option filter to filter out the file system entries in the traversation loop

Currently, there is no option to recursively traverse the directories following the symbolic links while avoiding potential infinite loop (e.g.,traverse D:\Temp with D:\Temp\D\A and D:\Temp\C\B, whereas A is a symbolic link "..\C" and B is a symbolic link to D:\Temp\D -> this leads to path D:\Temp\D\A\B\A\B\A\B...)
=> I added an option another option filter to filter out the names of directories in the traversation loop so that the user may avoid this problem

…turns a unique file or directory identifier that can be used to determine if two paths refer to the same directory (symbolic links and junctions) or to the same file (symbolic links or hard links). The methods are compatible with FAT, NTFS and ReFS file systems.
…ory.EnumerateFileSystemEntryInfos that allows you to specify custom callback methods to filter out a) exceptions that should not be thrown, b) directories that should not be recursively traversed, c) file system entries that should not be in the final enumeration.
@besoft besoft changed the title Adding new methods to support handling hard links, junctions and symbolic links Adding new methods to support handling hard links, junctions and symbolic links + Issue 221 Mar 3, 2017
@besoft besoft changed the title Adding new methods to support handling hard links, junctions and symbolic links + Issue 221 Adding new methods to support handling hard links, junctions and symbolic links + Issue #212 Mar 3, 2017
@Yomodo Yomodo added this to the vNext milestone Jun 5, 2017
@Yomodo Yomodo self-assigned this Jun 6, 2017
Yomodo pushed a commit that referenced this pull request Jun 26, 2017
…irectoryId to return a unique file or directory identifier.

-Implemented #357: Added new Windows 10 property: FILE_DAX_VOLUME to VolumeInfo class.
-Added new Windows 10 property: FILE_DAX_VOLUME to VolumeInfo class.
-Renamed some native enums and structs to their (original) WIN32 name.
-Update some unit tests.
@Yomodo Yomodo closed this Jun 26, 2017
@CyberSinh
Copy link
Contributor

@besoft Hi, you said:

=> I added an option another option filter to filter out the names of directories in the traversation loop so that the user may avoid this problem

Can you give me sample code how to avoid this problem? I didn't find any flag option or code sample for this. Thanks.

@Yomodo
Copy link
Collaborator

Yomodo commented Jan 23, 2018

@CyberSinh
Copy link
Contributor

Yes, I know. But I don't know how to avoid traversation loop with @besoft code.

@CyberSinh
Copy link
Contributor

In fact, I just want to know what is the best way to use the RecursionFilter property to detect and block junctions cycles. There is no unit test in the repo showing this feature. Thanks to @besoft for helping me.

@besoft
Copy link
Author

besoft commented Jan 24, 2018

I do not know if it is the best way but it is working: there is AlphaFS.Directory.GetDirectoryId method that returns NTFS unique id for the specified path, no matter if this path is native or a symbolic link. Then you may use something like what is in the snippet below. If combined with a parallel traversal of the filesystem tree the performance is not bad.

var discoveredDirs = new Dictionary<AlphaFS.FileId, string>();
discoveredDirs.Add(AlphaFS.Directory.GetDirectoryId(sources[0]), AlphaFS.Path.GetLongPath(sources[0]));

var list = AlphaFS.Directory.EnumerateFileSystemEntryInfos<AlphaFS.FileSystemEntryInfo>
            (
                AlphaFS.Path.GetLongPath(sources[0]),
                AlphaFS.DirectoryEnumerationOptions.FilesAndFolders | AlphaFS.DirectoryEnumerationOptions.Recursive
                /*| AlphaFS.DirectoryEnumerationOptions.SkipReparsePoints
				| AlphaFS.DirectoryEnumerationOptions.ContinueOnException*/,
                AlphaFS.PathFormat.LongFullPath, new AlphaFS.DirectoryEnumerationFilters()
                {
                    RecursionFilter = (x) =>
                    {
                        try
                        {
                            var id = AlphaFS.Directory.GetDirectoryId(x.FullPath);                                
                            if (discoveredDirs.ContainsKey(id))
                                return false;

                            discoveredDirs.Add(id, x.FullPath);
                            return true;
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine($"[{e.HResult}] {e.Message} : [{x.FullPath}]");
                            return false;
                        }

@Yomodo
Copy link
Collaborator

Yomodo commented Jan 27, 2018

I'm thinking of adding a CancellationToken property to DirectoryEnumerationFilters so that enumeration can easily be aborted.

@Yomodo Yomodo modified the milestones: vNext, Release 2.2 Jun 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants