Exemplo n.º 1
0
        internal void SaveDirectoryInfo(SMBDirectoryInfo dirInfo, ISMBCredential credential = null)
        {
            var path = dirInfo.FullName;

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed to SaveDirectoryInfo for {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            NTStatus status = NTStatus.STATUS_SUCCESS;

            if (credential == null)
            {
                credential = _credentialProvider.GetSMBCredential(path);
            }

            if (credential == null)
            {
                throw new SMBException($"Failed to SaveDirectoryInfo for {path}", new InvalidCredentialException($"Unable to find credential for path: {path}"));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying to SaveDirectoryInfo {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize);

                fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                status.HandleStatus();

                status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, AccessMask.GENERIC_WRITE, 0, ShareAccess.Read,
                                              CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                status.HandleStatus();

                var fileInfo = dirInfo.ToSMBFileInformation(credential);
                status = fileStore.SetFileInformation(handle, fileInfo);

                status.HandleStatus();
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed to SaveDirectoryInfo for {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 2
0
        public override bool Exists(string path)
        {
            if (!path.IsSharePath())
            {
                return(base.Exists(path));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                if (!path.TryResolveHostnameFromPath(out var ipAddress))
                {
                    throw new SMBException($"Failed to determine if {path} exists", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
                }

                NTStatus status = NTStatus.STATUS_SUCCESS;

                var credential = _credentialProvider.GetSMBCredential(path);

                using (var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize))
                {
                    var shareName     = path.ShareName();
                    var directoryPath = _fileSystem.Path.GetDirectoryName(path).Replace(path.SharePath(), "").RemoveLeadingAndTrailingSeperators();
                    var fileName      = _fileSystem.Path.GetFileName(path);

                    _logger?.LogTrace($"Trying to determine if {{DirectoryPath: {directoryPath}}} {{FileName: {fileName}}} Exists for {{ShareName: {shareName}}}");

                    fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                    status.HandleStatus();

                    AccessMask        accessMask    = AccessMask.SYNCHRONIZE | AccessMask.GENERIC_READ;
                    ShareAccess       shareAccess   = ShareAccess.Read;
                    CreateDisposition disposition   = CreateDisposition.FILE_OPEN;
                    CreateOptions     createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_DIRECTORY_FILE;

                    status = fileStore.CreateFile(out handle, out FileStatus fileStatus, directoryPath, accessMask, 0, shareAccess,
                                                  disposition, createOptions, null);

                    status.HandleStatus();

                    fileStore.QueryDirectory(out List <QueryDirectoryFileInformation> queryDirectoryFileInformation, handle, string.IsNullOrEmpty(fileName) ? "*" : fileName, FileInformationClass.FileDirectoryInformation);

                    foreach (var file in queryDirectoryFileInformation)
                    {
                        if (file.FileInformationClass == FileInformationClass.FileDirectoryInformation)
                        {
                            FileDirectoryInformation fileDirectoryInformation = (FileDirectoryInformation)file;
                            if (fileDirectoryInformation.FileName == fileName)
                            {
                                FileStoreUtilities.CloseFile(fileStore, ref handle);
                                return(true);
                            }
                        }
                    }

                    FileStoreUtilities.CloseFile(fileStore, ref handle);
                }

                return(false);
            }
            catch (Exception ex)
            {
                _logger?.LogTrace(ex, $"Failed to determine if {path} exists.");
                return(false);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 3
0
        public override void Delete(string path)
        {
            if (!path.IsSharePath())
            {
                base.Delete(path);
                return;
            }

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed to Delete {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            var credential = _credentialProvider.GetSMBCredential(path);

            if (credential == null)
            {
                throw new SMBException($"Failed to Delete {path}", new InvalidCredentialException($"Unable to find credential in SMBCredentialProvider for path: {path}"));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying to Delete {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using (var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize))
                {
                    fileStore = connection.SMBClient.TreeConnect(shareName, out var status);

                    status.HandleStatus();

                    AccessMask        accessMask    = AccessMask.SYNCHRONIZE | AccessMask.DELETE;
                    ShareAccess       shareAccess   = ShareAccess.Read | ShareAccess.Delete;
                    CreateDisposition disposition   = CreateDisposition.FILE_OPEN;
                    CreateOptions     createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_DELETE_ON_CLOSE;

                    var stopwatch = new Stopwatch();
                    stopwatch.Start();

                    do
                    {
                        if (status == NTStatus.STATUS_PENDING)
                        {
                            _logger.LogTrace($"STATUS_PENDING while trying to delete file {path}. {stopwatch.Elapsed.TotalSeconds}/{_smbFileSystemSettings.ClientSessionTimeout} seconds elapsed.");
                        }

                        status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, accessMask, 0, shareAccess,
                                                      disposition, createOptions, null);
                    }while (status == NTStatus.STATUS_PENDING && stopwatch.Elapsed.TotalSeconds <= _smbFileSystemSettings.ClientSessionTimeout);

                    stopwatch.Stop();
                    status.HandleStatus();

                    // There should be a seperate option to delete, but it doesn't seem to exsist in the library we are using, so this should work for now. Really hacky though.
                    FileStoreUtilities.CloseFile(fileStore, ref handle);
                }
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed to Delete {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 4
0
        internal IDirectoryInfo FromDirectoryName(string path, ISMBCredential credential)
        {
            if (!path.IsSharePath() || !path.IsValidSharePath())
            {
                return(null);
            }

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed FromDirectoryName for {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            NTStatus status = NTStatus.STATUS_SUCCESS;

            if (credential == null)
            {
                credential = _credentialProvider.GetSMBCredential(path);
            }

            if (credential == null)
            {
                throw new SMBException($"Failed FromDirectoryName for {path}", new InvalidCredentialException($"Unable to find credential for path: {path}"));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying FromDirectoryName {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize);

                fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                status.HandleStatus();

                status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, AccessMask.GENERIC_READ, 0, ShareAccess.Read,
                                              CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                status.HandleStatus();

                status = fileStore.GetFileInformation(out FileInformation fileInfo, handle, FileInformationClass.FileBasicInformation); // If you call this with any other FileInformationClass value
                                                                                                                                        // it doesn't work for some reason
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    return(null);
                }

                return(new SMBDirectoryInfo(path, fileInfo, _fileSystem, _credentialProvider, credential));
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed FromDirectoryName for {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 5
0
        internal IFileInfo FromFileName(string path, ISMBCredential credential)
        {
            if (!path.IsSharePath())
            {
                return(null);
            }

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed FromFileName for {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            NTStatus status = NTStatus.STATUS_SUCCESS;

            if (credential == null)
            {
                credential = _credentialProvider.GetSMBCredential(path);
            }

            if (credential == null)
            {
                throw new SMBException($"Failed FromFileName for {path}", new InvalidCredentialException($"Unable to find credential for path: {path}"));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying FromFileName {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize);

                fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                status.HandleStatus();

                AccessMask        accessMask    = AccessMask.SYNCHRONIZE | AccessMask.GENERIC_READ;
                ShareAccess       shareAccess   = ShareAccess.Read;
                CreateDisposition disposition   = CreateDisposition.FILE_OPEN;
                CreateOptions     createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_NON_DIRECTORY_FILE;

                status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, accessMask, 0, shareAccess,
                                              disposition, createOptions, null);

                status.HandleStatus();

                status = fileStore.GetFileInformation(out FileInformation fileBasicInfo, handle, FileInformationClass.FileBasicInformation);
                status.HandleStatus();
                status = fileStore.GetFileInformation(out FileInformation fileStandardInfo, handle, FileInformationClass.FileStandardInformation);
                status.HandleStatus();

                FileStoreUtilities.CloseFile(fileStore, ref handle);

                return(new SMBFileInfo(path, _fileSystem, (FileBasicInformation)fileBasicInfo, (FileStandardInformation)fileStandardInfo, credential));
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed FromFileName for {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 6
0
        public override bool Exists(string path)
        {
            if (!path.IsSharePath())
            {
                return(base.Exists(path));
            }

            // For some reason Directory.Exists is returning true if a file exists at that path.
            // File.Exists works properly so as long as we check it here we are fine.
            if (_fileSystem.File.Exists(path))
            {
                return(false);
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                if (!path.TryResolveHostnameFromPath(out var ipAddress))
                {
                    throw new SMBException($"Failed to determine if {path} exists", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
                }

                NTStatus status = NTStatus.STATUS_SUCCESS;

                var credential = _credentialProvider.GetSMBCredential(path);

                using (var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize))
                {
                    var shareName    = path.ShareName();
                    var relativePath = path.RelativeSharePath();

                    _logger?.LogTrace(
                        $"Trying to determine if {{RelativePath: {relativePath}}} Exists for {{ShareName: {shareName}}}");

                    if (string.IsNullOrEmpty(relativePath))
                    {
                        return(true);
                    }

                    var parentFullPath = path.GetParentPath();
                    var parentPath     = parentFullPath.RelativeSharePath();
                    var directoryName  = path.GetLastPathSegment().RemoveLeadingAndTrailingSeperators();

                    fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                    status.HandleStatus();

                    status = fileStore.CreateFile(out handle, out FileStatus fileStatus, parentPath, AccessMask.GENERIC_READ, 0, ShareAccess.Read,
                                                  CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                    status.HandleStatus();

                    fileStore.QueryDirectory(out List <QueryDirectoryFileInformation> queryDirectoryFileInformation, handle, string.IsNullOrEmpty(directoryName) ? "*" : directoryName, FileInformationClass.FileDirectoryInformation);

                    foreach (var file in queryDirectoryFileInformation)
                    {
                        if (file.FileInformationClass == FileInformationClass.FileDirectoryInformation)
                        {
                            FileDirectoryInformation fileDirectoryInformation = (FileDirectoryInformation)file;
                            if (fileDirectoryInformation.FileName == directoryName)
                            {
                                return(true);
                            }
                        }
                    }
                }

                return(false);
            }
            catch (Exception ex)
            {
                _logger?.LogTrace(ex, $"Failed to determine if {path} exists.");
                return(false);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 7
0
        private IEnumerable <string> EnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption, ISMBCredential credential)
        {
            if (!path.IsSharePath())
            {
                return(base.EnumerateFileSystemEntries(path, searchPattern, searchOption));
            }

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed to EnumerateFileSystemEntries for {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            NTStatus status = NTStatus.STATUS_SUCCESS;

            if (credential == null)
            {
                credential = _credentialProvider.GetSMBCredential(path);
            }

            if (credential == null)
            {
                throw new SMBException($"Failed to EnumerateFileSystemEntries for {path}", new InvalidCredentialException($"Unable to find credential in SMBCredentialProvider for path: {path}"));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying to EnumerateFileSystemEntries {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using (var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize))
                {
                    fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                    status.HandleStatus();

                    status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, AccessMask.GENERIC_READ, 0, ShareAccess.Read,
                                                  CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                    status.HandleStatus();

                    fileStore.QueryDirectory(out List <QueryDirectoryFileInformation> queryDirectoryFileInformation, handle, searchPattern, FileInformationClass.FileDirectoryInformation);

                    _logger?.LogTrace($"Found {queryDirectoryFileInformation.Count} FileDirectoryInformation for {path}");

                    List <string> files = new List <string>();

                    foreach (var file in queryDirectoryFileInformation)
                    {
                        if (file.FileInformationClass == FileInformationClass.FileDirectoryInformation)
                        {
                            FileDirectoryInformation fileDirectoryInformation = (FileDirectoryInformation)file;
                            if (fileDirectoryInformation.FileName == "." || fileDirectoryInformation.FileName == ".." || fileDirectoryInformation.FileName == ".DS_Store")
                            {
                                continue;
                            }


                            if (fileDirectoryInformation.FileAttributes.HasFlag(SMBLibrary.FileAttributes.Directory))
                            {
                                if (searchOption == SearchOption.AllDirectories)
                                {
                                    files.AddRange(EnumerateFileSystemEntries(_fileSystem.Path.Combine(path, fileDirectoryInformation.FileName), searchPattern, searchOption, credential));
                                }
                            }

                            files.Add(_fileSystem.Path.Combine(path, fileDirectoryInformation.FileName));
                        }
                    }

                    return(files);
                }
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed to EnumerateFileSystemEntries for {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 8
0
        private IDirectoryInfo CreateDirectory(string path, ISMBCredential credential)
        {
            if (!path.IsSharePath())
            {
                return(base.CreateDirectory(path));
            }

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed to CreateDirectory {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            if (credential == null)
            {
                credential = _credentialProvider.GetSMBCredential(path);
            }

            if (credential == null)
            {
                throw new SMBException($"Failed to CreateDirectory {path}", new InvalidCredentialException($"Unable to find credential in SMBCredentialProvider for path: {path}"));
            }

            if (Exists(path))
            {
                return(_directoryInfoFactory.FromDirectoryName(path));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying to CreateDirectory {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize);

                fileStore = connection.SMBClient.TreeConnect(shareName, out var status);

                status.HandleStatus();

                AccessMask        accessMask    = AccessMask.SYNCHRONIZE | AccessMask.MAXIMUM_ALLOWED;
                ShareAccess       shareAccess   = ShareAccess.Read | ShareAccess.Write;
                CreateDisposition disposition   = CreateDisposition.FILE_OPEN_IF;
                CreateOptions     createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_DIRECTORY_FILE;

                var stopwatch = new Stopwatch();

                stopwatch.Start();
                do
                {
                    if (status == NTStatus.STATUS_PENDING)
                    {
                        _logger.LogTrace($"STATUS_PENDING while trying to create directory {path}. {stopwatch.Elapsed.TotalSeconds}/{_smbFileSystemSettings.ClientSessionTimeout} seconds elapsed.");
                    }

                    status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, accessMask, 0, shareAccess,
                                                  disposition, createOptions, null);

                    if (status == NTStatus.STATUS_OBJECT_PATH_NOT_FOUND)
                    {
                        CreateDirectory(path.GetParentPath(), credential);
                        status = fileStore.CreateFile(out handle, out fileStatus, relativePath, accessMask, 0, shareAccess,
                                                      disposition, createOptions, null);
                    }
                } while (status == NTStatus.STATUS_PENDING && stopwatch.Elapsed.TotalSeconds <= _smbFileSystemSettings.ClientSessionTimeout);

                stopwatch.Stop();

                status.HandleStatus();

                FileStoreUtilities.CloseFile(fileStore, ref handle);

                return(_directoryInfoFactory.FromDirectoryName(path, credential));
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed to CreateDirectory {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }
Exemplo n.º 9
0
        public void Delete(string path, bool recursive, ISMBCredential credential)
        {
            if (!path.IsSharePath())
            {
                base.Delete(path, recursive);
                return;
            }

            if (recursive)
            {
                if (!path.TryResolveHostnameFromPath(out var ipAddress))
                {
                    throw new SMBException($"Failed to Delete {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
                }

                if (credential == null)
                {
                    credential = _credentialProvider.GetSMBCredential(path);
                }

                if (credential == null)
                {
                    throw new SMBException($"Failed to Delete {path}", new InvalidCredentialException("Unable to find credential in SMBCredentialProvider for path: {path}"));
                }

                ISMBFileStore fileStore = null;
                object        handle    = null;

                try
                {
                    var shareName    = path.ShareName();
                    var relativePath = path.RelativeSharePath();

                    _logger?.LogTrace($"Trying to Delete {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                    using (var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize))
                    {
                        fileStore = connection.SMBClient.TreeConnect(shareName, out var status);

                        status.HandleStatus();

                        AccessMask        accessMask    = AccessMask.SYNCHRONIZE | AccessMask.GENERIC_READ;
                        ShareAccess       shareAccess   = ShareAccess.Delete;
                        CreateDisposition disposition   = CreateDisposition.FILE_OPEN;
                        CreateOptions     createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_DIRECTORY_FILE;

                        var stopwatch = new Stopwatch();

                        stopwatch.Start();
                        do
                        {
                            if (status == NTStatus.STATUS_PENDING)
                            {
                                _logger.LogTrace($"STATUS_PENDING while trying to delete directory {path}. {stopwatch.Elapsed.TotalSeconds}/{_smbFileSystemSettings.ClientSessionTimeout} seconds elapsed.");
                            }

                            status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, accessMask, 0, shareAccess,
                                                          disposition, createOptions, null);
                        } while (status == NTStatus.STATUS_PENDING && stopwatch.Elapsed.TotalSeconds <= _smbFileSystemSettings.ClientSessionTimeout);

                        stopwatch.Stop();

                        status.HandleStatus();

                        fileStore.QueryDirectory(out List <QueryDirectoryFileInformation> queryDirectoryFileInformation, handle, "*", FileInformationClass.FileDirectoryInformation);

                        foreach (var file in queryDirectoryFileInformation)
                        {
                            if (file.FileInformationClass == FileInformationClass.FileDirectoryInformation)
                            {
                                FileDirectoryInformation fileDirectoryInformation = (FileDirectoryInformation)file;
                                if (fileDirectoryInformation.FileName == "." ||
                                    fileDirectoryInformation.FileName == ".." ||
                                    fileDirectoryInformation.FileName == ".DS_Store")
                                {
                                    continue;
                                }
                                else if (fileDirectoryInformation.FileAttributes.HasFlag(SMBLibrary.FileAttributes.Directory))
                                {
                                    Delete(_fileSystem.Path.Combine(path, fileDirectoryInformation.FileName), recursive, credential);
                                }

                                _fileSystem.File.Delete(_fileSystem.Path.Combine(path, fileDirectoryInformation.FileName));
                            }
                        }

                        FileStoreUtilities.CloseFile(fileStore, ref handle);

                        Delete(path, credential);
                    }
                }
                catch (Exception ex)
                {
                    throw new SMBException($"Failed to Delete {path}", ex);
                }
                finally
                {
                    FileStoreUtilities.CloseFile(fileStore, ref handle);
                }
            }
            else
            {
                Delete(path);
            }
        }
Exemplo n.º 10
0
        internal void Delete(string path, ISMBCredential credential)
        {
            if (!path.IsSharePath())
            {
                base.Delete(path);
                return;
            }

            if (!path.TryResolveHostnameFromPath(out var ipAddress))
            {
                throw new SMBException($"Failed to Delete {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\""));
            }

            if (!Exists(path))
            {
                return;
            }

            NTStatus status = NTStatus.STATUS_SUCCESS;

            if (credential == null)
            {
                credential = _credentialProvider.GetSMBCredential(path);
            }

            if (credential == null)
            {
                throw new SMBException($"Failed to Delete {path}", new InvalidCredentialException($"Unable to find credential in SMBCredentialProvider for path: {path}"));
            }

            if (EnumerateFileSystemEntries(path).Count() > 0)
            {
                throw new SMBException($"Failed to Delete {path}", new IOException("Cannot delete directory. Directory is not empty."));
            }

            ISMBFileStore fileStore = null;
            object        handle    = null;

            try
            {
                var shareName    = path.ShareName();
                var relativePath = path.RelativeSharePath();

                _logger?.LogTrace($"Trying to Delete {{RelativePath: {relativePath}}} for {{ShareName: {shareName}}}");

                using (var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize))
                {
                    fileStore = connection.SMBClient.TreeConnect(shareName, out status);

                    status.HandleStatus();

                    AccessMask        accessMask    = AccessMask.SYNCHRONIZE | AccessMask.DELETE;
                    ShareAccess       shareAccess   = ShareAccess.Delete;
                    CreateDisposition disposition   = CreateDisposition.FILE_OPEN;
                    CreateOptions     createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_DELETE_ON_CLOSE;

                    var stopwatch = new Stopwatch();

                    stopwatch.Start();
                    do
                    {
                        if (status == NTStatus.STATUS_PENDING)
                        {
                            _logger.LogTrace($"STATUS_PENDING while trying to delete directory {path}. {stopwatch.Elapsed.TotalSeconds}/{_smbFileSystemSettings.ClientSessionTimeout} seconds elapsed.");
                        }

                        status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, accessMask, 0, shareAccess,
                                                      disposition, createOptions, null);
                    }while (status == NTStatus.STATUS_PENDING && stopwatch.Elapsed.TotalSeconds <= _smbFileSystemSettings.ClientSessionTimeout);
                    stopwatch.Stop();

                    status.HandleStatus();

                    // This is the correct delete command, but it doesn't work for some reason. You have to use FILE_DELETE_ON_CLOSE
                    // fileStore.SetFileInformation(handle, new FileDispositionInformation());

                    FileStoreUtilities.CloseFile(fileStore, ref handle);
                }
            }
            catch (Exception ex)
            {
                throw new SMBException($"Failed to Delete {path}", ex);
            }
            finally
            {
                FileStoreUtilities.CloseFile(fileStore, ref handle);
            }
        }