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.
This commit is contained in:
2017-08-23 17:47:41 +01:00
parent a2b6c4a828
commit 1619cd020c
5 changed files with 156 additions and 39 deletions

View File

@@ -36,8 +36,10 @@ namespace osrepodbmgr.Core
{
public static List<string> files;
public static List<string> folders;
public static List<string> symlinks;
public static Dictionary<string, DBOSFile> hashes;
public static Dictionary<string, DBFolder> foldersDict;
public static Dictionary<string, string> 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<string, string> symlinks;
public delegate void UnarChangeStatusDelegate();
public static event UnarChangeStatusDelegate UnarChangeStatus;

96
osrepodbmgr.Core/IO.cs Normal file
View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace osrepodbmgr.Core
{
public static class IO
{
public static List<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOption, bool followLinks = true, bool symlinks = true)
{
if (followLinks)
return new List<string>(Directory.EnumerateFiles(path, searchPattern, searchOption));
List<string> files = new List<string>();
List<string> directories = new List<string>();
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<string> EnumerateDirectories(string path, string searchPattern, SearchOption searchOption, bool followLinks = true, bool symlinks = true)
{
if (followLinks)
return new List<string>(Directory.EnumerateDirectories(path, searchPattern, searchOption));
List<string> directories = new List<string>();
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<string> newDirectories = new List<string>();
foreach (string directory in directories)
newDirectories.AddRange(EnumerateDirectories(directory, searchPattern, searchOption, followLinks, symlinks));
directories.AddRange(newDirectories);
}
return directories;
}
public static List<string> EnumerateSymlinks(string path, string searchPattern, SearchOption searchOption)
{
List<string> links = new List<string>();
List<string> directories = new List<string>();
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;
}
}
}

View File

@@ -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<string, string> kvp in Context.symlinks)
foreach(KeyValuePair<string, string> 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);

View File

@@ -71,18 +71,25 @@ namespace osrepodbmgr.Core
#if DEBUG
stopwatch.Restart();
#endif
Context.files = new List<string>(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<string>(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<string, DBOSFile>();
Context.foldersDict = new Dictionary<string, DBFolder>();
Context.symlinks = new Dictionary<string, string>();
Context.symlinksDict = new Dictionary<string, string>();
List<string> alreadyMetadata = new List<string>();
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<ArchitecturesTypeArchitecture> architectures = new List<ArchitecturesTypeArchitecture>();
@@ -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)

View File

@@ -77,6 +77,7 @@
<Compile Include="Workers\Clamd.cs" />
<Compile Include="Workers\VirusTotal.cs" />
<Compile Include="Symlinks.cs" />
<Compile Include="IO.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />