예제 #1
0
        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);
            }
        }
예제 #2
0
        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);
        }