public static SMBConnection CreateSMBConnection(ISMBClientFactory smbClientFactory, IPAddress address, SMBTransportType transport, ISMBCredential credential, uint maxBufferSize) { var threadId = Thread.CurrentThread.ManagedThreadId; if (credential == null) { throw new ArgumentNullException(nameof(credential)); } lock (_connectionLock) { if (!instances.ContainsKey(threadId)) { instances.Add(threadId, new Dictionary <IPAddress, SMBConnection>()); } SMBConnection instance = null; if (instances[threadId].ContainsKey(address)) { instance = instances[threadId][address]; if (instance.SMBClient.Connect(instance._address, instance._transport)) { instance._referenceCount += 1; return(instance); } // in case the connection is not connected, dispose it and recreate a new one instance.Dispose(); if (!instances.ContainsKey(threadId)) { instances.Add(threadId, new Dictionary <IPAddress, SMBConnection>()); } } // Create new connection instance = new SMBConnection(smbClientFactory, address, transport, credential, threadId, maxBufferSize); instance.Connect(); instances[threadId].Add(address, instance); return(instance); } }
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); } }
protected override void Dispose(bool disposing) { _fileStore.CloseFile(_fileHandle); _connection.Dispose(); base.Dispose(disposing); }