tesses-vfs/Tesses.VirtualFilesystem/Class1.cs

2015 lines
71 KiB
C#
Raw Normal View History

2022-12-14 15:53:42 +00:00
/*
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.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Tesses.VirtualFilesystem;
using Tesses.VirtualFilesystem.Extensions;
using System.Linq;
namespace Tesses.VirtualFilesystem
{
public class SubdirFilesystem : IVirtualFilesystem
{
IVirtualFilesystem _fs;
UnixPath _path;
public SubdirFilesystem(IVirtualFilesystem fs,UnixPath path)
{
this._fs=fs;
this._path=path;
}
public bool CanHandleSymlinks(UnixPath path)
{
return _fs.CanHandleSymlinks(_path / path);
}
public bool CanWatch(UnixPath path)
{
return _fs.CanWatch(_path / path);
}
private UnixPath ChopOff(UnixPath path)
{
if(path.Parts.Length > _path.Parts.Length)
{
return new UnixPath(path.Parts.Skip(_path.Parts.Length));
}
return new UnixPath();
}
public string ConvertPathFromUnixPath(UnixPath path)
{
return _fs.ConvertPathFromUnixPath(path);
}
public UnixPath ConvertPathToUnixPath(string path)
{
return _fs.ConvertPathToUnixPath(path);
}
public void CreateDirectory(UnixPath directory)
{
_fs.CreateDirectory(_path / directory);
}
public async Task CreateDirectoryAsync(UnixPath directory, CancellationToken token = default)
{
await _fs.CreateDirectoryAsync(_path / directory,token);
}
public void CreateHardlink(UnixPath src, UnixPath dest)
{
_fs.CreateHardlink(_path / src,_path / dest);
}
public async Task CreateHardlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
await _fs.CreateHardlinkAsync(_path / src,_path /dest,token);
}
public void CreateSymlink(UnixPath src, UnixPath dest)
{
_fs.CreateSymlink(_path / src,_path / dest);
}
public async Task CreateSymlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
await _fs.CreateSymlinkAsync(_path / src,_path / dest,token);
}
public void DeleteDirectory(UnixPath path)
{
_fs.DeleteDirectory(_path / path);
}
public async Task DeleteDirectoryAsync(UnixPath path, CancellationToken token = default)
{
await _fs.DeleteDirectoryAsync(_path / path,token);
}
public void DeleteFile(UnixPath path)
{
_fs.DeleteFile(_path / path);
}
public async Task DeleteFileAsync(UnixPath path, CancellationToken token = default)
{
await _fs.DeleteFileAsync(_path / path,token);
}
public bool DirectoryExists(UnixPath path)
{
return _fs.DirectoryExists(_path / path);
}
public async Task<bool> DirectoryExistsAsync(UnixPath path, CancellationToken token = default)
{
return await _fs.DirectoryExistsAsync(_path / path,token);
}
public void Dispose()
{
}
public IEnumerable<UnixPath> EnumerateDirectories(UnixPath path)
{
foreach(var dir in _fs.EnumerateDirectories(_path / path))
{
yield return ChopOff(dir);
}
}
public async IAsyncEnumerable<UnixPath> EnumerateDirectoriesAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var dir in _fs.EnumerateDirectoriesAsync(_path / path,token))
{
if(token.IsCancellationRequested) yield break;
yield return ChopOff(dir);
}
}
public IEnumerable<UnixPath> EnumerateFiles(UnixPath path)
{
foreach(var file in _fs.EnumerateFiles(_path / path))
{
yield return ChopOff(file);
}
}
public async IAsyncEnumerable<UnixPath> EnumerateFilesAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
await foreach(var file in _fs.EnumerateFilesAsync(_path / path,token))
{
if(token.IsCancellationRequested) yield break;
yield return ChopOff(file);
}
}
public bool FileExists(UnixPath path)
{
return _fs.FileExists(_path / path);
}
public async Task<bool> FileExistsAsync(UnixPath path, CancellationToken token = default)
{
return await _fs.FileExistsAsync(_path / path,token);
}
public FileAttributes GetAttributes(UnixPath path)
{
return _fs.GetAttributes(_path / path);
}
public async Task<FileAttributes> GetAttributesAsync(UnixPath path, CancellationToken token = default)
{
return await _fs.GetAttributesAsync(_path / path,token);
}
public DateTime GetCreationTime(UnixPath path)
{
return _fs.GetCreationTime(_path / path);
}
public async Task<DateTime> GetCreationTimeAsync(UnixPath path, CancellationToken token = default)
{
return await _fs.GetCreationTimeAsync(_path / path,token);
}
public DateTime GetLastAccessTime(UnixPath path)
{
return _fs.GetLastAccessTime(_path / path);
}
public async Task<DateTime> GetLastAccessTimeAsync(UnixPath path, CancellationToken token = default)
{
return await _fs.GetLastAccessTimeAsync(_path / path,token);
}
public DateTime GetLastWriteTime(UnixPath path)
{
return _fs.GetLastWriteTime(_path / path);
}
public async Task<DateTime> GetLastWriteTimeAsync(UnixPath path, CancellationToken token = default)
{
return await _fs.GetLastWriteTimeAsync(_path / path,token);
}
public IVirtualFilesystem GetSubdirFilesystem(UnixPath path)
{
return new SubdirFilesystem(this,path);
}
public void MoveDirectory(UnixPath src, UnixPath dest)
{
_fs.MoveDirectory(_path / src,_path / dest);
}
public async Task MoveDirectoryAsync(UnixPath src, UnixPath dest)
{
await _fs.MoveDirectoryAsync(_path / src, _path / dest);
}
public void MoveFile(UnixPath src, UnixPath dest)
{
_fs.MoveFile(_path / src,_path / dest);
}
public async Task MoveFileAsync(UnixPath src, UnixPath dest)
{
await _fs.MoveFileAsync(_path / src, _path / dest);
}
public Stream Open(UnixPath path, FileMode mode, FileAccess access, FileShare share)
{
return _fs.Open(_path / path,mode,access,share);
}
public async Task<Stream> OpenAsync(UnixPath path, FileMode mode, FileAccess access, FileShare share, CancellationToken token = default)
{
return await _fs.OpenAsync(_path / path,mode,access,share,token);
}
public DirectoryPointer OpenDirectory()
{
return new DirectoryPointer(this);
}
public DirectoryPointer OpenDirectory(UnixPath path)
{
return new DirectoryPointer(this,path);
}
public UnixPath ReadLink(UnixPath file)
{
return _fs.ReadLink(_path / file);
}
public async Task<UnixPath> ReadLinkAsync(UnixPath file, CancellationToken token = default)
{
return await _fs.ReadLinkAsync(_path / file,token);
}
public bool SameFileSystem(UnixPath src, UnixPath dest)
{
return _fs.SameFileSystem(_path / src,_path / dest);
}
public async Task<bool> SameFileSystemAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
return await _fs.SameFileSystemAsync(_path / src, _path / dest,token);
}
public void SetAttributes(UnixPath path, FileAttributes attributes)
{
_fs.SetAttributes(_path / path,attributes);
}
public async Task SetAttributesAsync(UnixPath path, FileAttributes attributes, CancellationToken token = default)
{
await _fs.SetAttributesAsync(_path / path,attributes,token);
}
public void SetCreationTime(UnixPath path, DateTime time)
{
_fs.SetCreationTime(_path / path,time);
}
public async Task SetCreationTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
await _fs.SetCreationTimeAsync(_path / path,time,token);
}
public void SetLastAccessTime(UnixPath path, DateTime time)
{
_fs.SetLastAccessTime(_path / path,time);
}
public async Task SetLastAccessTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
await _fs.SetLastAccessTimeAsync(_path / path,time,token);
}
public void SetLastWriteTime(UnixPath path, DateTime time)
{
_fs.SetLastWriteTime(_path / path,time);
}
public async Task SetLastWriteTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
await _fs.SetLastWriteTimeAsync(_path / path,time,token);
}
public bool SymlinkExists(UnixPath file)
{
return _fs.SymlinkExists(_path / file);
}
public async Task<bool> SymlinkExistsAsync(UnixPath file, CancellationToken token = default)
{
return await _fs.SymlinkExistsAsync(_path / file,token);
}
public UnixPath UpPath(UnixPath path)
{
return path.Parent;
}
public IVirtualWatcher WatchDirectory(UnixPath dir)
{
return _fs.WatchDirectory(_path / dir);
}
public EntryPointer OpenEntry(UnixPath path)
{
return _fs.OpenEntry(_path / path);
}
public FilePointer OpenFile(UnixPath path)
{
return _fs.OpenFile(path);
}
public SymlinkPointer OpenSymlink(UnixPath path)
{
return _fs.OpenSymlink(path);
}
public IEnumerable<UnixPath> EnumerateFileSystemEntries(UnixPath path)
{
foreach(var item in _fs.EnumerateFileSystemEntries(_path/path))
{
yield return ChopOff(item);
}
}
public IEnumerable<UnixPath> EnumerateSymlinks(UnixPath path)
{
foreach(var item in _fs.EnumerateSymlinks(_path/path))
{
yield return ChopOff(item);
}
}
public async IAsyncEnumerable<UnixPath> EnumerateSymlinksAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var item in _fs.EnumerateSymlinksAsync(_path/path))
{
if(token.IsCancellationRequested) yield break;
yield return await Task.FromResult(ChopOff(item));
}
}
public async IAsyncEnumerable<UnixPath> EnumerateFileSystemEntriesAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var item in _fs.EnumerateFileSystemEntriesAsync(_path/path))
{
if(token.IsCancellationRequested) yield break;
yield return await Task.FromResult(ChopOff(item));
}
}
public void DeleteDirectory(UnixPath path, bool recursive)
{
_fs.DeleteDirectory(_path/path,recursive);
}
public async Task DeleteDirectoryAsync(UnixPath path, bool recursive, CancellationToken token = default)
{
await _fs.DeleteDirectoryAsync(_path/path,token);
}
}
public abstract class SyncFileSystem : IVirtualFilesystem
{
public virtual void Dispose()
{
}
public virtual UnixPath UpPath(UnixPath path)
{
return path.Parent;
}
public virtual UnixPath ConvertPathToUnixPath(string path)
{
return path;
}
public virtual string ConvertPathFromUnixPath(UnixPath path)
{
return path.ToString();
}
public virtual bool CanWatch(UnixPath path)
{
return false;
}
public virtual bool CanHandleSymlinks(UnixPath path)
{
return false;
}
public abstract void CreateDirectory(UnixPath directory);
public virtual async Task CreateDirectoryAsync(UnixPath directory,CancellationToken token=default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>CreateDirectory(directory));
}
public virtual void CreateHardlink(UnixPath src, UnixPath dest)
{
this.CopyFile(src,dest);
}
public virtual async Task CreateHardlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>CreateHardlink(src,dest));
}
public virtual void CreateSymlink(UnixPath src, UnixPath dest)
{
}
public virtual async Task CreateSymlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>CreateHardlink(src,dest));
}
public abstract void DeleteDirectory(UnixPath path);
public virtual async Task DeleteDirectoryAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>DeleteDirectory(path));
}
public abstract void DeleteFile(UnixPath path);
public virtual async Task DeleteFileAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>DeleteFile(path));
}
public abstract bool DirectoryExists(UnixPath path);
public async Task<bool> DirectoryExistsAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return false;
return await Task.Run<bool>(()=>DirectoryExistsAsync(path));
}
public IEnumerable<UnixPath> EnumerateDirectories(UnixPath path)
{
foreach(var item in EnumerateFileSystemEntries(path))
{
if(DirectoryExists(item) && !SymlinkExists(item))
{
yield return item;
}
}
}
public async IAsyncEnumerable<UnixPath> EnumerateDirectoriesAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var item in EnumerateFileSystemEntriesAsync(path))
{
if(token.IsCancellationRequested) yield break;
if(await DirectoryExistsAsync(item) && !await SymlinkExistsAsync(item))
yield return await Task.FromResult(item);
}
}
public IEnumerable<UnixPath> EnumerateFiles(UnixPath path)
{
foreach(var item in EnumerateFileSystemEntries(path))
{
if(FileExists(item) && !SymlinkExists(item))
{
yield return item;
}
}
}
public async IAsyncEnumerable<UnixPath> EnumerateFilesAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
await foreach(var item in EnumerateFileSystemEntriesAsync(path))
{
if(token.IsCancellationRequested) yield break;
if(await FileExistsAsync(item) && !await SymlinkExistsAsync(item))
yield return await Task.FromResult(item);
}
}
public abstract bool FileExists(UnixPath path);
public virtual async Task<bool> FileExistsAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return false;
return await Task.Run<bool>(()=>FileExists(path));
}
public virtual FileAttributes GetAttributes(UnixPath path)
{
return FileAttributes.Normal;
}
public virtual async Task<FileAttributes> GetAttributesAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return FileAttributes.Normal;
return await Task.Run<FileAttributes>(()=>GetAttributes(path));
}
public abstract DateTime GetCreationTime(UnixPath path);
public virtual async Task<DateTime> GetCreationTimeAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return DateTime.Now;
return await Task.Run<DateTime>(()=>GetCreationTime(path));
}
public abstract DateTime GetLastAccessTime(UnixPath path);
public virtual async Task<DateTime> GetLastAccessTimeAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return DateTime.Now;
return await Task.Run<DateTime>(()=>GetLastAccessTime(path));
}
public abstract DateTime GetLastWriteTime(UnixPath path);
public virtual async Task<DateTime> GetLastWriteTimeAsync(UnixPath path, CancellationToken token = default)
{
if(token.IsCancellationRequested) return DateTime.Now;
return await Task.Run<DateTime>(()=>GetLastWriteTime(path));
}
public abstract void MoveDirectory(UnixPath src, UnixPath dest);
public virtual async Task MoveDirectoryAsync(UnixPath src, UnixPath dest)
{
await Task.Run(()=>MoveDirectory(src,dest));
}
public abstract void MoveFile(UnixPath src, UnixPath dest);
public virtual async Task MoveFileAsync(UnixPath src, UnixPath dest)
{
await Task.Run(()=>MoveFile(src,dest));
}
public abstract Stream Open(UnixPath path, FileMode mode, FileAccess access, FileShare share);
public virtual async Task<Stream> OpenAsync(UnixPath path, FileMode mode, FileAccess access, FileShare share, CancellationToken token = default)
{
if(token.IsCancellationRequested) return Stream.Null;
return await Task.Run<Stream>(()=>Open(path,mode,access,share));
}
public virtual UnixPath ReadLink(UnixPath file)
{
return file;
}
public virtual async Task<UnixPath> ReadLinkAsync(UnixPath file, CancellationToken token = default)
{
if(token.IsCancellationRequested) return file;
return await Task.Run<UnixPath>(()=>ReadLink(file));
}
public virtual async Task<bool> SameFileSystemAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
if(token.IsCancellationRequested) return false;
return await Task.Run<bool>(()=>SameFileSystem(src,dest));
}
public virtual bool SameFileSystem(UnixPath src, UnixPath dest)
{
return false;
}
public virtual void SetAttributes(UnixPath path, FileAttributes attributes)
{
}
public virtual async Task SetAttributesAsync(UnixPath path, FileAttributes attributes, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>SetAttributes(path,attributes));
}
public abstract void SetCreationTime(UnixPath path, DateTime time);
public virtual async Task SetCreationTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>SetCreationTime(path,time));
}
public abstract void SetLastAccessTime(UnixPath path, DateTime time);
public virtual async Task SetLastAccessTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>SetLastAccessTime(path,time));
}
public abstract void SetLastWriteTime(UnixPath path, DateTime time);
public virtual async Task SetLastWriteTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
if(token.IsCancellationRequested) return;
await Task.Run(()=>SetLastWriteTimeAsync(path,time));
}
public virtual async Task<bool> SymlinkExistsAsync(UnixPath file, CancellationToken token = default)
{
if(token.IsCancellationRequested) return false;
return await Task.Run<bool>(()=>SymlinkExists(file));
}
public virtual bool SymlinkExists(UnixPath file)
{
return false;
}
public virtual IVirtualWatcher WatchDirectory(UnixPath dir)
{
return null;
}
public IVirtualFilesystem GetSubdirFilesystem(UnixPath path)
{
return new SubdirFilesystem(this,path);
}
public SymlinkPointer OpenSymlink(UnixPath path)
{
return new SymlinkPointer(this,path);
}
public FilePointer OpenFile(UnixPath path)
{
return new FilePointer(this,path);
}
public DirectoryPointer OpenDirectory(UnixPath path)
{
return new DirectoryPointer(this,path);
}
public DirectoryPointer OpenDirectory()
{
return new DirectoryPointer(this);
}
public EntryPointer OpenEntry(UnixPath path)
{
if(FileExists(path))
{
return new FilePointer(this,path);
}else if(SymlinkExists(path))
{
return new SymlinkPointer(this,path);
}
else if(DirectoryExists(path)){
return new DirectoryPointer(this,path);
}
return new NonExistantPointer(this,path);
}
public abstract IEnumerable<UnixPath> EnumerateFileSystemEntries(UnixPath path);
public IEnumerable<UnixPath> EnumerateSymlinks(UnixPath path)
{
foreach(var item in EnumerateFileSystemEntries(path))
{
if(SymlinkExists(item))
{
yield return item;
}
}
}
public async IAsyncEnumerable<UnixPath> EnumerateSymlinksAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var item in EnumerateFileSystemEntriesAsync(path))
{
if(token.IsCancellationRequested) yield break;
if(await SymlinkExistsAsync(item))
yield return await Task.FromResult(item);
}
}
public virtual async IAsyncEnumerable<UnixPath> EnumerateFileSystemEntriesAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
foreach(var item in EnumerateFileSystemEntries(path))
{
if(token.IsCancellationRequested) yield break;
yield return await Task.FromResult(item);
}
}
public virtual void DeleteDirectory(UnixPath path, bool recursive)
{
if(recursive)
{
foreach(var item in EnumerateFileSystemEntries(path))
{
if(DirectoryExists(item))
{
DeleteDirectory(item,true);
}else{
DeleteFile(item);
}
}
}
DeleteDirectory(path);
}
public virtual async Task DeleteDirectoryAsync(UnixPath path, bool recursive, CancellationToken token = default)
{
if(recursive){
await foreach(var item in EnumerateFileSystemEntriesAsync(path))
{
if(token.IsCancellationRequested) return;
if(await DirectoryExistsAsync(item))
{
await DeleteDirectoryAsync(item,true,token);
}else{
await DeleteFileAsync(item,token);
}
}
}
await DeleteDirectoryAsync(path,token);
}
}
public abstract class AsyncFileSystem : IVirtualFilesystem
{
public SymlinkPointer OpenSymlink(UnixPath path)
{
return new SymlinkPointer(this,path);
}
public FilePointer OpenFile(UnixPath path)
{
return new FilePointer(this,path);
}
public EntryPointer OpenEntry(UnixPath path)
{
if(FileExists(path))
{
return new FilePointer(this,path);
}else if(SymlinkExists(path))
{
return new SymlinkPointer(this,path);
}
else if(DirectoryExists(path)){
return new DirectoryPointer(this,path);
}
return new NonExistantPointer(this,path);
}
public virtual void DeleteDirectory(UnixPath path, bool recursive)
{
if(recursive)
{
foreach(var item in EnumerateFileSystemEntries(path))
{
if(DirectoryExists(item))
{
DeleteDirectory(item,true);
}else{
DeleteFile(item);
}
}
}
DeleteDirectory(path);
}
public virtual async Task DeleteDirectoryAsync(UnixPath path, bool recursive, CancellationToken token = default)
{
if(recursive){
await foreach(var item in EnumerateFileSystemEntriesAsync(path))
{
if(token.IsCancellationRequested) return;
if(await DirectoryExistsAsync(item))
{
await DeleteDirectoryAsync(item,true,token);
}else{
await DeleteFileAsync(item,token);
}
}
}
await DeleteDirectoryAsync(path,token);
}
public IVirtualFilesystem GetSubdirFilesystem(UnixPath path)
{
return new SubdirFilesystem(this,path);
}
public DirectoryPointer OpenDirectory()
{
return new DirectoryPointer(this);
}
public DirectoryPointer OpenDirectory(UnixPath path)
{
return new DirectoryPointer(this,path);
}
public virtual void Dispose()
{
}
public virtual UnixPath UpPath(UnixPath path)
{
return path.Parent;
}
public virtual UnixPath ConvertPathToUnixPath(string path)
{
return path;
}
public virtual string ConvertPathFromUnixPath(UnixPath path)
{
return path.ToString();
}
public virtual bool CanWatch(UnixPath path)
{
return false;
}
public virtual void CreateDirectory(UnixPath directory)
{
Task.Run(async()=>await CreateDirectoryAsync(directory)).Wait();
}
public abstract Task CreateDirectoryAsync(UnixPath directory, CancellationToken token = default);
public virtual void CreateHardlink(UnixPath src, UnixPath dest)
{
Task.Run(async()=>await CreateHardlinkAsync(src,dest)).Wait();
}
public virtual async Task CreateHardlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
//await this.CopyFile()
await this.CopyFileAsync(src,dest,token);
}
public virtual void CreateSymlink(UnixPath src, UnixPath dest)
{
Task.Run(async()=>await CreateSymlinkAsync(src,dest)).Wait();
}
public virtual async Task CreateSymlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
await Task.FromResult(0);
}
public virtual bool CanHandleSymlinks(UnixPath path)
{
return false;
}
public virtual void DeleteDirectory(UnixPath path)
{
Task.Run(async()=>await DeleteDirectoryAsync(path)).Wait();
}
public abstract Task DeleteDirectoryAsync(UnixPath path, CancellationToken token = default);
public virtual void DeleteFile(UnixPath path)
{
Task.Run(async()=>await DeleteFileAsync(path)).Wait();
}
public abstract Task DeleteFileAsync(UnixPath path, CancellationToken token = default);
public virtual bool DirectoryExists(UnixPath path)
{
bool res=false;
Task.Run(async()=>res=await DirectoryExistsAsync(path)).Wait();
return res;
}
public abstract Task<bool> DirectoryExistsAsync(UnixPath path, CancellationToken token = default);
public virtual IEnumerable<UnixPath> EnumerateDirectories(UnixPath path)
{
var enumerator = EnumerateDirectoriesAsync(path).GetAsyncEnumerator();
while(Task.Run<bool>(async()=>await enumerator.MoveNextAsync()).GetAwaiter().GetResult())
{
yield return enumerator.Current;
}
Task.Run(enumerator.DisposeAsync).Wait();
}
public virtual IEnumerable<UnixPath> EnumerateFiles(UnixPath path)
{
var enumerator = EnumerateFilesAsync(path).GetAsyncEnumerator();
while(Task.Run<bool>(async()=>await enumerator.MoveNextAsync()).GetAwaiter().GetResult())
{
yield return enumerator.Current;
}
Task.Run(enumerator.DisposeAsync).Wait();
}
public virtual async IAsyncEnumerable<UnixPath> EnumerateFilesAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
await foreach(var item in EnumerateFileSystemEntriesAsync(path,token))
{
if(token.IsCancellationRequested) yield break;
if(await FileExistsAsync(item,token) && !await SymlinkExistsAsync(item,token))
{
yield return await Task.FromResult(item);
}
}
}
public virtual async IAsyncEnumerable<UnixPath> EnumerateDirectoriesAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
await foreach(var item in EnumerateFileSystemEntriesAsync(path,token))
{
if(token.IsCancellationRequested) yield break;
if(await DirectoryExistsAsync(item,token) && !await SymlinkExistsAsync(item,token))
{
yield return await Task.FromResult(item);
}
}
}
public virtual async IAsyncEnumerable<UnixPath> EnumerateSymlinksAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
await foreach(var item in EnumerateFileSystemEntriesAsync(path,token))
{
if(token.IsCancellationRequested) yield break;
if(await SymlinkExistsAsync(item,token))
{
yield return await Task.FromResult(item);
}
}
}
public virtual bool FileExists(UnixPath path)
{
return Task.Run<bool>(async()=>await FileExistsAsync(path)).GetAwaiter().GetResult();
}
public abstract Task<bool> FileExistsAsync(UnixPath path, CancellationToken token = default);
public virtual FileAttributes GetAttributes(UnixPath path)
{
return Task.Run<FileAttributes>(async()=>await GetAttributesAsync(path)).GetAwaiter().GetResult();
}
public virtual Task<FileAttributes> GetAttributesAsync(UnixPath path, CancellationToken token = default)
{
return Task.FromResult(FileAttributes.Normal);
}
public virtual DateTime GetCreationTime(UnixPath path)
{
return Task.Run<DateTime>(async()=>await GetCreationTimeAsync(path)).GetAwaiter().GetResult();
}
public abstract Task<DateTime> GetCreationTimeAsync(UnixPath path, CancellationToken token = default);
public virtual DateTime GetLastAccessTime(UnixPath path)
{
return Task.Run<DateTime>(async()=>await GetLastAccessTimeAsync(path)).GetAwaiter().GetResult();
}
public abstract Task<DateTime> GetLastAccessTimeAsync(UnixPath path, CancellationToken token = default);
public virtual DateTime GetLastWriteTime(UnixPath path)
{
return Task.Run<DateTime>(async()=>await GetLastWriteTimeAsync(path)).GetAwaiter().GetResult();
}
public abstract Task<DateTime> GetLastWriteTimeAsync(UnixPath path, CancellationToken token = default);
public virtual void MoveDirectory(UnixPath src, UnixPath dest)
{
Task.Run(async()=>await MoveDirectoryAsync(src,dest)).Wait();
}
public abstract Task MoveDirectoryAsync(UnixPath src, UnixPath dest);
public virtual void MoveFile(UnixPath src, UnixPath dest)
{
Task.Run(async()=>await MoveFileAsync(src,dest)).Wait();
}
public abstract Task MoveFileAsync(UnixPath src, UnixPath dest);
public Stream Open(UnixPath path, FileMode mode, FileAccess access, FileShare share)
{
return Task.Run<Stream>(async()=>await OpenAsync(path,mode,access,share)).GetAwaiter().GetResult();
}
public abstract Task<Stream> OpenAsync(UnixPath path, FileMode mode, FileAccess access, FileShare share, CancellationToken token = default);
public virtual UnixPath ReadLink(UnixPath file)
{
return Task.Run<UnixPath>(async()=>await ReadLinkAsync(file)).GetAwaiter().GetResult();
}
public virtual async Task<UnixPath> ReadLinkAsync(UnixPath file, CancellationToken token = default)
{
return await Task.FromResult(file);
}
public virtual async Task<bool> SameFileSystemAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
return await Task.FromResult(false);
}
public virtual bool SameFileSystem(UnixPath src, UnixPath dest)
{
return Task.Run<bool>(async()=>await SameFileSystemAsync(src,dest)).GetAwaiter().GetResult();
}
public virtual void SetAttributes(UnixPath path, FileAttributes attributes)
{
Task.Run(async()=>await SetAttributesAsync(path,attributes)).Wait();
}
public virtual async Task SetAttributesAsync(UnixPath path, FileAttributes attributes, CancellationToken token = default)
{
await Task.FromResult(0);
}
public virtual void SetCreationTime(UnixPath path, DateTime time)
{
Task.Run(async()=>await SetCreationTimeAsync(path,time)).Wait();
}
public abstract Task SetCreationTimeAsync(UnixPath path, DateTime time, CancellationToken token = default);
public virtual void SetLastAccessTime(UnixPath path, DateTime time)
{
Task.Run(async()=>await SetLastAccessTimeAsync(path,time)).Wait();
}
public abstract Task SetLastAccessTimeAsync(UnixPath path, DateTime time, CancellationToken token = default);
public virtual void SetLastWriteTime(UnixPath path, DateTime time)
{
Task.Run(async()=>await SetLastWriteTimeAsync(path,time)).Wait();
}
public abstract Task SetLastWriteTimeAsync(UnixPath path, DateTime time, CancellationToken token = default);
public virtual async Task<bool> SymlinkExistsAsync(UnixPath file, CancellationToken token = default)
{
return await Task.FromResult(false);
}
public virtual bool SymlinkExists(UnixPath file)
{
return Task.Run<bool>(async()=>await SymlinkExistsAsync(file)).GetAwaiter().GetResult();
}
public virtual IVirtualWatcher WatchDirectory(UnixPath dir)
{
return null;
}
public IEnumerable<UnixPath> EnumerateFileSystemEntries(UnixPath path)
{
var enumerator = EnumerateFileSystemEntriesAsync(path).GetAsyncEnumerator();
while(Task.Run<bool>(async()=>await enumerator.MoveNextAsync()).GetAwaiter().GetResult())
{
yield return enumerator.Current;
}
Task.Run(enumerator.DisposeAsync).Wait();
}
public IEnumerable<UnixPath> EnumerateSymlinks(UnixPath path)
{
var enumerator = EnumerateSymlinksAsync(path).GetAsyncEnumerator();
while(Task.Run<bool>(async()=>await enumerator.MoveNextAsync()).GetAwaiter().GetResult())
{
yield return enumerator.Current;
}
Task.Run(enumerator.DisposeAsync).Wait();
}
public abstract IAsyncEnumerable<UnixPath> EnumerateFileSystemEntriesAsync(UnixPath path, CancellationToken token = default);
}
/*
public sealed class MultiLayerFS : AsyncFileSystem
{
private delegate Task<Stream> OpenAsyncDel(UnixPath path, FileMode mode, FileAccess access, FileShare share, CancellationToken token = default);
private class FileSystemWithCustomOpen : IVirtualFilesystem
{
public FileSystemWithCustomOpen(IVirtualFilesystem fs,OpenAsyncDel del)
{
this.del = del;
this.fs = fs;
}
OpenAsyncDel del;
public IVirtualFilesystem fs;
public bool CanHandleSymlinks(UnixPath path)
{
return fs.CanHandleSymlinks(path);
}
public bool CanWatch(UnixPath path)
{
return fs.CanWatch(path);
}
public string ConvertPathFromUnixPath(UnixPath path)
{
return fs.ConvertPathFromUnixPath(path);
}
public UnixPath ConvertPathToUnixPath(string path)
{
return fs.ConvertPathToUnixPath(path);
}
public void CreateDirectory(UnixPath directory)
{
fs.CreateDirectory(directory);
}
public async Task CreateDirectoryAsync(UnixPath directory, CancellationToken token = default)
{
await fs.CreateDirectoryAsync(directory,token);
}
public void CreateHardlink(UnixPath src, UnixPath dest)
{
fs.CreateHardlink(src,dest);
}
public async Task CreateHardlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
await fs.CreateHardlinkAsync(src,dest,token);
}
public void CreateSymlink(UnixPath src, UnixPath dest)
{
fs.CreateSymlink(src,dest);
}
public async Task CreateSymlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
await fs.CreateSymlinkAsync(src,dest,token);
}
public void DeleteDirectory(UnixPath path)
{
fs.DeleteDirectory(path);
}
public async Task DeleteDirectoryAsync(UnixPath path, CancellationToken token = default)
{
await fs.DeleteDirectoryAsync(path,token);
}
public void DeleteFile(UnixPath path)
{
fs.DeleteFile(path);
}
public async Task DeleteFileAsync(UnixPath path, CancellationToken token = default)
{
await fs.DeleteFileAsync(path,token);
}
public bool DirectoryExists(UnixPath path)
{
return fs.DirectoryExists(path);
}
public async Task<bool> DirectoryExistsAsync(UnixPath path, CancellationToken token = default)
{
return await fs.DirectoryExistsAsync(path,token);
}
public void Dispose()
{
fs.Dispose();
}
public IEnumerable<UnixPath> EnumerateDirectories(UnixPath path)
{
foreach(var item in fs.EnumerateDirectories(path))
{
yield return item;
}
}
public async IAsyncEnumerable<UnixPath> EnumerateDirectoriesAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var item in fs.EnumerateDirectoriesAsync(path,token))
{
if(token.IsCancellationRequested) yield break;
yield return item;
}
}
public IEnumerable<UnixPath> EnumerateFiles(UnixPath path)
{
foreach(var item in fs.EnumerateFiles(path))
{
yield return item;
}
}
public async IAsyncEnumerable<UnixPath> EnumerateFilesAsync(UnixPath path, [EnumeratorCancellation]CancellationToken token = default)
{
await foreach(var item in fs.EnumerateFilesAsync(path,token))
{
if(token.IsCancellationRequested) yield break;
yield return path;
}
}
public bool FileExists(UnixPath path)
{
return fs.FileExists(path);
}
public async Task<bool> FileExistsAsync(UnixPath path, CancellationToken token = default)
{
return await fs.FileExistsAsync(path,token);
}
public FileAttributes GetAttributes(UnixPath path)
{
return fs.GetAttributes(path);
}
public async Task<FileAttributes> GetAttributesAsync(UnixPath path, CancellationToken token = default)
{
return await fs.GetAttributesAsync(path,token);
}
public DateTime GetCreationTime(UnixPath path)
{
return fs.GetCreationTime(path);
}
public async Task<DateTime> GetCreationTimeAsync(UnixPath path, CancellationToken token = default)
{
return await fs.GetCreationTimeAsync(path,token);
}
public DateTime GetLastAccessTime(UnixPath path)
{
return fs.GetLastAccessTime(path);
}
public async Task<DateTime> GetLastAccessTimeAsync(UnixPath path, CancellationToken token = default)
{
return await fs.GetLastAccessTimeAsync(path,token);
}
public DateTime GetLastWriteTime(UnixPath path)
{
return fs.GetLastAccessTime(path);
}
public async Task<DateTime> GetLastWriteTimeAsync(UnixPath path, CancellationToken token = default)
{
return await fs.GetLastWriteTimeAsync(path,token);
}
public void MoveDirectory(UnixPath src, UnixPath dest)
{
fs.MoveDirectory(src,dest);
}
public async Task MoveDirectoryAsync(UnixPath src, UnixPath dest)
{
await fs.MoveDirectoryAsync(src,dest);
}
public void MoveFile(UnixPath src, UnixPath dest)
{
fs.MoveFile(src,dest);
}
public async Task MoveFileAsync(UnixPath src, UnixPath dest)
{
await fs.MoveFileAsync(src,dest);
}
public Stream Open(UnixPath path, FileMode mode, FileAccess access, FileShare share)
{
return Task.Run<Stream>(async()=>await del(path,mode,access,share)).GetAwaiter().GetResult();
}
public async Task<Stream> OpenAsync(UnixPath path, FileMode mode, FileAccess access, FileShare share, CancellationToken token = default)
{
return await del(path,mode,access,share,token);
}
public UnixPath ReadLink(UnixPath file)
{
return fs.ReadLink(file);
}
public async Task<UnixPath> ReadLinkAsync(UnixPath file, CancellationToken token = default)
{
return await fs.ReadLinkAsync(file,token);
}
public bool SameFileSystem(UnixPath src, UnixPath dest)
{
return fs.SameFileSystem(src,dest);
}
public async Task<bool> SameFileSystemAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
return await fs.SameFileSystemAsync(src,dest,token);
}
public void SetAttributes(UnixPath path, FileAttributes attributes)
{
fs.SetAttributes(path,attributes);
}
public async Task SetAttributesAsync(UnixPath path, FileAttributes attributes, CancellationToken token = default)
{
await fs.SetAttributesAsync(path,attributes,token);
}
public void SetCreationTime(UnixPath path, DateTime time)
{
fs.SetCreationTime(path,time);
}
public async Task SetCreationTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
await fs.SetCreationTimeAsync(path,time,token);
}
public void SetLastAccessTime(UnixPath path, DateTime time)
{
fs.SetLastAccessTime(path,time);
}
public async Task SetLastAccessTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
await fs.SetLastAccessTimeAsync(path,time,token);
}
public void SetLastWriteTime(UnixPath path, DateTime time)
{
fs.SetLastWriteTime(path,time);
}
public async Task SetLastWriteTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
await fs.SetLastWriteTimeAsync(path,time,token);
}
public bool SymlinkExists(UnixPath file)
{
return fs.SymlinkExists(file);
}
public async Task<bool> SymlinkExistsAsync(UnixPath file, CancellationToken token = default)
{
return await fs.SymlinkExistsAsync(file,token);
}
public UnixPath UpPath(UnixPath path)
{
return fs.UpPath(path);
}
public IVirtualWatcher WatchDirectory(UnixPath dir)
{
return fs.WatchDirectory(dir);
}
}
IVirtualFilesystem root;
public MultiLayerFS(IVirtualFilesystem root)
{
this.root=root;
}
public class CloseEvtStream : Stream
{
Stream parent;
Action cstrm;
bool destroyParent;
public CloseEvtStream(Stream parent,Action closed,bool destroyParent=true)
{
this.destroyParent=destroyParent;
this.parent = parent;
this.cstrm = closed;
}
public override bool CanRead => parent.CanRead;
public override bool CanSeek => parent.CanSeek;
public override bool CanWrite => parent.CanWrite;
public override long Length => parent.Length;
public override long Position { get => parent.Position; set => parent.Position = value; }
public override void Flush()
{
parent.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return parent.Read(buffer,offset,count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return parent.Seek(offset,origin);
}
public override void SetLength(long value)
{
parent.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
parent.Write(buffer,offset,count);
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
return parent.BeginRead(buffer, offset, count, callback, state);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
return parent.BeginWrite(buffer, offset, count, callback, state);
}
public override bool CanTimeout => parent.CanTimeout;
public override void Close()
{
if(destroyParent)
parent.Close();
cstrm();
}
protected override void Dispose(bool disposing)
{
if(disposing && destroyParent)
parent.Dispose();
cstrm();
}
public override void EndWrite(IAsyncResult asyncResult)
{
parent.EndWrite(asyncResult);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return parent.WriteAsync(buffer, offset, count, cancellationToken);
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return parent.FlushAsync(cancellationToken);
}
public override void WriteByte(byte value)
{
parent.WriteByte(value);
}
public override int EndRead(IAsyncResult asyncResult)
{
return parent.EndRead(asyncResult);
}
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
return parent.CopyToAsync(destination, bufferSize, cancellationToken);
}
}
List<IVirtualFilesystem> fs2=new List<IVirtualFilesystem>();
Dictionary<IVirtualFilesystem,(List<Stream> StreamList,Action2Event Destroy)> streams = new Dictionary<IVirtualFilesystem, (List<Stream> StreamList,Action2Event Destroy)>();
Dictionary<string,IVirtualFilesystem> fs=new Dictionary<string, IVirtualFilesystem>();
public override UnixPath UpPath(UnixPath path)
{
var unixPathLs = path as UnixPathList;
if(unixPathLs != null)
{
return unixPathLs.ParentPL;
}else{
return path.Parent;
}
}
Dictionary<string,IVirtualFileSystemCreator> _creators=new Dictionary<string,IVirtualFileSystemCreator>();
public void Register(string scheme,IVirtualFileSystemCreator fs)
{
_creators.Add(scheme,fs);
}
public void Register(IVirtualFileSystemCreator fs)
{
_creators.Add(fs.Scheme,fs);
}
public override void Dispose()
{
while(fs2.Count>0 && streams.Count > 0)
{
if(streams.ContainsKey(fs2[0]))
{
var strm = streams[fs2[0]];
foreach(var strm0 in strm.StreamList)
{
strm0.Dispose();
}
strm.StreamList.Clear();
CloseFileSystemIfNoStreams(fs2[0]);
streams.Remove(fs2[0]);
fs2.Remove(fs2[0]);
}
}
streams.Clear();
fs.Clear();
}
public override async Task CreateDirectoryAsync(UnixPath directory, CancellationToken token = default)
{
var fs=await OpenTillAsync(directory,token);
await fs.CreateDirectoryAsync(Last(directory));
CloseFileSystemIfNoStreams(fs);
}
private async Task<IVirtualFilesystem> OpenTillAsync(UnixPath path,CancellationToken token=default)
{
UnixPathList pathLs = path as UnixPathList;
if(pathLs != null && pathLs.Count > 1)
{
return await OpenTillAsync(pathLs,token);
}
return root;
}
private async Task<IVirtualFilesystem> OpenTillAsync(UnixPathList path,CancellationToken token=default)
{
IVirtualFilesystem fs=root;
List<UnixPath> paths=new List<UnixPath>();
for(int i = 0;i<path.Count-1;i++)
{
paths.Add(path[i]);
var curP = new UnixPathList(paths);
fs=await OpenFileSystemAsync(fs,curP,token);
if(token.IsCancellationRequested) {this.CloseFileSystemIfNoStreams(fs); return null;}
}
return fs;
}
Mutex mtx=new Mutex();
private async Task<Stream> OpenStreamOnBehalf(IVirtualFilesystem fs,UnixPath p,FileMode mode,FileAccess access,FileShare share,CancellationToken token=default(CancellationToken))
{
Stream strm = await fs.OpenAsync(p,mode,access,share);
CloseEvtStream strmI=new CloseEvtStream(strm,()=>{
mtx.WaitOne();
if(streams.ContainsKey(fs))
{
var strmItem = streams[fs];
if(strmItem.StreamList.Contains(strm))
{
strmItem.StreamList.Remove(strm);
}
if(strmItem.StreamList.Count == 0)
{
strmItem.Destroy.Invoke();
streams.Remove(fs);
string key = "";
foreach(var i in this.fs)
{
if(i.Value == fs)
{
key = i.Key;
break;
}
}
if(this.fs.ContainsKey(key))
{
this.fs.Remove(key);
}
}
}
mtx.ReleaseMutex();
});
mtx.WaitOne();
if(streams.ContainsKey(fs))
{
var strmItem = streams[fs];
if(!strmItem.StreamList.Contains(strm))
{
strmItem.StreamList.Add(strm);
}
}
mtx.ReleaseMutex();
return strmI;
}
public UnixPath ExceptLast(UnixPath p)
{
UnixPathList pl = p as UnixPathList;
if(pl != null && pl.Count > 0)
{
List<UnixPath> paths=new List<UnixPath>();
for(int i = 0;i<pl.Count-1;i++)
{
paths.Add(pl[i]);
}
return new UnixPathList(paths);
}
return p;
}
private UnixPath Last(UnixPath p)
{
UnixPathList pl=p as UnixPathList;
if(pl!=null && pl.Count >0)
{
return pl[pl.Count-1];
}
return p;
}
private async Task<IVirtualFilesystem> OpenFileSystemAsync(IVirtualFilesystem parent,UnixPath p,CancellationToken token=default)
{
if(string.IsNullOrWhiteSpace(p.Scheme)) return parent;
mtx.WaitOne();
var last=Last(p);
if(!_creators.ContainsKey(last.Scheme)){ mtx.ReleaseMutex();return null;}
if(parent == root)
{
if(fs.ContainsKey(p.AsText))
{
var res0= fs[p.AsText];
mtx.ReleaseMutex();
return res0;
}
var res=_creators[p.Scheme];
if(res.IsDirectoryOrganizer)
{
var c = res.Open(root,last);
fs.Add(p.AsText,c);
return c;
}else{
var strm = await OpenAsync(last,FileMode.Open,FileAccess.ReadWrite,FileShare.None,token);
var c = res.Open(strm);
Action a =()=>{
c.Dispose();
strm.Dispose();
};
streams.Add(c,(new List<Stream>(),a));
fs.Add(p.AsText,c);
return c;
}
}else{mtx.ReleaseMutex();
if(fs.ContainsKey(p.AsText))
{
var res0= fs[p.AsText];
mtx.ReleaseMutex();
return res0;
}
var res=_creators[p.Scheme];
if(res.IsDirectoryOrganizer)
{
var parent2 = new FileSystemWithCustomOpen(parent,async(path,mode,access,share,token)=>{
return await OpenStreamOnBehalf(parent,path,mode,access,share,token);
});
var c = res.Open(parent2,last);
streams[parent].Destroy.Add(c.Dispose);
fs2.Insert(0,c);
fs.Add(p.AsText,c);
return c;
}else{
var res0=await OpenStreamOnBehalf(parent,last,FileMode.Open,FileAccess.ReadWrite,FileShare.None,token);
var c = res.Open(res0);
Action a =()=>{
if(fs2.Contains(c))
fs2.Remove(c);
c.Dispose();
res0.Dispose();
};
streams.Add(c,(new List<Stream>(),a));
fs.Add(p.AsText,c);
fs2.Insert(0,c);
mtx.ReleaseMutex();
return c;
}
}
}
private void CloseFileSystemIfNoStreams(IVirtualFilesystem fs)
{
if(fs == root) return;
mtx.WaitOne();
if(streams.ContainsKey(fs))
{
var strmItem = streams[fs];
if(strmItem.StreamList.Count == 0)
{
strmItem.Destroy.Invoke();
}
}
mtx.ReleaseMutex();
}
public override async Task DeleteDirectoryAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
await fs.DeleteDirectoryAsync(Last(path),token);
CloseFileSystemIfNoStreams(fs);
}
public override async Task DeleteFileAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
await fs.DeleteFileAsync(Last(path),token);
CloseFileSystemIfNoStreams(fs);
}
public override async Task<bool> DirectoryExistsAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
var res=await fs.DirectoryExistsAsync(Last(path));
CloseFileSystemIfNoStreams(fs);
return res;
}
public override async IAsyncEnumerable<UnixPath> EnumerateDirectoriesAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
using(var reg= token.Register(()=>{
CloseFileSystemIfNoStreams(fs);
})){
await foreach(var item in fs.EnumerateDirectoriesAsync(Last(path)))
{
yield return item;
}
CloseFileSystemIfNoStreams(fs);
}
}
public override async IAsyncEnumerable<UnixPath> EnumerateFilesAsync(UnixPath path, [EnumeratorCancellation] CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
using(var reg= token.Register(()=>{
CloseFileSystemIfNoStreams(fs);
})){
await foreach(var item in fs.EnumerateFilesAsync(Last(path)))
{
yield return item;
}
CloseFileSystemIfNoStreams(fs);
}
}
public override async Task<bool> FileExistsAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
bool res = await fs.FileExistsAsync(Last(path),token);
CloseFileSystemIfNoStreams(fs);
return res;
}
public override async Task<DateTime> GetCreationTimeAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
DateTime res = await fs.GetCreationTimeAsync(Last(path),token);
CloseFileSystemIfNoStreams(fs);
return res;
}
public override async Task<DateTime> GetLastAccessTimeAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
DateTime res = await fs.GetLastAccessTimeAsync(Last(path),token);
CloseFileSystemIfNoStreams(fs);
return res;
}
public override async Task<DateTime> GetLastWriteTimeAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path,token);
DateTime res = await fs.GetLastWriteTimeAsync(Last(path),token);
CloseFileSystemIfNoStreams(fs);
return res;
}
public override async Task MoveDirectoryAsync(UnixPath src, UnixPath dest)
{
if(ExceptLast(src).AsText == ExceptLast(dest).AsText)
{
var fs=await OpenTillAsync(src);
await fs.MoveDirectoryAsync(Last(src),Last(dest));
CloseFileSystemIfNoStreams(fs);
}else{
var fs=await OpenTillAsync(src);
var fs2=await OpenTillAsync(dest);
await fs.MoveDirectoryAsync(fs2,Last(src),Last(dest));
CloseFileSystemIfNoStreams(fs);
CloseFileSystemIfNoStreams(fs2);
}
}
public override async Task MoveFileAsync(UnixPath src, UnixPath dest)
{
if(ExceptLast(src).AsText == ExceptLast(dest).AsText)
{
var fs=await OpenTillAsync(src);
await fs.MoveFileAsync(Last(src),Last(dest));
CloseFileSystemIfNoStreams(fs);
}else{
var fs=await OpenTillAsync(src);
var fs2=await OpenTillAsync(dest);
await fs.MoveFileAsync(fs2,Last(src),Last(dest));
CloseFileSystemIfNoStreams(fs);
CloseFileSystemIfNoStreams(fs2);
}
}
public override async Task<Stream> OpenAsync(UnixPath path, FileMode mode, FileAccess access, FileShare share, CancellationToken token = default)
{
var fs = await OpenTillAsync(path,token);
using(var t = token.Register(()=>{CloseFileSystemIfNoStreams(fs);}))
{
return await OpenStreamOnBehalf(fs,Last(path),mode,access,share,token);
}
}
public override async Task SetCreationTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
var fs=await OpenTillAsync(path);
await fs.SetCreationTimeAsync(Last(path),time,token);
CloseFileSystemIfNoStreams(fs);
}
public override async Task SetLastAccessTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
var fs=await OpenTillAsync(path);
await fs.SetLastAccessTimeAsync(Last(path),time,token);
CloseFileSystemIfNoStreams(fs);
}
public override async Task SetAttributesAsync(UnixPath path, FileAttributes attributes, CancellationToken token = default)
{
var fs=await OpenTillAsync(path);
await fs.SetAttributesAsync(Last(path),attributes,token);
CloseFileSystemIfNoStreams(fs);
}
public override bool CanWatch(UnixPath path)
{
return false;
}
public override async Task<UnixPath> ReadLinkAsync(UnixPath file, CancellationToken token = default)
{
var fs=await OpenTillAsync(file);
var rlink=await fs.ReadLinkAsync(Last(file));
CloseFileSystemIfNoStreams(fs);
return rlink;
}
public override async Task<bool> SameFileSystemAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
return await Task.FromResult(ExceptLast(src).AsText == ExceptLast(dest).AsText);
}
public override Task<bool> SymlinkExistsAsync(UnixPath file, CancellationToken token = default)
{
return base.SymlinkExistsAsync(file, token);
}
public override async Task<FileAttributes> GetAttributesAsync(UnixPath path, CancellationToken token = default)
{
var fs=await OpenTillAsync(path);
var res=await fs.GetAttributesAsync(Last(path));
CloseFileSystemIfNoStreams(fs);
return res;
}
public override async Task CreateSymlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
if(ExceptLast(src).AsText != ExceptLast(dest).AsText) return;
var fs=await OpenTillAsync(src);
await fs.CreateSymlinkAsync(Last(src),Last(dest));
CloseFileSystemIfNoStreams(fs);
}
public override async Task CreateHardlinkAsync(UnixPath src, UnixPath dest, CancellationToken token = default)
{
if(ExceptLast(src).AsText != ExceptLast(dest).AsText) return;
var fs=await OpenTillAsync(src);
await fs.CreateHardlinkAsync(Last(src),Last(dest));
CloseFileSystemIfNoStreams(fs);
}
public override bool CanHandleSymlinks(UnixPath path)
{
var fs=Task.Run<IVirtualFilesystem>(async()=>await OpenTillAsync(path)).GetAwaiter().GetResult();
var can=fs.CanHandleSymlinks(Last(path));
CloseFileSystemIfNoStreams(fs);
return can;
}
public override async Task SetLastWriteTimeAsync(UnixPath path, DateTime time, CancellationToken token = default)
{
var fs=await OpenTillAsync(path);
await fs.SetLastWriteTimeAsync(Last(path),time,token);
CloseFileSystemIfNoStreams(fs);
}
}
*/
public class Action2Event
{
public Action2Event(Action a)
{
Event+=a;
}
public void Add(Action a)
{
Event+=a;
}
public void Invoke()
{
Event?.Invoke();
}
public event Action Event;
public static implicit operator Action2Event(Action a)
{
return new Action2Event(a);
}
}
}