1023 lines
33 KiB
C#
1023 lines
33 KiB
C#
/*
|
|
Tesses.VirtualFilesystem a library for virtual filesystems in .NET
|
|
Copyright (C) 2023 Mike Nolan
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Tesses.VirtualFilesystem
|
|
{
|
|
public sealed class NonExistantPointer : EntryPointer
|
|
{
|
|
public override bool IsNonExistantPointer => true;
|
|
public NonExistantPointer(IVirtualFilesystem fs,UnixPath path) : base(fs,path)
|
|
{
|
|
|
|
}
|
|
|
|
public override bool Exists => false;
|
|
public override string Name { get => Path.Name; set {} }
|
|
|
|
public override void Delete()
|
|
{
|
|
|
|
}
|
|
}
|
|
public abstract class EntryPointer
|
|
{
|
|
public virtual bool IsNonExistantPointer {get{return false;}}
|
|
public virtual bool IsFilePointer {get{return false;}}
|
|
public virtual bool IsDirectoryPointer {get{return false;}}
|
|
|
|
public virtual bool IsSymlinkPointer {get{return false;}}
|
|
public EntryPointer this[UnixPath path]
|
|
{
|
|
get{
|
|
return _fs.OpenEntry(Path / path);
|
|
}
|
|
}
|
|
public DirectoryPointer AsDirectoryPointer()
|
|
{
|
|
return new DirectoryPointer(_fs,Path);
|
|
}
|
|
public FilePointer AsFilePointer()
|
|
{
|
|
return new FilePointer(_fs,Path);
|
|
}
|
|
public SymlinkPointer AsSymlinkPointer()
|
|
{
|
|
return new SymlinkPointer(_fs,Path);
|
|
}
|
|
internal EntryPointer(IVirtualFilesystem fs)
|
|
{
|
|
_fs=fs;
|
|
}
|
|
internal EntryPointer(IVirtualFilesystem fs,UnixPath path) : this(fs)
|
|
{
|
|
Path = path;
|
|
}
|
|
protected IVirtualFilesystem _fs;
|
|
|
|
public IVirtualFilesystem Filesystem {get{return _fs;}}
|
|
public UnixPath Path {get;set;}="/";
|
|
public abstract string Name {get;set;}
|
|
|
|
public UnixPath WithPath(UnixPath path)
|
|
{
|
|
return Path / path;
|
|
}
|
|
public DirectoryPointer Up()
|
|
{
|
|
return new DirectoryPointer(_fs,_fs.UpPath(Path));
|
|
}
|
|
public abstract void Delete();
|
|
public abstract bool Exists {get;}
|
|
}
|
|
|
|
public sealed class SymlinkPointer : EntryPointer
|
|
{
|
|
public override bool IsSymlinkPointer => true;
|
|
public SymlinkPointer(IVirtualFilesystem fs,UnixPath path) : base(fs,path)
|
|
{
|
|
|
|
}
|
|
private void _setName(string name)
|
|
{
|
|
UnixPath oldPath = Path;
|
|
UnixPath target= Target;
|
|
Delete();
|
|
Path.Name = name;
|
|
Target= target;
|
|
|
|
}
|
|
public override string Name { get => Path.Name; set => _setName(value); }
|
|
|
|
public override bool Exists => _fs.SymlinkExists(Path);
|
|
|
|
public override void Delete()
|
|
{
|
|
if(Exists)
|
|
_fs.DeleteFile(Path);
|
|
}
|
|
|
|
public UnixPath Target {
|
|
get{
|
|
return _fs.ReadLink(Path);
|
|
}
|
|
set{
|
|
Delete();
|
|
_fs.CreateSymlink(value,Path);
|
|
}
|
|
}
|
|
public EntryPointer TargetPointer
|
|
{
|
|
get
|
|
{
|
|
return _fs.OpenEntry(Target);
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed class FilePointer : EntryPointer
|
|
{
|
|
public override bool IsFilePointer => true;
|
|
public FilePointer(IVirtualFilesystem fs,UnixPath path) : base(fs,path)
|
|
{
|
|
|
|
}
|
|
public Stream Create()
|
|
{
|
|
return _fs.Open(Path,FileMode.Create,FileAccess.Write,FileShare.Inheritable);
|
|
}
|
|
public Stream OpenRead()
|
|
{
|
|
return _fs.Open(Path,FileMode.Open,FileAccess.Read,FileShare.Read);
|
|
}
|
|
public Stream OpenWrite()
|
|
{
|
|
return _fs.Open(Path,FileMode.OpenOrCreate,FileAccess.Write,FileShare.Inheritable);
|
|
}
|
|
|
|
public void WriteAllText(string text,Encoding encoding)
|
|
{
|
|
using(var f = Create())
|
|
StreamHelper.WriteAllText(f,text,encoding);
|
|
}
|
|
public void WriteAllText(string text)
|
|
{
|
|
WriteAllText(text,Encoding.UTF8);
|
|
}
|
|
public string ReadAllText(Encoding encoding)
|
|
{
|
|
using(var f = OpenRead())
|
|
return StreamHelper.ReadAllText(f,encoding);
|
|
}
|
|
public override bool Exists => _fs.FileExists(Path);
|
|
public void WriteAllBytes(byte[] data)
|
|
{
|
|
using(var f = Create())
|
|
StreamHelper.WriteAllBytes(f,data);
|
|
}
|
|
public byte[] ReadAllBytes()
|
|
{
|
|
using(var f = OpenRead())
|
|
return StreamHelper.ReadAllBytes(f);
|
|
}
|
|
public override void Delete()
|
|
{
|
|
_fs.DeleteFile(Path);
|
|
}
|
|
public override string Name
|
|
{
|
|
get
|
|
{
|
|
return Path.Name;
|
|
}
|
|
set
|
|
{
|
|
UnixPath old = new UnixPath(Path);
|
|
Path.Name = value;
|
|
_fs.MoveFile(old,Path);
|
|
}
|
|
}
|
|
}
|
|
public class DirectoryPointer : EntryPointer, IEnumerable<EntryPointer>
|
|
{
|
|
|
|
public override bool IsDirectoryPointer => true;
|
|
public DirectoryPointer(IVirtualFilesystem fs) : base(fs)
|
|
{
|
|
|
|
}
|
|
public DirectoryPointer(IVirtualFilesystem fs,UnixPath path) : this(fs)
|
|
{
|
|
|
|
Path = path;
|
|
}
|
|
public void Create()
|
|
{
|
|
_fs.CreateDirectory(Path);
|
|
}
|
|
public override void Delete()
|
|
{
|
|
_fs.DeleteDirectory(Path);
|
|
}
|
|
public void DeleteRecursive()
|
|
{
|
|
_fs.DeleteDirectory(Path,true);
|
|
}
|
|
|
|
public IVirtualFilesystem SubDirectoryFilesystem {get{return _fs.GetSubdirFilesystem(Path);}}
|
|
|
|
public DirectoryPointer[] Directories
|
|
{
|
|
get{
|
|
return EnumerateDirectories().ToArray();
|
|
}
|
|
}
|
|
public FilePointer[] Files
|
|
{
|
|
get{
|
|
return EnumerateFiles().ToArray();
|
|
}
|
|
}
|
|
public SymlinkPointer[] Symlinks
|
|
{
|
|
get{
|
|
return EnumerateSymlinks().ToArray();
|
|
}
|
|
}
|
|
public EntryPointer[] Entries
|
|
{
|
|
get {
|
|
return EnumerateEntries().ToArray();
|
|
}
|
|
}
|
|
|
|
public IEnumerable<DirectoryPointer> EnumerateDirectories()
|
|
{
|
|
foreach(var item in _fs.EnumerateDirectories(Path))
|
|
{
|
|
yield return new DirectoryPointer(_fs,item);
|
|
}
|
|
}
|
|
public IEnumerable<FilePointer> EnumerateFiles()
|
|
{
|
|
foreach(var item in _fs.EnumerateFiles(Path))
|
|
{
|
|
yield return new FilePointer(_fs,item);
|
|
}
|
|
|
|
}
|
|
public IEnumerable<SymlinkPointer> EnumerateSymlinks()
|
|
{
|
|
foreach(var item in _fs.EnumerateSymlinks(Path))
|
|
{
|
|
yield return new SymlinkPointer(_fs,item);
|
|
}
|
|
}
|
|
public static DirectoryPointer operator/(DirectoryPointer pointer,string path)
|
|
{
|
|
return new DirectoryPointer(pointer._fs,pointer.Path / path);
|
|
}
|
|
public static DirectoryPointer operator/(DirectoryPointer pointer,UnixPath path)
|
|
{
|
|
return new DirectoryPointer(pointer._fs,pointer.Path / path);
|
|
}
|
|
public IEnumerable<EntryPointer> EnumerateEntries()
|
|
{
|
|
foreach(var item in _fs.EnumerateFileSystemEntries(Path))
|
|
{
|
|
yield return _fs.OpenEntry(item);
|
|
}
|
|
}
|
|
|
|
public IEnumerator<EntryPointer> GetEnumerator()
|
|
{
|
|
return EnumerateEntries().GetEnumerator();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return EnumerateEntries().GetEnumerator();
|
|
}
|
|
|
|
public override bool Exists {get{return _fs.DirectoryExists(Path);}}
|
|
|
|
public override string Name
|
|
{
|
|
get
|
|
{
|
|
return Path.Name;
|
|
}
|
|
set
|
|
{
|
|
UnixPath old = new UnixPath(Path);
|
|
Path.Name = value;
|
|
_fs.MoveDirectory(old,Path);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
public static class StreamHelper
|
|
{
|
|
public static string ReadAllText(Stream strm,Encoding enc)
|
|
{
|
|
using(var sr = new StreamReader(strm,enc))
|
|
{
|
|
return sr.ReadToEnd();
|
|
}
|
|
}
|
|
public static string ReadAllText(Stream strm)
|
|
{
|
|
return ReadAllText(strm,Encoding.UTF8);
|
|
}
|
|
public static byte[] ReadAllBytes(Stream strm)
|
|
{
|
|
MemoryStream ms=new MemoryStream();
|
|
strm.CopyTo(ms);
|
|
return ms.ToArray();
|
|
}
|
|
public static void WriteAllBytes(Stream strm,byte[] data)
|
|
{
|
|
using(MemoryStream ms = new MemoryStream(data))
|
|
ms.CopyTo(strm);
|
|
}
|
|
|
|
public static void WriteAllText(Stream strm,string text,Encoding enc)
|
|
{
|
|
using(var sw = new StreamWriter(strm,enc))
|
|
{
|
|
sw.Write(text);
|
|
}
|
|
}
|
|
public static void WriteAllText(Stream strm,string text)
|
|
{
|
|
WriteAllText(strm,text,Encoding.UTF8);
|
|
}
|
|
public static string[] ReadAllLines(Stream strm,Encoding enc)
|
|
{
|
|
List<string> ls = new List<string>();
|
|
using(var sr = new StreamReader(strm,enc))
|
|
{
|
|
string line;
|
|
while((line=sr.ReadLine()) != null)
|
|
{
|
|
ls.Add(line);
|
|
}
|
|
}
|
|
return ls.ToArray();
|
|
}
|
|
public static string[] ReadAllLines(Stream strm)
|
|
{
|
|
return ReadAllLines(strm,Encoding.UTF8);
|
|
}
|
|
public static void WriteAllLines(Stream strm,IEnumerable<string> lines,Encoding enc)
|
|
{
|
|
using(var sw = new StreamWriter(strm,enc))
|
|
{
|
|
foreach(var line in lines)
|
|
{
|
|
sw.WriteLine(line);
|
|
}
|
|
}
|
|
}
|
|
public static void WriteAllLines(Stream strm,IEnumerable<string> lines)
|
|
{
|
|
WriteAllLines(strm,lines,Encoding.UTF8);
|
|
}
|
|
|
|
|
|
}
|
|
public interface IVirtualFilesystem : IDisposable
|
|
{
|
|
|
|
IVirtualFilesystem GetSubdirFilesystem(UnixPath path);
|
|
EntryPointer OpenEntry(UnixPath path);
|
|
FilePointer OpenFile(UnixPath path);
|
|
SymlinkPointer OpenSymlink(UnixPath path);
|
|
DirectoryPointer OpenDirectory();
|
|
DirectoryPointer OpenDirectory(UnixPath path);
|
|
UnixPath UpPath(UnixPath path);
|
|
UnixPath ConvertPathToUnixPath(string path);
|
|
string ConvertPathFromUnixPath(UnixPath path);
|
|
Stream Open(UnixPath path,FileMode mode,FileAccess access,FileShare share);
|
|
Task<Stream> OpenAsync(UnixPath path,FileMode mode,FileAccess access,FileShare share,CancellationToken token=default(CancellationToken));
|
|
void CreateDirectory(UnixPath directory);
|
|
Task CreateDirectoryAsync(UnixPath directory,CancellationToken token=default(CancellationToken));
|
|
|
|
IEnumerable<UnixPath> EnumerateFileSystemEntries(UnixPath path);
|
|
IEnumerable<UnixPath> EnumerateFiles(UnixPath path);
|
|
IEnumerable<UnixPath> EnumerateDirectories(UnixPath path);
|
|
|
|
IEnumerable<UnixPath> EnumerateSymlinks(UnixPath path);
|
|
|
|
IAsyncEnumerable<UnixPath> EnumerateFilesAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
|
|
IAsyncEnumerable<UnixPath> EnumerateDirectoriesAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
IAsyncEnumerable<UnixPath> EnumerateSymlinksAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
IAsyncEnumerable<UnixPath> EnumerateFileSystemEntriesAsync(UnixPath path,CancellationToken token =default(CancellationToken));
|
|
|
|
bool DirectoryExists(UnixPath path);
|
|
|
|
Task<bool> DirectoryExistsAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
|
|
bool FileExists(UnixPath path);
|
|
|
|
Task<bool> FileExistsAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
|
|
void DeleteFile(UnixPath path);
|
|
void DeleteDirectory(UnixPath path);
|
|
|
|
void DeleteDirectory(UnixPath path,bool recursive);
|
|
void CreateSymlink(UnixPath src,UnixPath dest);
|
|
|
|
void CreateHardlink(UnixPath src,UnixPath dest);
|
|
|
|
UnixPath ReadLink(UnixPath file);
|
|
|
|
Task<UnixPath> ReadLinkAsync(UnixPath file,CancellationToken token=default(CancellationToken));
|
|
bool SymlinkExists(UnixPath file);
|
|
Task<bool> SymlinkExistsAsync(UnixPath file,CancellationToken token=default(CancellationToken));
|
|
Task CreateSymlinkAsync(UnixPath src,UnixPath dest,CancellationToken token=default(CancellationToken));
|
|
Task CreateHardlinkAsync(UnixPath src,UnixPath dest,CancellationToken token=default(CancellationToken));
|
|
Task<bool> SameFileSystemAsync(UnixPath src,UnixPath dest,CancellationToken token=default(CancellationToken));
|
|
bool SameFileSystem(UnixPath src,UnixPath dest);
|
|
bool CanHandleSymlinks(UnixPath path);
|
|
|
|
Task DeleteFileAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
Task DeleteDirectoryAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
Task DeleteDirectoryAsync(UnixPath path,bool recursive,CancellationToken token=default(CancellationToken));
|
|
bool CanWatch(UnixPath path);
|
|
|
|
IVirtualWatcher WatchDirectory(UnixPath dir);
|
|
|
|
void MoveFile(UnixPath src,UnixPath dest);
|
|
|
|
void MoveDirectory(UnixPath src,UnixPath dest);
|
|
|
|
Task MoveFileAsync(UnixPath src,UnixPath dest);
|
|
Task MoveDirectoryAsync(UnixPath src,UnixPath dest);
|
|
|
|
DateTime GetCreationTime(UnixPath path);
|
|
|
|
DateTime GetLastAccessTime(UnixPath path);
|
|
DateTime GetLastWriteTime(UnixPath path);
|
|
|
|
void SetCreationTime(UnixPath path,DateTime time);
|
|
void SetLastAccessTime(UnixPath path,DateTime time);
|
|
void SetLastWriteTime(UnixPath path,DateTime time);
|
|
|
|
void SetAttributes(UnixPath path,FileAttributes attributes);
|
|
|
|
FileAttributes GetAttributes(UnixPath path);
|
|
|
|
Task<DateTime> GetCreationTimeAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
|
|
Task<DateTime> GetLastAccessTimeAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
Task<DateTime> GetLastWriteTimeAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
|
|
Task SetCreationTimeAsync(UnixPath path,DateTime time,CancellationToken token=default(CancellationToken));
|
|
Task SetLastAccessTimeAsync(UnixPath path,DateTime time,CancellationToken token=default(CancellationToken));
|
|
Task SetLastWriteTimeAsync(UnixPath path,DateTime time,CancellationToken token=default(CancellationToken));
|
|
|
|
Task SetAttributesAsync(UnixPath path,FileAttributes attributes,CancellationToken token=default(CancellationToken));
|
|
|
|
Task<FileAttributes> GetAttributesAsync(UnixPath path,CancellationToken token=default(CancellationToken));
|
|
|
|
|
|
}
|
|
|
|
public interface IVirtualWatcher : IDisposable
|
|
{
|
|
|
|
event EventHandler<VirtualWatcherChangedArgs> Changed;
|
|
event EventHandler<VirtualWatcherChangedArgs> Created;
|
|
|
|
event EventHandler<VirtualWatcherChangedArgs> Deleted;
|
|
|
|
event EventHandler<VirtualWatcherRenamedEventArgs> Renamed;
|
|
|
|
event EventHandler<ErrorEventArgs> Error;
|
|
|
|
|
|
/// <summary>
|
|
/// Implementation-defined buffer size for storing events.
|
|
/// </summary>
|
|
int InternalBufferSize { get; set; }
|
|
|
|
/// <summary>
|
|
/// Implementation-defined filters for filtering events.
|
|
/// </summary>
|
|
NotifyFilters NotifyFilter { get; set; }
|
|
|
|
/// <summary>
|
|
/// True to enable raising events, false to never raise them. Default false.
|
|
/// </summary>
|
|
bool EnableRaisingEvents { get; set; }
|
|
|
|
/// <summary>
|
|
/// File name and extension filter. Use <c>"*"</c> to specify variable length placeholder, <c>"?"</c>
|
|
/// for a single character placeholder. Default is <c>"*.*"</c> for all files.
|
|
/// </summary>
|
|
string Filter { get; set; }
|
|
|
|
/// <summary>
|
|
/// True to watch all subdirectories in <see cref="Path"/>, false to only watch entries directly
|
|
/// in <see cref="Path"/>.
|
|
/// </summary>
|
|
bool IncludeSubdirectories { get; set; }
|
|
|
|
}
|
|
|
|
public class VirtualWatcherRenamedEventArgs : VirtualWatcherChangedArgs
|
|
{
|
|
public VirtualWatcherRenamedEventArgs(IVirtualFilesystem fs,WatcherChangeTypes changeTypes,UnixPath newPath,UnixPath oldPath) : base(fs,changeTypes,newPath)
|
|
{
|
|
OldFullPath = oldPath;
|
|
OldName = oldPath.Name;
|
|
}
|
|
public UnixPath OldFullPath {get;}
|
|
public string OldName {get;}
|
|
}
|
|
public class VirtualWatcherChangedArgs : EventArgs
|
|
{
|
|
public VirtualWatcherChangedArgs(IVirtualFilesystem fs,WatcherChangeTypes changeTypes,UnixPath path)
|
|
{
|
|
FullPath=path;
|
|
Name = path.Name;
|
|
Filesystem = fs;
|
|
ChangeType = changeTypes;
|
|
}
|
|
public IVirtualFilesystem Filesystem {get;}
|
|
public WatcherChangeTypes ChangeType {get;}
|
|
|
|
public UnixPath FullPath { get; }
|
|
|
|
public string Name {get;}
|
|
|
|
}
|
|
/*
|
|
public class UnixPathList : UnixPath, IReadOnlyCollection<UnixPath>
|
|
{
|
|
|
|
private string tostr(int i,UnixPath[] paths)
|
|
{
|
|
if(i == 0)
|
|
{
|
|
return paths[0].ToString();
|
|
}
|
|
else
|
|
{
|
|
var p = paths[i];
|
|
if(!string.IsNullOrWhiteSpace(p._scheme))
|
|
{
|
|
return $"{p._scheme}://[{tostr(i-1,paths)}]{p._path}";
|
|
}
|
|
else
|
|
{
|
|
return $"[{tostr(i - 1, paths)}]{p._path}";
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private bool LastIsRoot
|
|
{
|
|
get
|
|
{
|
|
if (Count > 0)
|
|
{
|
|
return _paths[_paths.Length - 1].IsRoot;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
public UnixPathList ParentPL
|
|
{
|
|
get
|
|
{
|
|
if (LastIsRoot)
|
|
{
|
|
List<UnixPath> paths = new List<UnixPath>();
|
|
for (int i = 0; i < Count - 2; i++)
|
|
{
|
|
paths.Add(new UnixPath(this[i]));
|
|
}
|
|
if (Count > 1)
|
|
{
|
|
paths.Add(this[Count - 2].Parent);
|
|
}
|
|
return new UnixPathList(paths);
|
|
}
|
|
else
|
|
{
|
|
List<UnixPath> paths = new List<UnixPath>();
|
|
for (int i = 0; i < Count - 1; i++)
|
|
{
|
|
paths.Add(new UnixPath(this[i]));
|
|
}
|
|
if (Count > 0)
|
|
{
|
|
paths.Add(this[Count - 1].Parent);
|
|
}
|
|
return new UnixPathList(paths);
|
|
}
|
|
}
|
|
}
|
|
UnixPath[] _paths;
|
|
public UnixPathList(params UnixPath[] paths)
|
|
{
|
|
_paths = paths;
|
|
if (_paths.Length > 0)
|
|
{
|
|
_path = _paths[0]._path;
|
|
_parts = _paths[0]._parts;
|
|
_scheme = _paths[0]._scheme;
|
|
}
|
|
}
|
|
|
|
public UnixPathList(IEnumerable<UnixPath> paths) : this(paths.ToArray())
|
|
{
|
|
|
|
}
|
|
|
|
public static UnixPathList Parse(string path)
|
|
{
|
|
List<UnixPath> paths = new List<UnixPath>();
|
|
Parse(path, paths);
|
|
return new UnixPathList(paths);
|
|
}
|
|
private static void Parse(string path, List<UnixPath> paths)
|
|
{
|
|
|
|
string scheme = "";
|
|
if (path.Contains("://"))
|
|
{
|
|
var res = path.Split(new string[] { "://" }, 2, StringSplitOptions.None);
|
|
scheme = res[0] + "://";
|
|
path = res[1];
|
|
}
|
|
if (path[0] == '[')
|
|
{
|
|
int br = 1;
|
|
int i = 1;
|
|
for (; i < path.Length; i++)
|
|
{
|
|
if (path[i] == '[') br++;
|
|
if (path[i] == ']') br--;
|
|
if (br <= 0) break;
|
|
}
|
|
Parse(path.Substring(1, i - 1), paths);
|
|
paths.Add(scheme + path.Substring(i + 1));
|
|
|
|
}
|
|
else
|
|
{
|
|
paths.Add(scheme + path);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public IEnumerator<UnixPath> GetEnumerator()
|
|
{
|
|
return _G().GetEnumerator();
|
|
|
|
}
|
|
private IEnumerable<UnixPath> _G()
|
|
{
|
|
foreach(UnixPath p in _paths)
|
|
{
|
|
yield return p;
|
|
}
|
|
}
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return _G().GetEnumerator();
|
|
}
|
|
|
|
public UnixPath this[int i]
|
|
{
|
|
get
|
|
{
|
|
return _paths[i];
|
|
}
|
|
set
|
|
{
|
|
_paths[i] = value;
|
|
}
|
|
}
|
|
public int Count { get { return _paths.Length; } }
|
|
|
|
public override string AsText
|
|
{
|
|
get
|
|
{
|
|
if (Count < 2)
|
|
{
|
|
return ToString();
|
|
}
|
|
else
|
|
{
|
|
|
|
return tostr(Count-1,_paths);
|
|
}
|
|
}
|
|
}
|
|
private string GetFs()
|
|
{
|
|
return "";
|
|
}
|
|
}*/
|
|
public class Special
|
|
{
|
|
|
|
public static UnixPath CurDir {get{return UnixPath.FromLocal(Environment.CurrentDirectory);} set{Environment.CurrentDirectory = value.ToLocal();}}
|
|
public static UnixPath Root {get;} = new UnixPath();
|
|
public static UnixPath Home {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.UserProfile);}}
|
|
|
|
public static UnixPath Videos {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.MyVideos);}}
|
|
public static UnixPath Pictures {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.MyPictures);}}
|
|
|
|
public static UnixPath Documents {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.MyDocuments);}}
|
|
|
|
public static UnixPath LocalAppData {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.LocalApplicationData);}}
|
|
public static UnixPath RoamingAppData {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.ApplicationData);}}
|
|
|
|
public static UnixPath Music {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.MyMusic);}}
|
|
|
|
public static UnixPath DesktopFolder {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.DesktopDirectory);}}
|
|
|
|
public static UnixPath PublicVideos {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonVideos);}}
|
|
public static UnixPath PublicPictures {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonPictures);}}
|
|
|
|
public static UnixPath PublicDocuments {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonDocuments);}}
|
|
|
|
public static UnixPath PublicAppData {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonApplicationData);}}
|
|
|
|
|
|
public static UnixPath PublicStart {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonStartMenu);}}
|
|
|
|
public static UnixPath PublicTemplates {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonTemplates);}}
|
|
|
|
public static UnixPath Start {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.StartMenu);}}
|
|
public static UnixPath Templates {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.Templates);}}
|
|
|
|
|
|
public static UnixPath ProgramFiles {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.ProgramFiles);}}
|
|
|
|
public static UnixPath ProgramFilesX86 {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.ProgramFilesX86);}}
|
|
|
|
public static UnixPath Programs {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.Programs);}}
|
|
|
|
|
|
|
|
public static UnixPath CommonProgramFiles {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonProgramFiles);}}
|
|
|
|
public static UnixPath CommonProgramFilesX86 {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonProgramFilesX86);}}
|
|
|
|
public static UnixPath CommonPrograms {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonPrograms);}}
|
|
|
|
|
|
public static UnixPath PublicDesktopFolder {get {return UnixPath.FromSpecialDirectory(Environment.SpecialFolder.CommonDesktopDirectory);}}
|
|
}
|
|
public class UnixPath
|
|
{
|
|
public string ToLocal()
|
|
{
|
|
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
|
|
{
|
|
// /mnt/driveLetter/
|
|
if(Parts[0] != "mnt")
|
|
{
|
|
return "";
|
|
}else{
|
|
List<string> p = new List<string>();
|
|
for(int i = 0;i<Parts.Length;i++)
|
|
{
|
|
if(i == 0)
|
|
{
|
|
p.Add($"{Parts[i].ToUpper()}:");
|
|
}else{
|
|
p.Add(Parts[i]);
|
|
}
|
|
}
|
|
return string.Join("\\",p);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
return Path;
|
|
}
|
|
}
|
|
public static UnixPath FromSpecialDirectory(Environment.SpecialFolder specialFolder)
|
|
{
|
|
return UnixPath.FromLocal(Environment.GetFolderPath(specialFolder));
|
|
}
|
|
public static UnixPath FromLocal(string path)
|
|
{
|
|
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
|
|
{
|
|
string[] p = path.Split(new char[]{':'},2,StringSplitOptions.None);
|
|
List<string> paths=new List<string>();
|
|
paths.Add("mnt");
|
|
paths.Add(p[0].ToLower());
|
|
foreach(var path0 in p[1].Split('\\'))
|
|
{
|
|
paths.Add(path0);
|
|
}
|
|
return new UnixPath(paths);
|
|
}
|
|
else
|
|
{
|
|
return path;
|
|
}
|
|
}
|
|
|
|
public UnixPath()
|
|
{
|
|
|
|
_path = "/";
|
|
_parts = new string[0];
|
|
}
|
|
public UnixPath(IEnumerable<string> pathParts)
|
|
{
|
|
UnixPath path = new UnixPath();
|
|
foreach (var item in pathParts)
|
|
{
|
|
path /= new UnixPath(item);
|
|
}
|
|
_parts = path._parts;
|
|
path = path._path;
|
|
}
|
|
public UnixPath(UnixPath path1, UnixPath path2)
|
|
{
|
|
|
|
List<string> pathParts = new List<string>();
|
|
pathParts.AddRange(path1.Parts);
|
|
pathParts.AddRange(path2.Parts);
|
|
SetPath(pathParts);
|
|
}
|
|
private void SetPath(IEnumerable<string> p)
|
|
{
|
|
_parts = p.ToArray();
|
|
StringBuilder pa = new StringBuilder();
|
|
for (int i = 0; i < _parts.Length; i++)
|
|
{
|
|
pa.Append($"/{_parts[i]}");
|
|
}
|
|
if(pa.Length > 0)
|
|
_path = pa.ToString();
|
|
else
|
|
_path = "/";
|
|
}
|
|
public UnixPath(UnixPath path1)
|
|
{
|
|
_parts = path1._parts.ToArray();
|
|
_path = path1._path;
|
|
|
|
}
|
|
public UnixPath(params string[] pathParts) : this((IEnumerable<string>)pathParts)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
public UnixPath(UnixPath path, params string[] pathParts) : this(path, new UnixPath(pathParts))
|
|
{
|
|
|
|
}
|
|
public UnixPath(string path)
|
|
{
|
|
|
|
SetPath(path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries));
|
|
}
|
|
|
|
|
|
|
|
public static DirectoryPointer operator/(IVirtualFilesystem fs,UnixPath path)
|
|
{
|
|
return new DirectoryPointer(fs,path);
|
|
}
|
|
public static UnixPath operator /(UnixPath path, string path2)
|
|
{
|
|
return new UnixPath(path, path2);
|
|
}
|
|
public static UnixPath operator /(UnixPath path1, UnixPath path2)
|
|
{
|
|
|
|
return new UnixPath(
|
|
path1, path2
|
|
);
|
|
}
|
|
public static UnixPath operator +(UnixPath path1, string path2)
|
|
{
|
|
return path1 + new UnixPath(path2);
|
|
}
|
|
public static UnixPath operator +(UnixPath path1, UnixPath path2)
|
|
{
|
|
List<string> p = new List<string>();
|
|
StringBuilder b = new StringBuilder();
|
|
for (int i = 0; i < path1._parts.Length - 1; i++)
|
|
{
|
|
p.Add(path1._parts[i]);
|
|
}
|
|
if (path1._parts.Length - 1 >= 0)
|
|
{
|
|
b.Append(path1._parts[path1._parts.Length - 1]);
|
|
}
|
|
if (path2._parts.Length > 0)
|
|
{
|
|
b.Append(path2._parts[0]);
|
|
}
|
|
if (b.Length > 0)
|
|
{
|
|
p.Add(b.ToString());
|
|
}
|
|
for (int i = 1; i < path2._parts.Length; i++)
|
|
{
|
|
p.Add(path2._parts[i]);
|
|
}
|
|
|
|
var path = new UnixPath();
|
|
path.SetPath(p);
|
|
return path;
|
|
}
|
|
public static implicit operator UnixPath(string path)
|
|
{
|
|
|
|
|
|
return new UnixPath(path);
|
|
}
|
|
public static implicit operator UnixPath(string[] path)
|
|
{
|
|
return new UnixPath((IEnumerable<string>)path);
|
|
}
|
|
public bool MyPathEquals(UnixPath path)
|
|
{
|
|
if(path.Parts.Length != Parts.Length) return false;
|
|
|
|
for(int i = 0;i<Parts.Length;i++)
|
|
{
|
|
if(Parts[i] != path.Parts[i]) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
internal string _path;
|
|
|
|
public string Path { get { return _path; } }
|
|
|
|
public string Name { get { if (_parts.Length == 0) return ""; return _parts[_parts.Length - 1]; } set{
|
|
if(_parts.Length > 0) _parts[_parts.Length-1] = value;
|
|
|
|
} }
|
|
public bool IsRoot
|
|
{
|
|
get
|
|
{
|
|
return _parts.Length == 0;
|
|
}
|
|
}
|
|
public bool ParentIsRoot
|
|
{
|
|
get
|
|
{
|
|
return _parts.Length <= 1;
|
|
}
|
|
}
|
|
public UnixPath Parent
|
|
{
|
|
get
|
|
{
|
|
var p = new UnixPath();
|
|
if (!ParentIsRoot)
|
|
{
|
|
p.SetPath(_parts.Take(_parts.Length - 1));
|
|
}
|
|
return p;
|
|
}
|
|
}
|
|
internal string[] _parts;
|
|
public string[] Parts { get { return _parts; } }
|
|
public virtual string AsText
|
|
{
|
|
get { return ToString(); }
|
|
}
|
|
public override string ToString()
|
|
{
|
|
|
|
return _path;
|
|
|
|
}
|
|
}
|
|
|
|
}
|