internal Stream Open(string path, FileMode mode, FileAccess access, FileShare share, FileOptions fileOptions, ISMBCredential credential) { if (!path.TryResolveHostnameFromPath(out var ipAddress)) { throw new SMBException($"Failed to Open {path}", new ArgumentException($"Unable to resolve \"{path.Hostname()}\"")); } NTStatus status = NTStatus.STATUS_SUCCESS; AccessMask accessMask = AccessMask.MAXIMUM_ALLOWED; ShareAccess shareAccess = ShareAccess.None; CreateDisposition disposition = CreateDisposition.FILE_OPEN; CreateOptions createOptions; switch (fileOptions) { case FileOptions.DeleteOnClose: createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_DELETE_ON_CLOSE; break; case FileOptions.RandomAccess: createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_RANDOM_ACCESS; break; case FileOptions.SequentialScan: createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_SEQUENTIAL_ONLY; break; case FileOptions.WriteThrough: createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_WRITE_THROUGH; break; case FileOptions.None: case FileOptions.Encrypted: // These two are not suported unless I am missing something case FileOptions.Asynchronous: // default: createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | CreateOptions.FILE_NON_DIRECTORY_FILE; break; } switch (access) { case FileAccess.Read: accessMask = AccessMask.SYNCHRONIZE | AccessMask.GENERIC_READ; shareAccess = ShareAccess.Read; break; case FileAccess.Write: accessMask = AccessMask.SYNCHRONIZE | AccessMask.GENERIC_WRITE; shareAccess = ShareAccess.Write; break; case FileAccess.ReadWrite: accessMask = AccessMask.SYNCHRONIZE | AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE; shareAccess = ShareAccess.Read | ShareAccess.Write; break; } if (credential == null) { credential = _credentialProvider.GetSMBCredential(path); } if (credential == null) { throw new SMBException($"Failed to Open {path}", new InvalidCredentialException($"Unable to find credential in SMBCredentialProvider for path: {path}")); } SMBConnection connection = null; try { connection = SMBConnection.CreateSMBConnectionForStream(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize); var shareName = path.ShareName(); var relativePath = path.RelativeSharePath(); ISMBFileStore fileStore = connection.SMBClient.TreeConnect(shareName, out status); status.HandleStatus(); switch (mode) { case FileMode.Create: disposition = CreateDisposition.FILE_OVERWRITE_IF; break; case FileMode.CreateNew: disposition = CreateDisposition.FILE_CREATE; break; case FileMode.Open: disposition = CreateDisposition.FILE_OPEN; break; case FileMode.OpenOrCreate: disposition = CreateDisposition.FILE_OPEN_IF; break; } object handle; var stopwatch = new Stopwatch(); stopwatch.Start(); do { if (status == NTStatus.STATUS_PENDING) { _logger.LogTrace($"STATUS_PENDING while trying to open 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(); FileInformation fileInfo; stopwatch.Reset(); stopwatch.Start(); do { status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileStandardInformation); }while (status == NTStatus.STATUS_NETWORK_NAME_DELETED && stopwatch.Elapsed.TotalSeconds <= _smbFileSystemSettings.ClientSessionTimeout); stopwatch.Stop(); status.HandleStatus(); var fileStandardInfo = (FileStandardInformation)fileInfo; Stream s = new SMBStream(fileStore, handle, connection, fileStandardInfo.EndOfFile, _smbFileSystemSettings); if (mode == FileMode.Append) { s.Seek(0, SeekOrigin.End); } return(s); } catch (Exception ex) { // Dispose connection if fail to open stream connection?.Dispose(); throw new SMBException($"Failed to Open {path}", ex); } }
internal Stream Open(string path, FileMode mode, FileAccess access, FileShare share, FileOptions fileOptions, ISMBCredential credential) { if (!path.TryResolveHostnameFromPath(out var ipAddress)) { throw new ArgumentException($"Unable to resolve \"{path.Hostname()}\""); } NTStatus status = NTStatus.STATUS_SUCCESS; AccessMask accessMask = AccessMask.MAXIMUM_ALLOWED; ShareAccess shareAccess = ShareAccess.None; CreateDisposition disposition = CreateDisposition.FILE_OPEN; CreateOptions createOptions; switch (fileOptions) { case FileOptions.DeleteOnClose: createOptions = CreateOptions.FILE_DELETE_ON_CLOSE; break; case FileOptions.RandomAccess: createOptions = CreateOptions.FILE_RANDOM_ACCESS; break; case FileOptions.SequentialScan: createOptions = CreateOptions.FILE_SEQUENTIAL_ONLY; break; case FileOptions.WriteThrough: createOptions = CreateOptions.FILE_WRITE_THROUGH; break; case FileOptions.None: case FileOptions.Encrypted: // These two are not suported unless I am missing something case FileOptions.Asynchronous: // default: createOptions = CreateOptions.FILE_NON_DIRECTORY_FILE; break; } switch (access) { case FileAccess.Read: accessMask = AccessMask.GENERIC_READ; shareAccess = ShareAccess.Read; break; case FileAccess.Write: accessMask = AccessMask.GENERIC_WRITE; shareAccess = ShareAccess.Write; break; case FileAccess.ReadWrite: accessMask = AccessMask.GENERIC_ALL; shareAccess = ShareAccess.Write; break; } if (credential == null) { credential = _credentialProvider.GetSMBCredential(path); } if (credential == null) { throw new Exception($"Unable to find credential for path: {path}"); } var connection = SMBConnection.CreateSMBConnection(_smbClientFactory, ipAddress, transport, credential, _maxBufferSize); var shareName = path.ShareName(); var relativePath = path.RelativeSharePath(); ISMBFileStore fileStore = connection.SMBClient.TreeConnect(shareName, out status); status.HandleStatus(); switch (mode) { case FileMode.Create: disposition = CreateDisposition.FILE_CREATE; break; case FileMode.CreateNew: disposition = CreateDisposition.FILE_OVERWRITE; break; case FileMode.Open: disposition = CreateDisposition.FILE_OPEN; break; case FileMode.OpenOrCreate: disposition = Exists(path) ? CreateDisposition.FILE_OPEN : CreateDisposition.FILE_CREATE; break; } int getInfoAttempts = 0; int getInfoAllowedRetrys = 5; object handle; FileInformation fileInfo; do { getInfoAttempts++; int openAttempts = 0; int openAllowedRetrys = 5; do { openAttempts++; status = fileStore.CreateFile(out handle, out FileStatus fileStatus, relativePath, accessMask, 0, shareAccess, disposition, createOptions, null); }while (status == NTStatus.STATUS_PENDING && openAttempts < openAllowedRetrys); status.HandleStatus(); status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileStandardInformation); }while (status == NTStatus.STATUS_NETWORK_NAME_DELETED && getInfoAttempts < getInfoAllowedRetrys); status.HandleStatus(); var fileStandardInfo = (FileStandardInformation)fileInfo; Stream s = new SMBStream(fileStore, handle, connection, fileStandardInfo.EndOfFile); if (mode == FileMode.Append) { s.Seek(0, SeekOrigin.End); } return(s); }