From 1619cd020c96c9025aa06937a45f508fb3d6a29e Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 23 Aug 2017 17:47:41 +0100 Subject: [PATCH] System.IO.EnumerateFiles follow symbolic links, creating an infinite loop on links to "." and "..", so implement and use an enumerator that do not follow links. --- osrepodbmgr.Core/Context.cs | 3 +- osrepodbmgr.Core/IO.cs | 96 ++++++++++++++++++++++++ osrepodbmgr.Core/Workers/Database.cs | 6 +- osrepodbmgr.Core/Workers/Files.cs | 89 +++++++++++++--------- osrepodbmgr.Core/osrepodbmgr.Core.csproj | 1 + 5 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 osrepodbmgr.Core/IO.cs diff --git a/osrepodbmgr.Core/Context.cs b/osrepodbmgr.Core/Context.cs index cee76fe..99d0b0d 100644 --- a/osrepodbmgr.Core/Context.cs +++ b/osrepodbmgr.Core/Context.cs @@ -36,8 +36,10 @@ namespace osrepodbmgr.Core { public static List files; public static List folders; + public static List symlinks; public static Dictionary hashes; public static Dictionary foldersDict; + public static Dictionary symlinksDict; public static string path; public static DBEntry dbInfo; public static bool unarUsable; @@ -54,7 +56,6 @@ namespace osrepodbmgr.Core public static bool usableDotNetZip; public static string clamdVersion; public static bool virusTotalEnabled; - public static Dictionary symlinks; public delegate void UnarChangeStatusDelegate(); public static event UnarChangeStatusDelegate UnarChangeStatus; diff --git a/osrepodbmgr.Core/IO.cs b/osrepodbmgr.Core/IO.cs new file mode 100644 index 0000000..ac7cf03 --- /dev/null +++ b/osrepodbmgr.Core/IO.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace osrepodbmgr.Core +{ + public static class IO + { + public static List EnumerateFiles(string path, string searchPattern, SearchOption searchOption, bool followLinks = true, bool symlinks = true) + { + if (followLinks) + return new List(Directory.EnumerateFiles(path, searchPattern, searchOption)); + + List files = new List(); + List directories = new List(); + + foreach (string file in Directory.EnumerateFiles(path, searchPattern)) + { + FileInfo fi = new FileInfo(file); + if (fi.Attributes.HasFlag(FileAttributes.ReparsePoint) && symlinks) + files.Add(file); + else if (!fi.Attributes.HasFlag(FileAttributes.ReparsePoint)) + files.Add(file); + } + + if (searchOption == SearchOption.AllDirectories) + { + foreach (string directory in Directory.EnumerateDirectories(path, searchPattern)) + { + DirectoryInfo di = new DirectoryInfo(directory); + if (!di.Attributes.HasFlag(FileAttributes.ReparsePoint)) + files.AddRange(EnumerateFiles(directory, searchPattern, searchOption, followLinks, symlinks)); + } + } + + return files; + } + + public static List EnumerateDirectories(string path, string searchPattern, SearchOption searchOption, bool followLinks = true, bool symlinks = true) + { + if (followLinks) + return new List(Directory.EnumerateDirectories(path, searchPattern, searchOption)); + + List directories = new List(); + + if (searchOption == SearchOption.AllDirectories) + { + foreach (string directory in Directory.EnumerateDirectories(path, searchPattern)) + { + DirectoryInfo di = new DirectoryInfo(directory); + if (!di.Attributes.HasFlag(FileAttributes.ReparsePoint)) + directories.Add(directory); + } + + List newDirectories = new List(); + + foreach (string directory in directories) + newDirectories.AddRange(EnumerateDirectories(directory, searchPattern, searchOption, followLinks, symlinks)); + + directories.AddRange(newDirectories); + } + + return directories; + } + + public static List EnumerateSymlinks(string path, string searchPattern, SearchOption searchOption) + { + List links = new List(); + List directories = new List(); + + foreach (string file in Directory.EnumerateFiles(path, searchPattern)) + { + FileInfo fi = new FileInfo(file); + if (fi.Attributes.HasFlag(FileAttributes.ReparsePoint)) + links.Add(file); + } + + if (searchOption == SearchOption.AllDirectories) + { + foreach (string directory in Directory.EnumerateDirectories(path, searchPattern)) + { + DirectoryInfo di = new DirectoryInfo(directory); + if (!di.Attributes.HasFlag(FileAttributes.ReparsePoint)) + directories.Add(directory); + else //if (!links.Contains(directory)) + links.Add(directory); + } + + foreach (string directory in directories) + links.AddRange(EnumerateSymlinks(directory, searchPattern, searchOption)); + } + + return links; + } + } +} diff --git a/osrepodbmgr.Core/Workers/Database.cs b/osrepodbmgr.Core/Workers/Database.cs index 3d81c1d..45ceaa5 100644 --- a/osrepodbmgr.Core/Workers/Database.cs +++ b/osrepodbmgr.Core/Workers/Database.cs @@ -296,13 +296,13 @@ namespace osrepodbmgr.Core stopwatch.Restart(); #endif counter = 0; - if(Context.symlinks.Count > 0) + if(Context.symlinksDict.Count > 0) dbCore.DBOps.CreateSymlinkTableForOS(Context.dbInfo.id); - foreach(KeyValuePair kvp in Context.symlinks) + foreach(KeyValuePair kvp in Context.symlinksDict) { if(UpdateProgress != null) - UpdateProgress(null, "Adding symbolic links to OS in database", counter, Context.symlinks.Count); + UpdateProgress(null, "Adding symbolic links to OS in database", counter, Context.symlinksDict.Count); dbCore.DBOps.AddSymlinkToOS(kvp.Key, kvp.Value, Context.dbInfo.id); diff --git a/osrepodbmgr.Core/Workers/Files.cs b/osrepodbmgr.Core/Workers/Files.cs index 389980a..9e23ee5 100644 --- a/osrepodbmgr.Core/Workers/Files.cs +++ b/osrepodbmgr.Core/Workers/Files.cs @@ -71,18 +71,25 @@ namespace osrepodbmgr.Core #if DEBUG stopwatch.Restart(); #endif - Context.files = new List(Directory.EnumerateFiles(filesPath, "*", SearchOption.AllDirectories)); + Context.files = IO.EnumerateFiles(filesPath, "*", SearchOption.AllDirectories, false, false); Context.files.Sort(); #if DEBUG stopwatch.Stop(); Console.WriteLine("Core.FindFiles(): Took {0} seconds to find all files", stopwatch.Elapsed.TotalSeconds); stopwatch.Restart(); #endif - Context.folders = new List(Directory.EnumerateDirectories(filesPath, "*", SearchOption.AllDirectories)); + Context.folders = IO.EnumerateDirectories(filesPath, "*", SearchOption.AllDirectories, false, false); Context.folders.Sort(); #if DEBUG stopwatch.Stop(); Console.WriteLine("Core.FindFiles(): Took {0} seconds to find all folders", stopwatch.Elapsed.TotalSeconds); + stopwatch.Restart(); +#endif + Context.symlinks = IO.EnumerateSymlinks(filesPath, "*", SearchOption.AllDirectories); + Context.symlinks.Sort(); +#if DEBUG + stopwatch.Stop(); + Console.WriteLine("Core.FindFiles(): Took {0} seconds to find all symbolic links", stopwatch.Elapsed.TotalSeconds); #endif if(Finished != null) Finished(); @@ -107,14 +114,9 @@ namespace osrepodbmgr.Core { Context.hashes = new Dictionary(); Context.foldersDict = new Dictionary(); - Context.symlinks = new Dictionary(); + Context.symlinksDict = new Dictionary(); List alreadyMetadata = new List(); bool foundMetadata = false; - bool symlinksSupported = DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.WinCE && - DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32S && - DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32NT && - DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32Windows && - DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.WindowsPhone; // For metadata List architectures = new List(); @@ -141,6 +143,18 @@ namespace osrepodbmgr.Core // End for metadata + if ((DetectOS.GetRealPlatformID() == DiscImageChef.Interop.PlatformID.WinCE || + DetectOS.GetRealPlatformID() == DiscImageChef.Interop.PlatformID.Win32S || + DetectOS.GetRealPlatformID() == DiscImageChef.Interop.PlatformID.Win32NT || + DetectOS.GetRealPlatformID() == DiscImageChef.Interop.PlatformID.Win32Windows || + DetectOS.GetRealPlatformID() == DiscImageChef.Interop.PlatformID.WindowsPhone) && + Context.symlinks.Count > 0) + { + if (Failed != null) + Failed("Source contain unsupported symbolic links, not continuing."); + return; + } + #if DEBUG stopwatch.Restart(); #endif @@ -362,32 +376,6 @@ namespace osrepodbmgr.Core string relpath = file.Substring(filesPath.Length + 1); - if(fi.Attributes.HasFlag(FileAttributes.ReparsePoint)) - { - // TODO: Symlinks not supported on any Windows platform - if(!symlinksSupported) - { - if(Failed != null) - Failed(string.Format("{0} is an unsupported symbolic link, not continuing.", relpath)); - return; - } - - if(UpdateProgress != null) - UpdateProgress(string.Format("Resolving symlink on file {0} of {1}", counter, Context.files.Count), null, counter, Context.files.Count); - - string target = Symlinks.ReadLink(file); - if(target == null) - { - if(Failed != null) - Failed(string.Format("Could not resolve symbolic link at {0}, not continuing.", relpath)); - return; - } - - Context.symlinks.Add(relpath, target); - counter++; - continue; - } - if(UpdateProgress != null) UpdateProgress(string.Format("Hashing file {0} of {1}", counter, Context.files.Count), null, counter, Context.files.Count); FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read); @@ -451,7 +439,6 @@ namespace osrepodbmgr.Core counter = 1; foreach(string folder in Context.folders) { - string filesPath; DirectoryInfo di = new DirectoryInfo(folder); @@ -477,6 +464,38 @@ namespace osrepodbmgr.Core #if DEBUG stopwatch.Stop(); Console.WriteLine("Core.HashFiles(): Took {0} seconds to iterate all folders", stopwatch.Elapsed.TotalSeconds); + stopwatch.Restart(); +#endif + counter = 2; + foreach (string symlink in Context.symlinks) + { + string filesPath; + + if (!string.IsNullOrEmpty(Context.tmpFolder) && Directory.Exists(Context.tmpFolder)) + filesPath = Context.tmpFolder; + else + filesPath = Context.path; + + string relpath = symlink.Substring(filesPath.Length + 1); + + if (UpdateProgress != null) + UpdateProgress(string.Format("Resolving symlink {0} of {1}", counter, Context.symlinks.Count), null, counter, Context.symlinks.Count); + + string target = Symlinks.ReadLink(symlink); + if (target == null) + { + if (Failed != null) + Failed(string.Format("Could not resolve symbolic link at {0}, not continuing.", relpath)); + return; + } + + Context.symlinksDict.Add(relpath, target); + counter++; + continue; + } +#if DEBUG + stopwatch.Stop(); + Console.WriteLine("Core.HashFiles(): Took {0} seconds to resolve all symbolic links", stopwatch.Elapsed.TotalSeconds); #endif if(foundMetadata) diff --git a/osrepodbmgr.Core/osrepodbmgr.Core.csproj b/osrepodbmgr.Core/osrepodbmgr.Core.csproj index 98b11a1..f10a273 100644 --- a/osrepodbmgr.Core/osrepodbmgr.Core.csproj +++ b/osrepodbmgr.Core/osrepodbmgr.Core.csproj @@ -77,6 +77,7 @@ +