StreamCopyCommandHandler, Async rename
This commit is contained in:
@@ -9,7 +9,7 @@ namespace FileTime.Providers.Smb
|
||||
{
|
||||
public class SmbContentProvider : IContentProvider
|
||||
{
|
||||
private readonly object _initializationGuard = new object();
|
||||
private readonly object _initializationGuard = new();
|
||||
private bool _initialized;
|
||||
private bool _initializing;
|
||||
private IContainer? _parent;
|
||||
@@ -39,6 +39,7 @@ namespace FileTime.Providers.Smb
|
||||
public bool SupportsDirectoryLevelSoftDelete => false;
|
||||
|
||||
public bool IsDestroyed => false;
|
||||
public bool SupportsContentStreams => true;
|
||||
|
||||
public SmbContentProvider(IInputInterface inputInterface, Persistence.PersistenceService persistenceService, ILogger<SmbContentProvider> logger)
|
||||
{
|
||||
@@ -50,7 +51,7 @@ namespace FileTime.Providers.Smb
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<IContainer> CreateContainer(string name)
|
||||
public async Task<IContainer> CreateContainerAsync(string name)
|
||||
{
|
||||
var fullName = "\\\\" + name;
|
||||
var container = _rootContainers.Find(c => c.Name == name);
|
||||
@@ -69,7 +70,7 @@ namespace FileTime.Providers.Smb
|
||||
return container;
|
||||
}
|
||||
|
||||
public Task<IElement> CreateElement(string name)
|
||||
public Task<IElement> CreateElementAsync(string name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
@@ -98,9 +99,9 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
public IContainer? GetParent() => _parent;
|
||||
|
||||
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
|
||||
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
|
||||
|
||||
public async Task<bool> IsExists(string name) => (await GetItems())?.Any(i => i.Name == name) ?? false;
|
||||
public async Task<bool> IsExistsAsync(string name) => (await GetItems())?.Any(i => i.Name == name) ?? false;
|
||||
|
||||
public async Task RefreshAsync(CancellationToken token = default) => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
|
||||
|
||||
@@ -124,7 +125,7 @@ namespace FileTime.Providers.Smb
|
||||
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult((IReadOnlyList<IElement>?)_elements);
|
||||
|
||||
public Task Rename(string newName) => throw new NotSupportedException();
|
||||
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||
public Task<bool> CanOpenAsync() => Task.FromResult(true);
|
||||
|
||||
public void Destroy() { }
|
||||
|
||||
|
||||
67
src/Providers/FileTime.Providers.Smb/SmbContentReader.cs
Normal file
67
src/Providers/FileTime.Providers.Smb/SmbContentReader.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using FileTime.Core.Providers;
|
||||
using SMBLibrary;
|
||||
using SMBLibrary.Client;
|
||||
|
||||
namespace FileTime.Providers.Smb
|
||||
{
|
||||
public class SmbContentReader : IContentReader
|
||||
{
|
||||
private readonly ISMBFileStore _smbFileStore;
|
||||
private readonly object _fileHandle;
|
||||
private readonly ISMBClient _client;
|
||||
private bool disposed;
|
||||
private long _bytesRead;
|
||||
|
||||
public int PreferredBufferSize => (int)_client.MaxReadSize;
|
||||
|
||||
public SmbContentReader(ISMBFileStore smbFileStore, object fileHandle, ISMBClient client)
|
||||
{
|
||||
_smbFileStore = smbFileStore;
|
||||
_fileHandle = fileHandle;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public Task<byte[]> ReadBytesAsync(int bufferSize)
|
||||
{
|
||||
var max = bufferSize > 0 && bufferSize < (int)_client.MaxReadSize ? bufferSize : (int)_client.MaxReadSize;
|
||||
|
||||
var status = _smbFileStore.ReadFile(out byte[] data, _fileHandle, _bytesRead, max);
|
||||
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE)
|
||||
{
|
||||
throw new Exception("Failed to read from file");
|
||||
}
|
||||
|
||||
if (status == NTStatus.STATUS_END_OF_FILE || data.Length == 0)
|
||||
{
|
||||
return Task.FromResult(Array.Empty<byte>());
|
||||
}
|
||||
_bytesRead += data.Length;
|
||||
|
||||
return Task.FromResult(data);
|
||||
}
|
||||
|
||||
~SmbContentReader()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_smbFileStore.CloseFile(_fileHandle);
|
||||
_smbFileStore.Disconnect();
|
||||
}
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/Providers/FileTime.Providers.Smb/SmbContentWriter.cs
Normal file
24
src/Providers/FileTime.Providers.Smb/SmbContentWriter.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using FileTime.Core.Providers;
|
||||
|
||||
namespace FileTime.Providers.Smb
|
||||
{
|
||||
public class SmbContentWriter : IContentWriter
|
||||
{
|
||||
public int PreferredBufferSize => throw new NotImplementedException();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task FlushAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task WriteBytesAsync(byte[] data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Providers;
|
||||
using SMBLibrary;
|
||||
|
||||
namespace FileTime.Providers.Smb
|
||||
{
|
||||
public class SmbFile : IElement
|
||||
{
|
||||
private readonly IContainer _parent;
|
||||
private readonly SmbClientContext _smbClientContext;
|
||||
private readonly SmbShare _smbShare;
|
||||
|
||||
public bool IsSpecial => false;
|
||||
|
||||
public string Name { get; }
|
||||
@@ -17,11 +22,10 @@ namespace FileTime.Providers.Smb
|
||||
public bool CanRename => true;
|
||||
|
||||
public IContentProvider Provider { get; }
|
||||
private IContainer _parent;
|
||||
|
||||
public bool IsDestroyed { get; private set; }
|
||||
|
||||
public SmbFile(string name, SmbContentProvider provider, IContainer parent)
|
||||
public SmbFile(string name, SmbContentProvider provider, SmbShare smbShare, IContainer parent, SmbClientContext smbClientContext)
|
||||
{
|
||||
Name = name;
|
||||
FullName = parent.FullName + Constants.SeparatorChar + Name;
|
||||
@@ -29,6 +33,8 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
Provider = provider;
|
||||
_parent = parent;
|
||||
_smbClientContext = smbClientContext;
|
||||
_smbShare = smbShare;
|
||||
}
|
||||
|
||||
public Task Delete(bool hardDelete = false)
|
||||
@@ -50,5 +56,35 @@ namespace FileTime.Providers.Smb
|
||||
public Task<long> GetElementSize(CancellationToken token = default) => Task.FromResult(-1L);
|
||||
|
||||
public void Destroy() => IsDestroyed = true;
|
||||
|
||||
public async Task<IContentReader> GetContentReaderAsync()
|
||||
{
|
||||
return await _smbClientContext.RunWithSmbClientAsync(client =>
|
||||
{
|
||||
NTStatus status = NTStatus.STATUS_DATA_ERROR;
|
||||
var fileStore = _smbShare.TreeConnect(client, out status);
|
||||
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
throw new Exception($"Could not open file {NativePath} for read.");
|
||||
}
|
||||
|
||||
var path = NativePath!;
|
||||
path = path[(_parent.NativePath!.Length + 1)..];
|
||||
status = fileStore.CreateFile(out object fileHandle, out FileStatus fileStatus, path, AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, SMBLibrary.FileAttributes.Normal, ShareAccess.Read, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);
|
||||
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
throw new Exception($"Could not open file {NativePath} for read.");
|
||||
}
|
||||
|
||||
return new SmbContentReader(fileStore, fileHandle, client);
|
||||
});
|
||||
}
|
||||
|
||||
public Task<IContentWriter> GetContentWriterAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ namespace FileTime.Providers.Smb
|
||||
private IReadOnlyList<IItem>? _items;
|
||||
private IReadOnlyList<IContainer>? _containers;
|
||||
private IReadOnlyList<IElement>? _elements;
|
||||
private readonly SmbShare _smbShare;
|
||||
private readonly IContainer? _parent;
|
||||
|
||||
public string Name { get; }
|
||||
@@ -22,6 +21,7 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
public SmbContentProvider Provider { get; }
|
||||
IContentProvider IItem.Provider => Provider;
|
||||
public SmbShare SmbShare { get; }
|
||||
public SupportsDelete CanDelete => SupportsDelete.True;
|
||||
public bool CanRename => true;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace FileTime.Providers.Smb
|
||||
public SmbFolder(string name, SmbContentProvider contentProvider, SmbShare smbShare, IContainer parent)
|
||||
{
|
||||
_parent = parent;
|
||||
_smbShare = smbShare;
|
||||
SmbShare = smbShare;
|
||||
|
||||
Name = name;
|
||||
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
||||
@@ -43,21 +43,21 @@ namespace FileTime.Providers.Smb
|
||||
Provider = contentProvider;
|
||||
}
|
||||
|
||||
public Task<IContainer> CreateContainer(string name)
|
||||
public Task<IContainer> CreateContainerAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IElement> CreateElement(string name)
|
||||
public Task<IElement> CreateElementAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
|
||||
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
|
||||
|
||||
public IContainer? GetParent() => _parent;
|
||||
|
||||
public Task<bool> IsExists(string name)
|
||||
public Task<bool> IsExistsAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -78,8 +78,8 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
try
|
||||
{
|
||||
var path = FullName![(_smbShare.FullName!.Length + 1)..];
|
||||
(containers, elements) = await _smbShare.ListFolder(this, _smbShare.Name, path, token);
|
||||
var path = FullName![(SmbShare.FullName!.Length + 1)..];
|
||||
(containers, elements) = await SmbShare.ListFolder(this, path, token);
|
||||
}
|
||||
catch { }
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace FileTime.Providers.Smb
|
||||
if (_elements == null) await RefreshAsync(token);
|
||||
return _elements;
|
||||
}
|
||||
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||
public Task<bool> CanOpenAsync() => Task.FromResult(true);
|
||||
|
||||
public void Destroy() => IsDestroyed = true;
|
||||
|
||||
|
||||
@@ -69,12 +69,12 @@ namespace FileTime.Providers.Smb
|
||||
return Task.FromResult(_elements);
|
||||
}
|
||||
|
||||
public Task<IContainer> CreateContainer(string name)
|
||||
public Task<IContainer> CreateContainerAsync(string name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Task<IElement> CreateElement(string name)
|
||||
public Task<IElement> CreateElementAsync(string name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
public IContainer? GetParent() => Provider;
|
||||
|
||||
public Task<bool> IsExists(string name)
|
||||
public Task<bool> IsExistsAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -120,7 +120,7 @@ namespace FileTime.Providers.Smb
|
||||
await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
|
||||
}
|
||||
|
||||
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
|
||||
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
|
||||
|
||||
private void DisposeSmbClient()
|
||||
{
|
||||
@@ -211,7 +211,7 @@ namespace FileTime.Providers.Smb
|
||||
}
|
||||
|
||||
public Task Rename(string newName) => throw new NotSupportedException();
|
||||
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||
public Task<bool> CanOpenAsync() => Task.FromResult(true);
|
||||
|
||||
public void Destroy() { }
|
||||
|
||||
|
||||
@@ -61,12 +61,12 @@ namespace FileTime.Providers.Smb
|
||||
return _elements;
|
||||
}
|
||||
|
||||
public Task<IContainer> CreateContainer(string name)
|
||||
public Task<IContainer> CreateContainerAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IElement> CreateElement(string name)
|
||||
public Task<IElement> CreateElementAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -78,9 +78,9 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
public IContainer? GetParent() => _parent;
|
||||
|
||||
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
|
||||
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
|
||||
|
||||
public Task<bool> IsExists(string name)
|
||||
public Task<bool> IsExistsAsync(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -92,7 +92,7 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
try
|
||||
{
|
||||
(containers, elements) = await ListFolder(this, Name, string.Empty, token);
|
||||
(containers, elements) = await ListFolder(this, string.Empty, token);
|
||||
}
|
||||
catch { }
|
||||
|
||||
@@ -111,14 +111,15 @@ namespace FileTime.Providers.Smb
|
||||
await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
|
||||
}
|
||||
|
||||
public async Task<(List<IContainer> containers, List<IElement> elements)> ListFolder(IContainer parent, string shareName, string folderName, CancellationToken token = default)
|
||||
public async Task<(List<IContainer> containers, List<IElement> elements)> ListFolder(IContainer parent, string folderName, CancellationToken token = default)
|
||||
{
|
||||
return await _smbClientContext.RunWithSmbClientAsync(client =>
|
||||
{
|
||||
var containers = new List<IContainer>();
|
||||
var elements = new List<IElement>();
|
||||
NTStatus status = NTStatus.STATUS_DATA_ERROR;
|
||||
ISMBFileStore fileStore = client.TreeConnect(shareName, out status);
|
||||
var status = NTStatus.STATUS_DATA_ERROR;
|
||||
var fileStore = TreeConnect(client, out status);
|
||||
|
||||
if (status == NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
status = fileStore.CreateFile(out object directoryHandle, out FileStatus fileStatus, folderName, AccessMask.GENERIC_READ, SMBLibrary.FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
|
||||
@@ -137,7 +138,7 @@ namespace FileTime.Providers.Smb
|
||||
}
|
||||
else
|
||||
{
|
||||
elements.Add(new SmbFile(fileDirectoryInformation.FileName, Provider, parent));
|
||||
elements.Add(new SmbFile(fileDirectoryInformation.FileName, Provider, this, parent, _smbClientContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,8 +152,13 @@ namespace FileTime.Providers.Smb
|
||||
});
|
||||
}
|
||||
|
||||
internal ISMBFileStore TreeConnect(ISMBClient client, out NTStatus status)
|
||||
{
|
||||
return client.TreeConnect(Name, out status);
|
||||
}
|
||||
|
||||
public Task Rename(string newName) => throw new NotSupportedException();
|
||||
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||
public Task<bool> CanOpenAsync() => Task.FromResult(true);
|
||||
|
||||
public void Destroy() { }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user