using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Threading; using Robust.Shared.Utility; namespace Robust.Shared.ContentPack { /// internal sealed class WritableDirProvider : IWritableDirProvider { private readonly bool _hideRootDir; public string RootDir { get; } string? IWritableDirProvider.RootDir => _hideRootDir ? null : RootDir; /// /// Constructs an instance of . /// /// Root file system directory to allow writing. /// If true, is reported as null. public WritableDirProvider(DirectoryInfo rootDir, bool hideRootDir) { // FullName does not have a trailing separator, and we MUST have a separator. RootDir = rootDir.FullName + Path.DirectorySeparatorChar.ToString(); _hideRootDir = hideRootDir; } #region File Access /// public void CreateDir(ResPath path) { var fullPath = GetFullPath(path); Directory.CreateDirectory(fullPath); } /// public void Delete(ResPath path) { var fullPath = GetFullPath(path); if (Directory.Exists(fullPath)) { Directory.Delete(fullPath, true); } else if (File.Exists(fullPath)) { File.Delete(fullPath); } } /// public bool Exists(ResPath path) { var fullPath = GetFullPath(path); return Directory.Exists(fullPath) || File.Exists(fullPath); } /// public (IEnumerable files, IEnumerable directories) Find(string pattern, bool recursive = true) { if (pattern.Contains("..")) throw new InvalidOperationException($"Pattern may not contain '..'. Pattern: {pattern}."); var rootLen = RootDir.Length - 1; var option = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; var files = Directory.GetFiles(RootDir, pattern, option); var dirs = Directory.GetDirectories(RootDir, pattern, option); var resFiles = new List(files.Length); var resDirs = new List(dirs.Length); foreach (var file in files) { if (file.Contains("\\..") || file.Contains("/..")) continue; resFiles.Add(ResPath.FromRelativeSystemPath(file.Substring(rootLen)).ToRootedPath()); } foreach (var dir in dirs) { if (dir.Contains("\\..") || dir.Contains("/..")) continue; resDirs.Add(ResPath.FromRelativeSystemPath(dir.Substring(rootLen)).ToRootedPath()); } return (resFiles, resDirs); } public IEnumerable DirectoryEntries(ResPath path) { var fullPath = GetFullPath(path); if (!Directory.Exists(fullPath)) yield break; foreach (var entry in Directory.EnumerateFileSystemEntries(fullPath)) { yield return Path.GetRelativePath(fullPath, entry); } } /// public bool IsDir(ResPath path) { return Directory.Exists(GetFullPath(path)); } /// public Stream Open(ResPath path, FileMode fileMode, FileAccess access, FileShare share) { var fullPath = GetFullPath(path); return File.Open(fullPath, fileMode, access, share); } public IWritableDirProvider OpenSubdirectory(ResPath path) { if (!IsDir(path)) throw new FileNotFoundException(); var dirInfo = new DirectoryInfo(GetFullPath(path)); return new WritableDirProvider(dirInfo, _hideRootDir); } /// public void Rename(ResPath oldPath, ResPath newPath) { var fullOldPath = GetFullPath(oldPath); var fullNewPath = GetFullPath(newPath); File.Move(fullOldPath, fullNewPath); } public void OpenOsWindow(ResPath path) { if (!IsDir(path)) path = path.Directory; var fullPath = GetFullPath(path); if (OperatingSystem.IsWindows()) { Process.Start(new ProcessStartInfo { FileName = $"{Environment.GetEnvironmentVariable("SystemRoot")}\\explorer.exe", Arguments = ".", WorkingDirectory = fullPath, }); } else if (OperatingSystem.IsMacOS()) { Process.Start(new ProcessStartInfo { FileName = "open", Arguments = ".", WorkingDirectory = fullPath, }); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD()) { Process.Start(new ProcessStartInfo { FileName = "xdg-open", Arguments = ".", WorkingDirectory = fullPath, }); } else { throw new NotSupportedException("Opening OS windows not supported on this OS"); } } #endregion public string GetFullPath(ResPath path) { if (!path.IsRooted) { throw new ArgumentException($"Path must be rooted. Path: {path}"); } path = path.Clean(); return PathHelpers.SafeGetResourcePath(RootDir, path); } } }