tesses-vfs/Tesses.VirtualFilesystem.Zio/Class1.cs

478 lines
19 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 Zio;
using Zio.FileSystems;
using Tesses.VirtualFilesystem;
using System.Collections.Generic;
using System;
using System.IO;
using Tesses.VirtualFilesystem.Extensions;
namespace Tesses.VirtualFilesystem.Filesystems
{
public class ZioFileSystem : SyncFileSystem
{
IFileSystem fs;
public IFileSystem Filesystem => fs;
public override void Dispose()
{
fs.Dispose();
}
public ZioFileSystem(IFileSystem fs)
{
this.fs = fs;
}
public UPath ConvertUPathFromUnixPath(UnixPath path)
{
return path.Path;
}
public UnixPath ConvertUPathToUnixPath(UPath path)
{
return new UnixPath(path.ToString());
}
public override void CreateDirectory(UnixPath directory)
{
fs.CreateDirectory(ConvertUPathFromUnixPath(directory));
}
public override void DeleteDirectory(UnixPath path)
{
fs.DeleteDirectory(ConvertUPathFromUnixPath(path),false);
}
public override void DeleteFile(UnixPath path)
{
fs.DeleteFile(ConvertUPathFromUnixPath(path));
}
public override bool DirectoryExists(UnixPath path)
{
return fs.DirectoryExists(ConvertUPathFromUnixPath(path));
}
public override bool FileExists(UnixPath path)
{
return fs.FileExists(ConvertUPathFromUnixPath(path));
}
public override DateTime GetCreationTime(UnixPath path)
{
return fs.GetCreationTime(ConvertUPathFromUnixPath(path));
}
public override DateTime GetLastAccessTime(UnixPath path)
{
return fs.GetLastAccessTime(ConvertUPathFromUnixPath(path));
}
public override DateTime GetLastWriteTime(UnixPath path)
{
return fs.GetLastWriteTime(ConvertUPathFromUnixPath(path));
}
public override void MoveDirectory(UnixPath src, UnixPath dest)
{
fs.MoveDirectory(ConvertUPathFromUnixPath(src),ConvertUPathFromUnixPath(dest));
}
public override void MoveFile(UnixPath src, UnixPath dest)
{
fs.MoveFile(ConvertUPathFromUnixPath(src),ConvertUPathFromUnixPath(dest));
}
public override Stream Open(UnixPath path, FileMode mode, FileAccess access, FileShare share)
{
return fs.OpenFile(ConvertUPathFromUnixPath(path),mode,access,share);
}
public override void SetCreationTime(UnixPath path, DateTime time)
{
fs.SetCreationTime(ConvertUPathFromUnixPath(path),time);
}
public override void SetLastAccessTime(UnixPath path, DateTime time)
{
fs.SetLastAccessTime(ConvertUPathFromUnixPath(path),time);
}
public override void SetLastWriteTime(UnixPath path, DateTime time)
{
fs.SetLastWriteTime(ConvertUPathFromUnixPath(path),time);
}
public override void SetAttributes(UnixPath path, FileAttributes attributes)
{
fs.SetAttributes(ConvertUPathFromUnixPath(path),attributes);
}
public override FileAttributes GetAttributes(UnixPath path)
{
return fs.GetAttributes(ConvertUPathFromUnixPath(path));
}
public override bool CanWatch(UnixPath path)
{
return fs.CanWatch(ConvertUPathFromUnixPath(path));
}
public override IVirtualWatcher WatchDirectory(UnixPath dir)
{
return new ZioWatcher(this,fs,dir);
}
public override IEnumerable<UnixPath> EnumerateFileSystemEntries(UnixPath path)
{
foreach(var item in fs.EnumeratePaths(ConvertUPathFromUnixPath(path)))
{
yield return ConvertUPathToUnixPath(item);
}
}
private class ZioWatcher : IVirtualWatcher
{
Zio.IFileSystemWatcher watcher;
ZioFileSystem _fs;
public ZioWatcher(ZioFileSystem fs,IFileSystem fs2,UnixPath path)
{
watcher = fs2.Watch(fs.ConvertUPathFromUnixPath(path));
watcher.Changed += (sender,e)=>{
Changed?.Invoke(this,new VirtualWatcherChangedArgs(fs,(System.IO.WatcherChangeTypes)(int)e.ChangeType,fs.ConvertUPathToUnixPath(e.FullPath)));
};
watcher.Created += (sender,e)=>{
Created?.Invoke(this,new VirtualWatcherChangedArgs(fs,(System.IO.WatcherChangeTypes)(int)e.ChangeType,fs.ConvertUPathToUnixPath(e.FullPath)));
};
watcher.Deleted += (sender,e)=>{
Deleted?.Invoke(this,new VirtualWatcherChangedArgs(fs,(System.IO.WatcherChangeTypes)(int)e.ChangeType,fs.ConvertUPathToUnixPath(e.FullPath)));
};
watcher.Error += (sender,e)=>{
Error?.Invoke(this,new ErrorEventArgs(e.Exception));
};
watcher.Renamed += (sender,e)=>{
Renamed?.Invoke(this,new VirtualWatcherRenamedEventArgs(fs,(System.IO.WatcherChangeTypes)(int)e.ChangeType,fs.ConvertUPathToUnixPath(e.FullPath),fs.ConvertUPathToUnixPath(e.OldFullPath)));
};
_fs=fs;
}
public int InternalBufferSize { get => watcher.InternalBufferSize; set => watcher.InternalBufferSize=value;}
public System.IO.NotifyFilters NotifyFilter { get => (System.IO.NotifyFilters)watcher.NotifyFilter; set => watcher.NotifyFilter=(Zio.NotifyFilters)value; }
public bool EnableRaisingEvents { get => watcher.EnableRaisingEvents; set => watcher.EnableRaisingEvents=value; }
public string Filter { get => watcher.Filter; set => watcher.Filter=value; }
public bool IncludeSubdirectories { get => watcher.IncludeSubdirectories; set => watcher.IncludeSubdirectories=value;}
public event EventHandler<VirtualWatcherChangedArgs> Changed;
public event EventHandler<VirtualWatcherChangedArgs> Created;
public event EventHandler<VirtualWatcherChangedArgs> Deleted;
public event EventHandler<VirtualWatcherRenamedEventArgs> Renamed;
public event EventHandler<ErrorEventArgs> Error;
public void Dispose()
{
this.watcher.Dispose();
}
}
}
public class ZioMountableWrapper : ZioFileSystem
{
public MountFileSystem MountFilesystem {get;}
private ZioMountableWrapper(MountFileSystem fs) : base(fs)
{
MountFilesystem = fs;
}
public static ZioMountableWrapper Create(IVirtualFilesystem fs,bool owned=true)
{
return new ZioMountableWrapper(new MountFileSystem(new TessesVFSFilesystem(fs),owned));
}
public static ZioMountableWrapper Create(bool owned=true)
{
return new ZioMountableWrapper(new MountFileSystem(owned));
}
public void Mount(UnixPath path,IVirtualFilesystem fs)
{
MountFilesystem.Mount(path.Path,new TessesVFSFilesystem(fs));
}
public bool IsMounted(UnixPath path)
{
return MountFilesystem.IsMounted(path.Path);
}
public Dictionary<UnixPath,IVirtualFilesystem> GetMounts()
{
Dictionary<UnixPath,IVirtualFilesystem> fs=new Dictionary<UnixPath, IVirtualFilesystem>();
foreach(var item in MountFilesystem.GetMounts())
{
var _fs=item.Value as TessesVFSFilesystem;
if(_fs !=null)
fs.Add(item.Key.FullName,_fs.Filesystem);
}
return fs;
}
}
}
namespace Zio.FileSystems
{
public class TessesVFSFilesystem : Zio.FileSystems.FileSystem
{
protected override void Dispose(bool disposing)
{
if(disposing)
fs.Dispose();
}
IVirtualFilesystem fs;
public IVirtualFilesystem Filesystem => fs;
public TessesVFSFilesystem(IVirtualFilesystem fs)
{
this.fs = fs;
}
protected override UPath ConvertPathFromInternalImpl(string innerPath)
{
return innerPath;
}
protected override string ConvertPathToInternalImpl(UPath path)
{
return path.FullName;
}
protected override void CopyFileImpl(UPath srcPath, UPath destPath, bool overwrite)
{
if(!overwrite && fs.FileExists(fs.ConvertPathToUnixPath(ConvertPathToInternal(destPath)))) throw new IOException("File already exists");
fs.CopyFile(fs.ConvertPathToUnixPath(ConvertPathToInternal(srcPath)),fs.ConvertPathToUnixPath(ConvertPathToInternal(destPath)));
}
protected override void CreateDirectoryImpl(UPath path)
{
fs.CreateDirectory(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override void DeleteDirectoryImpl(UPath path, bool isRecursive)
{
fs.DeleteDirectory(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),isRecursive);
}
protected override void DeleteFileImpl(UPath path)
{
fs.DeleteFile(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override bool DirectoryExistsImpl(UPath path)
{
return fs.DirectoryExists(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override IEnumerable<FileSystemItem> EnumerateItemsImpl(UPath path, SearchOption searchOption, SearchPredicate searchPredicate)
{
foreach(var item in fs.EnumerateFileSystemEntries(fs.ConvertPathToUnixPath(ConvertPathToInternal(path))))
{
yield return new FileSystemItem(this,ConvertPathFromInternal(fs.ConvertPathFromUnixPath(item)),fs.DirectoryExists(item));
}
}
protected override IEnumerable<UPath> EnumeratePathsImpl(UPath path, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
{
foreach(var item in fs.EnumerateFileSystemEntries(fs.ConvertPathToUnixPath(ConvertPathToInternal(path))))
{
yield return ConvertPathFromInternal(fs.ConvertPathFromUnixPath(item));
}
}
protected override bool FileExistsImpl(UPath path)
{
return fs.FileExists(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override FileAttributes GetAttributesImpl(UPath path)
{
return fs.GetAttributes(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override DateTime GetCreationTimeImpl(UPath path)
{
return fs.GetCreationTime(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override long GetFileLengthImpl(UPath path)
{
using(var f = fs.OpenRead(fs.ConvertPathToUnixPath(ConvertPathToInternal(path))))
{
return f.Length;
}
}
protected override DateTime GetLastAccessTimeImpl(UPath path)
{
return fs.GetLastAccessTime(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override DateTime GetLastWriteTimeImpl(UPath path)
{
return fs.GetLastWriteTime(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override void MoveDirectoryImpl(UPath srcPath, UPath destPath)
{
fs.MoveDirectory(fs.ConvertPathToUnixPath(ConvertPathToInternal(srcPath)),fs.ConvertPathToUnixPath(ConvertPathToInternal(destPath)));
}
protected override void MoveFileImpl(UPath srcPath, UPath destPath)
{
fs.MoveDirectory(fs.ConvertPathToUnixPath(ConvertPathToInternal(srcPath)),fs.ConvertPathToUnixPath(ConvertPathToInternal(destPath)));
}
protected override Stream OpenFileImpl(UPath path, FileMode mode, FileAccess access, FileShare share)
{
return fs.Open(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),mode,access,share);
}
protected override void ReplaceFileImpl(UPath srcPath, UPath destPath, UPath destBackupPath, bool ignoreMetadataErrors)
{
MoveFile(destPath,destBackupPath);
MoveFile(srcPath,destPath);
}
protected override void SetAttributesImpl(UPath path, FileAttributes attributes)
{
fs.SetAttributes(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),attributes);
}
protected override void SetCreationTimeImpl(UPath path, DateTime time)
{
fs.SetCreationTime(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),time);
}
protected override void SetLastAccessTimeImpl(UPath path, DateTime time)
{
fs.SetLastAccessTime(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),time);
}
protected override void SetLastWriteTimeImpl(UPath path, DateTime time)
{
fs.SetLastWriteTime(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),time);
}
protected override IFileSystemWatcher WatchImpl(UPath path)
{
return new _FSW(this,fs,fs.ConvertPathToUnixPath(ConvertPathToInternal(path)));
}
protected override void CreateSymbolicLinkImpl(UPath path, UPath pathToTarget)
{
fs.CreateSymlink(fs.ConvertPathToUnixPath(ConvertPathToInternal(path)),fs.ConvertPathToUnixPath(ConvertPathToInternal(pathToTarget)));
}
protected override bool TryResolveLinkTargetImpl(UPath linkPath, out UPath resolvedPath)
{
if(fs.SymlinkExists(fs.ConvertPathToUnixPath(ConvertPathToInternal(linkPath))))
{
resolvedPath = ConvertPathFromInternal(fs.ConvertPathFromUnixPath(fs.ReadLink(fs.ConvertPathToUnixPath(ConvertPathToInternal(linkPath)))));
return true;
}
else
{
resolvedPath = ConvertPathFromInternal(fs.ConvertPathFromUnixPath(Special.Root));
return false;
}
}
private class _FSW : IFileSystemWatcher
{
IVirtualWatcher watcher;
public _FSW(IFileSystem fs2,IVirtualFilesystem fs,UnixPath unixPath)
{
this.FileSystem=fs2;
watcher=fs.WatchDirectory(unixPath);
Path = fs2.ConvertPathFromInternal(fs.ConvertPathFromUnixPath(unixPath));
this._fs = fs;
watcher.Changed += W_Changed;
watcher.Created += W_Created;
watcher.Deleted += W_Deleted;
watcher.Error += W_Error;
watcher.Renamed += W_Renamed;
}
private void W_Renamed(object sender, VirtualWatcherRenamedEventArgs e)
{
Renamed?.Invoke(this,new FileRenamedEventArgs(FileSystem,(Zio.WatcherChangeTypes)e.ChangeType,FileSystem.ConvertPathFromInternal(_fs.ConvertPathFromUnixPath(e.FullPath)),FileSystem.ConvertPathFromInternal(_fs.ConvertPathFromUnixPath(e.OldFullPath))));
}
private void W_Error(object sender, System.IO.ErrorEventArgs e)
{
Error?.Invoke(this,new FileSystemErrorEventArgs(e.GetException()));
}
private void W_Deleted(object sender, VirtualWatcherChangedArgs e)
{
Deleted?.Invoke(this,new FileChangedEventArgs(FileSystem,(Zio.WatcherChangeTypes)e.ChangeType,FileSystem.ConvertPathFromInternal(_fs.ConvertPathFromUnixPath(e.FullPath))));
}
IVirtualFilesystem _fs;
private void W_Created(object sender, VirtualWatcherChangedArgs e)
{
Created?.Invoke(this,new FileChangedEventArgs(FileSystem,(Zio.WatcherChangeTypes)e.ChangeType,FileSystem.ConvertPathFromInternal(_fs.ConvertPathFromUnixPath(e.FullPath))));
}
private void W_Changed(object sender, VirtualWatcherChangedArgs e)
{
Changed?.Invoke(this,new FileChangedEventArgs(FileSystem,(Zio.WatcherChangeTypes)e.ChangeType,FileSystem.ConvertPathFromInternal(_fs.ConvertPathFromUnixPath(e.FullPath))));
}
public IFileSystem FileSystem {get;}
public UPath Path {get;}
public int InternalBufferSize { get => watcher.InternalBufferSize; set => watcher.InternalBufferSize = value; }
public Zio.NotifyFilters NotifyFilter { get => (Zio.NotifyFilters)watcher.NotifyFilter; set => watcher.NotifyFilter = (System.IO.NotifyFilters)value; }
public bool EnableRaisingEvents { get => watcher.EnableRaisingEvents; set => watcher.EnableRaisingEvents=value; }
public string Filter { get => watcher.Filter; set => watcher.Filter=value; }
public bool IncludeSubdirectories { get => watcher.IncludeSubdirectories; set => watcher.IncludeSubdirectories=value; }
public event EventHandler<FileChangedEventArgs> Changed;
public event EventHandler<FileChangedEventArgs> Created;
public event EventHandler<FileChangedEventArgs> Deleted;
public event EventHandler<FileSystemErrorEventArgs> Error;
public event EventHandler<FileRenamedEventArgs> Renamed;
public void Dispose()
{
watcher.Changed -= W_Changed;
watcher.Created -= W_Created;
watcher.Deleted -= W_Deleted;
watcher.Error -= W_Error;
watcher.Renamed -= W_Renamed;
watcher.Dispose();
}
}
}
}