|
|
@@ -0,0 +1,739 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.IO;
|
|
|
+using System.IO.Abstractions;
|
|
|
+using System.Linq;
|
|
|
+using System.Text.RegularExpressions;
|
|
|
+namespace Quadarax.Foundation.Core.IO.FileSystem.Memory
|
|
|
+{
|
|
|
+
|
|
|
+
|
|
|
+ public class MemoryDirectory : IDirectory
|
|
|
+ {
|
|
|
+ private readonly MemoryFileSystem _fileSystem;
|
|
|
+
|
|
|
+ public IFileSystem FileSystem => _fileSystem;
|
|
|
+
|
|
|
+ public MemoryDirectory(MemoryFileSystem fileSystem)
|
|
|
+ {
|
|
|
+ _fileSystem = fileSystem;
|
|
|
+ }
|
|
|
+
|
|
|
+ public IDirectoryInfo CreateDirectory(string path)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(path))
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Path cannot be null or whitespace.", nameof(path));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Normalize the path
|
|
|
+ string normalizedPath = _fileSystem.Path.GetFullPath(path);
|
|
|
+
|
|
|
+ // Split the path into its components
|
|
|
+ string[] pathParts = normalizedPath.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
+
|
|
|
+ string? currentPath = _fileSystem.Path.GetPathRoot(normalizedPath);
|
|
|
+ MemoryDirectoryEntry? currentDir = null;
|
|
|
+
|
|
|
+ // Ensure the root directory exists
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(currentPath ?? string.Empty, out var rootEntry))
|
|
|
+ {
|
|
|
+ rootEntry = new MemoryDirectoryEntry
|
|
|
+ {
|
|
|
+ Name = currentPath ?? string.Empty,
|
|
|
+ FullName = currentPath ?? string.Empty,
|
|
|
+ Attributes = FileAttributes.Directory,
|
|
|
+ CreationTime = DateTime.Now,
|
|
|
+ LastAccessTime = DateTime.Now,
|
|
|
+ LastWriteTime = DateTime.Now
|
|
|
+ };
|
|
|
+ _fileSystem.FileSystemDictionary[currentPath ?? string.Empty] = rootEntry;
|
|
|
+ }
|
|
|
+ currentDir = (MemoryDirectoryEntry)rootEntry;
|
|
|
+
|
|
|
+ // Create or navigate through each directory in the path
|
|
|
+ foreach (string part in pathParts.Skip(1)) // Skip the root
|
|
|
+ {
|
|
|
+ currentPath = Path.Combine(currentPath ?? string.Empty, part);
|
|
|
+
|
|
|
+ if (_fileSystem.FileSystemDictionary.TryGetValue(currentPath, out var existingEntry))
|
|
|
+ {
|
|
|
+ if (existingEntry is MemoryFileEntry)
|
|
|
+ {
|
|
|
+ throw new IOException($"Cannot create directory '{currentPath}': A file with the same name already exists.");
|
|
|
+ }
|
|
|
+ currentDir = (MemoryDirectoryEntry)existingEntry;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var newDir = new MemoryDirectoryEntry
|
|
|
+ {
|
|
|
+ Name = part,
|
|
|
+ FullName = currentPath,
|
|
|
+ Attributes = FileAttributes.Directory,
|
|
|
+ CreationTime = DateTime.Now,
|
|
|
+ LastAccessTime = DateTime.Now,
|
|
|
+ LastWriteTime = DateTime.Now
|
|
|
+ };
|
|
|
+ _fileSystem.FileSystemDictionary[currentPath] = newDir;
|
|
|
+ currentDir.Children[part] = newDir;
|
|
|
+ currentDir = newDir;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update the last access time of the final directory
|
|
|
+ currentDir.LastAccessTime = DateTime.Now;
|
|
|
+
|
|
|
+ // Return an IDirectoryInfo object for the created or existing directory
|
|
|
+ return new MemoryDirectoryInfo(_fileSystem, normalizedPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Delete(string path)
|
|
|
+ {
|
|
|
+ Delete(path, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Delete(string path, bool recursive)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) || !(entry is MemoryDirectoryEntry dirEntry))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Directory not found: {normalizedPath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!recursive && dirEntry.Children.Count > 0)
|
|
|
+ {
|
|
|
+ throw new IOException($"The directory '{normalizedPath}' is not empty.");
|
|
|
+ }
|
|
|
+
|
|
|
+ var keysToRemove = _fileSystem.FileSystemDictionary.Keys
|
|
|
+ .Where(k => k.StartsWith(normalizedPath))
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ foreach (var key in keysToRemove)
|
|
|
+ {
|
|
|
+ _fileSystem.FileSystemDictionary.Remove(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateDirectories(string path)
|
|
|
+ {
|
|
|
+ return EnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateDirectories(string path, string searchPattern)
|
|
|
+ {
|
|
|
+ return EnumerateDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateDirectories(string path, string searchPattern, SearchOption searchOption)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) || !(entry is MemoryDirectoryEntry dirEntry))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Directory not found: {normalizedPath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var directories = new List<string>();
|
|
|
+ EnumerateDirectoriesRecursive(dirEntry, searchPattern, searchOption, directories);
|
|
|
+ return directories;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EnumerateDirectoriesRecursive(MemoryDirectoryEntry directory, string searchPattern, SearchOption searchOption, List<string> result)
|
|
|
+ {
|
|
|
+ foreach (var child in directory.Children.Values)
|
|
|
+ {
|
|
|
+ if (child is MemoryDirectoryEntry childDir && MatchesPattern(child.Name, searchPattern))
|
|
|
+ {
|
|
|
+ result.Add(child.FullName);
|
|
|
+ if (searchOption == SearchOption.AllDirectories)
|
|
|
+ {
|
|
|
+ EnumerateDirectoriesRecursive(childDir, searchPattern, searchOption, result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFiles(string path)
|
|
|
+ {
|
|
|
+ return EnumerateFiles(path, "*", SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFiles(string path, string searchPattern)
|
|
|
+ {
|
|
|
+ return EnumerateFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOption)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) || !(entry is MemoryDirectoryEntry dirEntry))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Directory not found: {normalizedPath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var files = new List<string>();
|
|
|
+ EnumerateFilesRecursive(dirEntry, searchPattern, searchOption, files);
|
|
|
+ return files;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EnumerateFilesRecursive(MemoryDirectoryEntry directory, string searchPattern, SearchOption searchOption, List<string> result)
|
|
|
+ {
|
|
|
+ foreach (var child in directory.Children.Values)
|
|
|
+ {
|
|
|
+ if (child is MemoryFileEntry && MatchesPattern(child.Name, searchPattern))
|
|
|
+ {
|
|
|
+ result.Add(child.FullName);
|
|
|
+ }
|
|
|
+ else if (child is MemoryDirectoryEntry childDir && searchOption == SearchOption.AllDirectories)
|
|
|
+ {
|
|
|
+ EnumerateFilesRecursive(childDir, searchPattern, searchOption, result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFileSystemEntries(string path)
|
|
|
+ {
|
|
|
+ return EnumerateFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern)
|
|
|
+ {
|
|
|
+ return EnumerateFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) || !(entry is MemoryDirectoryEntry dirEntry))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Directory not found: {normalizedPath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var entries = new List<string>();
|
|
|
+ EnumerateFileSystemEntriesRecursive(dirEntry, searchPattern, searchOption, entries);
|
|
|
+ return entries;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EnumerateFileSystemEntriesRecursive(MemoryDirectoryEntry directory, string searchPattern, SearchOption searchOption, List<string> result)
|
|
|
+ {
|
|
|
+ foreach (var child in directory.Children.Values)
|
|
|
+ {
|
|
|
+ if (MatchesPattern(child.Name, searchPattern))
|
|
|
+ {
|
|
|
+ result.Add(child.FullName);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (child is MemoryDirectoryEntry childDir && searchOption == SearchOption.AllDirectories)
|
|
|
+ {
|
|
|
+ EnumerateFileSystemEntriesRecursive(childDir, searchPattern, searchOption, result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool Exists(string? path)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ return _fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) && entry is MemoryDirectoryEntry;
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetDirectories(string path)
|
|
|
+ {
|
|
|
+ return GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetDirectories(string path, string searchPattern)
|
|
|
+ {
|
|
|
+ return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetDirectories(string path, string searchPattern, SearchOption searchOption)
|
|
|
+ {
|
|
|
+ return EnumerateDirectories(path, searchPattern, searchOption).ToArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFiles(string path)
|
|
|
+ {
|
|
|
+ return GetFiles(path, "*", SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFiles(string path, string searchPattern)
|
|
|
+ {
|
|
|
+ return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
|
|
|
+ {
|
|
|
+ return EnumerateFiles(path, searchPattern, searchOption).ToArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFileSystemEntries(string path)
|
|
|
+ {
|
|
|
+ return GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFileSystemEntries(string path, string searchPattern)
|
|
|
+ {
|
|
|
+ return GetFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
|
|
|
+ {
|
|
|
+ return EnumerateFileSystemEntries(path, searchPattern, searchOption).ToArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Move(string sourceDirName, string destDirName)
|
|
|
+ {
|
|
|
+ var normalizedSourcePath = NormalizePath(sourceDirName);
|
|
|
+ var normalizedDestPath = NormalizePath(destDirName);
|
|
|
+
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedSourcePath, out var sourceEntry) || !(sourceEntry is MemoryDirectoryEntry sourceDir))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Source directory not found: {normalizedSourcePath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_fileSystem.FileSystemDictionary.ContainsKey(normalizedDestPath))
|
|
|
+ {
|
|
|
+ throw new IOException($"Cannot create '{normalizedDestPath}' because a file or directory with the same name already exists.");
|
|
|
+ }
|
|
|
+
|
|
|
+ var entriesToMove = _fileSystem.FileSystemDictionary
|
|
|
+ .Where(kvp => kvp.Key.StartsWith(normalizedSourcePath))
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ foreach (var entry in entriesToMove)
|
|
|
+ {
|
|
|
+ var newPath = entry.Key.Replace(normalizedSourcePath, normalizedDestPath);
|
|
|
+ _fileSystem.FileSystemDictionary[newPath] = entry.Value;
|
|
|
+ entry.Value.FullName = newPath;
|
|
|
+ _fileSystem.FileSystemDictionary.Remove(entry.Key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private string NormalizePath(string? path)
|
|
|
+ {
|
|
|
+ if (path == null)
|
|
|
+ return string.Empty;
|
|
|
+ return Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool MatchesPattern(string name, string pattern)
|
|
|
+ {
|
|
|
+ return System.Text.RegularExpressions.Regex.IsMatch(name, "^" + System.Text.RegularExpressions.Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$");
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, EnumerationOptions enumerationOptions)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) || !(entry is MemoryDirectoryEntry dirEntry))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Directory not found: {normalizedPath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var entries = new List<string>();
|
|
|
+ EnumerateFileSystemEntriesRecursive(dirEntry, searchPattern, enumerationOptions, entries);
|
|
|
+ return entries;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EnumerateFileSystemEntriesRecursive(MemoryDirectoryEntry directory, string searchPattern, EnumerationOptions options, List<string> result)
|
|
|
+ {
|
|
|
+ foreach (var child in directory.Children.Values)
|
|
|
+ {
|
|
|
+ if (ShouldIncludeEntry(child, searchPattern, options))
|
|
|
+ {
|
|
|
+ result.Add(child.FullName);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (child is MemoryDirectoryEntry childDir && options.RecurseSubdirectories)
|
|
|
+ {
|
|
|
+ EnumerateFileSystemEntriesRecursive(childDir, searchPattern, options, result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (options.ReturnSpecialDirectories)
|
|
|
+ {
|
|
|
+ if (MatchesPattern(".", searchPattern, options) && !result.Contains(directory.FullName))
|
|
|
+ {
|
|
|
+ result.Add(directory.FullName);
|
|
|
+ }
|
|
|
+
|
|
|
+ var parentDir = Path.GetDirectoryName(directory.FullName);
|
|
|
+ if (parentDir != null && MatchesPattern("..", searchPattern, options) && !result.Contains(parentDir))
|
|
|
+ {
|
|
|
+ result.Add(parentDir);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool ShouldIncludeEntry(MemoryFileSystemEntry entry, string searchPattern, EnumerationOptions options)
|
|
|
+ {
|
|
|
+ if ((entry.Attributes & options.AttributesToSkip) != 0)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (options.IgnoreInaccessible)
|
|
|
+ {
|
|
|
+ // Simulate inaccessible entries (e.g., by checking a hypothetical 'IsAccessible' property)
|
|
|
+ // For this example, we'll assume all entries are accessible
|
|
|
+ }
|
|
|
+
|
|
|
+ return MatchesPattern(entry.Name, searchPattern, options);
|
|
|
+ }
|
|
|
+ public IEnumerable<string> EnumerateFiles(string path, string searchPattern, EnumerationOptions enumerationOptions)
|
|
|
+ {
|
|
|
+ var normalizedPath = NormalizePath(path);
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(normalizedPath, out var entry) || !(entry is MemoryDirectoryEntry dirEntry))
|
|
|
+ {
|
|
|
+ throw new DirectoryNotFoundException($"Directory not found: {normalizedPath}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var files = new List<string>();
|
|
|
+ EnumerateFilesRecursive(dirEntry, searchPattern, enumerationOptions, files);
|
|
|
+ return files;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EnumerateFilesRecursive(MemoryDirectoryEntry directory, string searchPattern, EnumerationOptions options, List<string> result)
|
|
|
+ {
|
|
|
+ foreach (var child in directory.Children.Values)
|
|
|
+ {
|
|
|
+ if (child is MemoryFileEntry fileEntry)
|
|
|
+ {
|
|
|
+ if (ShouldIncludeFile(fileEntry, searchPattern, options))
|
|
|
+ {
|
|
|
+ result.Add(child.FullName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (child is MemoryDirectoryEntry childDir && options.RecurseSubdirectories)
|
|
|
+ {
|
|
|
+ EnumerateFilesRecursive(childDir, searchPattern, options, result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool ShouldIncludeFile(MemoryFileEntry file, string searchPattern, EnumerationOptions options)
|
|
|
+ {
|
|
|
+ if ((file.Attributes & options.AttributesToSkip) != 0)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (options.IgnoreInaccessible)
|
|
|
+ {
|
|
|
+ // Simulate inaccessible files (e.g., by checking a hypothetical 'IsAccessible' property)
|
|
|
+ // For this example, we'll assume all files are accessible
|
|
|
+ }
|
|
|
+
|
|
|
+ return MatchesPattern(file.Name, searchPattern, options);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private bool MatchesWin32(string name, string pattern, MatchCasing matchCasing)
|
|
|
+ {
|
|
|
+ string regexPattern = "^" + Regex.Escape(pattern)
|
|
|
+ .Replace("\\*", ".*")
|
|
|
+ .Replace("\\?", ".")
|
|
|
+ + "$";
|
|
|
+
|
|
|
+ RegexOptions regexOptions = matchCasing == MatchCasing.CaseInsensitive
|
|
|
+ ? RegexOptions.IgnoreCase
|
|
|
+ : RegexOptions.None;
|
|
|
+
|
|
|
+ return Regex.IsMatch(name, regexPattern, regexOptions);
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool MatchesSimple(string name, string pattern, MatchCasing matchCasing)
|
|
|
+ {
|
|
|
+ return matchCasing == MatchCasing.CaseInsensitive
|
|
|
+ ? name.Equals(pattern, StringComparison.OrdinalIgnoreCase)
|
|
|
+ : name.Equals(pattern, StringComparison.Ordinal);
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool MatchesRegex(string name, string pattern, MatchCasing matchCasing)
|
|
|
+ {
|
|
|
+ RegexOptions regexOptions = matchCasing == MatchCasing.CaseInsensitive
|
|
|
+ ? RegexOptions.IgnoreCase
|
|
|
+ : RegexOptions.None;
|
|
|
+
|
|
|
+ return Regex.IsMatch(name, pattern, regexOptions);
|
|
|
+ }
|
|
|
+ private bool MatchesPattern(string name, string pattern, EnumerationOptions options)
|
|
|
+ {
|
|
|
+ if (options.MatchType == MatchType.Win32)
|
|
|
+ {
|
|
|
+ return MatchesWin32(name, pattern, options.MatchCasing);
|
|
|
+ }
|
|
|
+ else if (options.MatchType == MatchType.Simple)
|
|
|
+ {
|
|
|
+ return MatchesSimple(name, pattern, options.MatchCasing);
|
|
|
+ }
|
|
|
+ else // MatchType.Regular
|
|
|
+ {
|
|
|
+ return MatchesRegex(name, pattern, options.MatchCasing);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public IDirectoryInfo CreateDirectory(string path, UnixFileMode unixCreateMode)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(path))
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Path cannot be null or whitespace.", nameof(path));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Normalize the path
|
|
|
+ string normalizedPath = _fileSystem.Path.GetFullPath(path);
|
|
|
+
|
|
|
+ // Split the path into its components
|
|
|
+ string[] pathParts = normalizedPath.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
+
|
|
|
+ string? currentPath = _fileSystem.Path.GetPathRoot(normalizedPath);
|
|
|
+ MemoryDirectoryEntry? currentDir = null;
|
|
|
+
|
|
|
+ // Ensure the root directory exists
|
|
|
+ if (!_fileSystem.FileSystemDictionary.TryGetValue(currentPath ?? string.Empty, out var rootEntry))
|
|
|
+ {
|
|
|
+ rootEntry = new MemoryDirectoryEntry
|
|
|
+ {
|
|
|
+ Name = currentPath ?? string.Empty,
|
|
|
+ FullName = currentPath ?? string.Empty,
|
|
|
+ Attributes = FileAttributes.Directory,
|
|
|
+ CreationTime = DateTime.Now,
|
|
|
+ LastAccessTime = DateTime.Now,
|
|
|
+ LastWriteTime = DateTime.Now,
|
|
|
+ UnixFileMode = System.IO.UnixFileMode.None
|
|
|
+ };
|
|
|
+ _fileSystem.FileSystemDictionary[currentPath ?? string.Empty] = rootEntry;
|
|
|
+ }
|
|
|
+ currentDir = (MemoryDirectoryEntry)rootEntry;
|
|
|
+
|
|
|
+ // Create or navigate through each directory in the path
|
|
|
+ foreach (string part in pathParts.Skip(1)) // Skip the root
|
|
|
+ {
|
|
|
+ currentPath = Path.Combine(currentPath ?? string.Empty, part);
|
|
|
+
|
|
|
+ if (_fileSystem.FileSystemDictionary.TryGetValue(currentPath, out var existingEntry))
|
|
|
+ {
|
|
|
+ if (existingEntry is MemoryFileEntry)
|
|
|
+ {
|
|
|
+ throw new IOException($"Cannot create directory '{currentPath}': A file with the same name already exists.");
|
|
|
+ }
|
|
|
+ currentDir = (MemoryDirectoryEntry)existingEntry;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var newDir = new MemoryDirectoryEntry
|
|
|
+ {
|
|
|
+ Name = part,
|
|
|
+ FullName = currentPath,
|
|
|
+ Attributes = FileAttributes.Directory,
|
|
|
+ CreationTime = DateTime.Now,
|
|
|
+ LastAccessTime = DateTime.Now,
|
|
|
+ LastWriteTime = DateTime.Now,
|
|
|
+ UnixFileMode = unixCreateMode
|
|
|
+ };
|
|
|
+ _fileSystem.FileSystemDictionary[currentPath] = newDir;
|
|
|
+ currentDir.Children[part] = newDir;
|
|
|
+ currentDir = newDir;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update the last access time of the final directory
|
|
|
+ currentDir.LastAccessTime = DateTime.Now;
|
|
|
+
|
|
|
+ // Return an IDirectoryInfo object for the created or existing directory
|
|
|
+ return new MemoryDirectoryInfo(_fileSystem, normalizedPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(path))
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Path cannot be null or whitespace.", nameof(path));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (string.IsNullOrWhiteSpace(pathToTarget))
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Target path cannot be null or whitespace.", nameof(pathToTarget));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Normalize the paths
|
|
|
+ string normalizedPath = _fileSystem.Path.GetFullPath(path);
|
|
|
+ string normalizedTargetPath = _fileSystem.Path.GetFullPath(pathToTarget);
|
|
|
+
|
|
|
+ // Check if the symlink already exists
|
|
|
+ if (_fileSystem.FileSystemDictionary.ContainsKey(normalizedPath))
|
|
|
+ {
|
|
|
+ throw new IOException($"Cannot create '{normalizedPath}': A file or directory with the same name already exists.");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Determine if the target is a file or directory
|
|
|
+ bool isTargetDirectory = _fileSystem.Directory.Exists(normalizedTargetPath);
|
|
|
+
|
|
|
+ // Create the symbolic link entry
|
|
|
+ MemoryFileSystemEntry symlinkEntry;
|
|
|
+ if (isTargetDirectory)
|
|
|
+ {
|
|
|
+ symlinkEntry = new MemoryDirectoryEntry
|
|
|
+ {
|
|
|
+ Name = _fileSystem.Path.GetFileName(normalizedPath),
|
|
|
+ FullName = normalizedPath,
|
|
|
+ Attributes = FileAttributes.Directory | FileAttributes.ReparsePoint,
|
|
|
+ CreationTime = DateTime.Now,
|
|
|
+ LastAccessTime = DateTime.Now,
|
|
|
+ LastWriteTime = DateTime.Now,
|
|
|
+ IsSymbolicLink = true,
|
|
|
+ SymbolicLinkTarget = normalizedTargetPath
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ symlinkEntry = new MemoryFileEntry
|
|
|
+ {
|
|
|
+ Name = _fileSystem.Path.GetFileName(normalizedPath),
|
|
|
+ FullName = normalizedPath,
|
|
|
+ Attributes = FileAttributes.ReparsePoint,
|
|
|
+ CreationTime = DateTime.Now,
|
|
|
+ LastAccessTime = DateTime.Now,
|
|
|
+ LastWriteTime = DateTime.Now,
|
|
|
+ IsSymbolicLink = true,
|
|
|
+ SymbolicLinkTarget = normalizedTargetPath
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add the symlink to the file system
|
|
|
+ _fileSystem.FileSystemDictionary[normalizedPath] = symlinkEntry;
|
|
|
+
|
|
|
+ // Add the symlink to its parent directory's children
|
|
|
+ string? parentPath = _fileSystem.Path.GetDirectoryName(normalizedPath);
|
|
|
+ if (_fileSystem.FileSystemDictionary.TryGetValue(parentPath ?? string.Empty, out var parentEntry) && parentEntry is MemoryDirectoryEntry parentDir)
|
|
|
+ {
|
|
|
+ parentDir.Children[symlinkEntry.Name] = symlinkEntry;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Return the appropriate IFileSystemInfo object
|
|
|
+ return isTargetDirectory
|
|
|
+ ? (IFileSystemInfo)new MemoryDirectoryInfo(_fileSystem, normalizedPath)
|
|
|
+ : new MemoryFileInfo(_fileSystem, normalizedPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IDirectoryInfo CreateTempSubdirectory(string? prefix = null)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<string> EnumerateDirectories(string path, string searchPattern, EnumerationOptions enumerationOptions)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public DateTime GetCreationTime(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public DateTime GetCreationTimeUtc(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string GetCurrentDirectory()
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetDirectories(string path, string searchPattern, EnumerationOptions enumerationOptions)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string GetDirectoryRoot(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFiles(string path, string searchPattern, EnumerationOptions enumerationOptions)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetFileSystemEntries(string path, string searchPattern, EnumerationOptions enumerationOptions)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public DateTime GetLastAccessTime(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public DateTime GetLastAccessTimeUtc(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public DateTime GetLastWriteTime(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public DateTime GetLastWriteTimeUtc(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] GetLogicalDrives()
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public IDirectoryInfo? GetParent(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public IFileSystemInfo? ResolveLinkTarget(string linkPath, bool returnFinalTarget)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetCreationTime(string path, DateTime creationTime)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetCreationTimeUtc(string path, DateTime creationTimeUtc)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetCurrentDirectory(string path)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetLastAccessTime(string path, DateTime lastAccessTime)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetLastWriteTime(string path, DateTime lastWriteTime)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc)
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Implement other methods (e.g., GetParent, GetDirectoryRoot) as needed
|
|
|
+ }
|
|
|
+}
|