Пример #1
0
        /// <summary>
        /// Create intersection with another option
        /// </summary>
        /// <param name="option"></param>
        /// <returns>this if <paramref name="option"/> is null or new instance with intersection</returns>
        public virtual AllOptions Intersection(IOption option)
        {
            if (option == null)
            {
                return(this);
            }
            AllOptions result = new AllOptions();

            result.CanBrowse           = this.CanBrowse | option.CanBrowse();
            result.CanGetEntry         = this.CanGetEntry | option.CanGetEntry();
            result.CanObserve          = this.CanObserve | option.CanObserve();
            result.CanOpen             = this.CanOpen | option.CanOpen();
            result.CanRead             = this.CanRead | option.CanRead();
            result.CanWrite            = this.CanWrite | option.CanWrite();
            result.CanCreateFile       = this.CanCreateFile | option.CanCreateFile();
            result.CanDelete           = this.CanDelete | option.CanDelete();
            result.CanSetFileAttribute = this.CanSetFileAttribute | option.CanSetFileAttribute();
            result.CanMount            = this.CanMount | option.CanMount();
            result.CanCreateFile       = this.CanCreateFile | option.CanCreateFile();
            result.CanDelete           = this.CanDelete | option.CanDelete();
            result.CanMove             = this.CanMove | option.CanMove();
            result.CanCreateDirectory  = this.CanCreateDirectory | option.CanCreateDirectory();
            result.CanMount            = this.CanMount | option.CanMount();
            result.CanUnmount          = this.CanUnmount | option.CanUnmount();
            result.CanListMountPoints  = this.CanListMountPoints | option.CanListMountPoints();
            result.SubPath             = this.SubPath ?? option.SubPath();
            return(result);
        }
Пример #2
0
 /// <inheritdoc/>
 public Stream CreateReadStream()
 {
     // Assert enabled
     if (!options.CanOpen() || !options.CanRead())
     {
         throw new NotSupportedException(nameof(CreateReadStream));
     }
     // Open
     return(FileSystem.Open(Entry.Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, token));
 }
Пример #3
0
 /// <summary>
 /// Read options from <paramref name="option"/> and return flattened object.
 /// </summary>
 /// <param name="option"></param>
 /// <returns></returns>
 public virtual void ReadFrom(IOption option)
 {
     this.CanBrowse           = option.CanBrowse();
     this.CanGetEntry         = option.CanGetEntry();
     this.CanObserve          = option.CanObserve();
     this.CanOpen             = option.CanOpen();
     this.CanRead             = option.CanRead();
     this.CanWrite            = option.CanWrite();
     this.CanCreateFile       = option.CanCreateFile();
     this.CanDelete           = option.CanDelete();
     this.CanMove             = option.CanMove();
     this.CanCreateDirectory  = option.CanCreateDirectory();
     this.CanMount            = option.CanMount();
     this.CanUnmount          = option.CanUnmount();
     this.CanListMountPoints  = option.CanListMountPoints();
     this.SubPath             = option.SubPath();
     this.CanSetFileAttribute = option.CanSetFileAttribute();
 }
        /// <summary>
        /// Open a file for reading or writing.
        ///
        /// To GET a file, the combination of <see cref="FileMode.Open"/> and <see cref="FileAccess.Read"/> issues a GET request on <paramref name="uri"/>.
        /// Returns async stream that may not yet have been fully loaded.
        ///
        /// To PUT a file, the combination of <see cref="FileMode.Create"/>, <see cref="FileMode.CreateNew"/> or <see cref="FileMode.Truncate"/>, and <see cref="FileAccess.Write"/> issues a request on <paramref name="uri"/>.
        /// Returns a memory stream that can be written to.
        ///
        /// <paramref name="fileShare"/> is ignored.
        ///
        /// Authentication header can be placed in <paramref name="option"/> as instance of <see cref="AuthenticationHeaderValue"/> wrapped in (for example) <see cref="Token"/> or <see cref="TokenList"/>.
        ///
        /// Other <see cref="HttpHeaders"/> can also placed in <paramref name="option"/>.
        ///
        /// <see cref="CancellationToken"/> can be placed in <paramref name="option"/>.
        /// </summary>
        /// <param name="uri">Relative path to file. Directory separator is "/". Root is without preceding "/", e.g. "dir/file.xml"</param>
        /// <param name="fileMode">determines whether to open or to create the file</param>
        /// <param name="fileAccess">how to access the file, read, write or read and write</param>
        /// <param name="fileShare">how the file will be shared by processes</param>
        /// <param name="option">(optional) Credentials</param>
        /// <returns>open file stream</returns>
        /// <exception cref="FileSystemException">On unexpected IO error</exception>
        /// <exception cref="ArgumentNullException"><paramref name="uri"/> is null</exception>
        /// <exception cref="ArgumentException"><paramref name="uri"/> is an empty string (""), contains only white space, or contains one or more invalid characters</exception>
        /// <exception cref="NotSupportedException">The <see cref="IFileSystem"/> doesn't support opening files</exception>
        /// <exception cref="FileNotFoundException">The file cannot be found, such as when mode is FileMode.Truncate or FileMode.Open, and and the file specified by path does not exist. The file must already exist in these modes.</exception>
        /// <exception cref="DirectoryNotFoundException">The specified path is invalid, such as being on an unmapped drive.</exception>
        /// <exception cref="UnauthorizedAccessException">The access requested is not permitted by the operating system for the specified path, such as when access is Write or ReadWrite and the file or directory is set for read-only access.</exception>
        /// <exception cref="PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="fileMode"/>, <paramref name="fileAccess"/> or <paramref name="fileShare"/> contains an invalid value.</exception>
        /// <exception cref="InvalidOperationException">If <paramref name="uri"/> refers to a non-file device, such as "con:", "com1:", "lpt1:", etc.</exception>
        /// <exception cref="ObjectDisposedException"/>
        /// <exception cref="FileSystemExceptionNoReadAccess">No read access</exception>
        /// <exception cref="FileSystemExceptionNoWriteAccess">No write access</exception>
        /// <exception cref="OperationCanceledException">operation canceled</exception>
        public Stream Open(string uri, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, IOption option = null)
        {
            // Take reference
            var _httpClient = httpClient;

            // Assert not disposed
            if (_httpClient == null || IsDisposing)
            {
                throw new ObjectDisposedException(nameof(HttpFileSystem));
            }

            // Append subpath
            string _subpath = option.SubPath() ?? this.options.SubPath;

            if (_subpath != null)
            {
                uri = _subpath + uri;
            }

            // Cancel token
            CancellationToken cancel = default;

            option.TryGetToken(uri, out cancel);

            try
            {
                // Check canceled
                if (cancel.IsCancellationRequested)
                {
                    throw new OperationCanceledException();
                }
                // GET
                if (fileMode == FileMode.Open && fileAccess == FileAccess.Read)
                {
                    // Assert allowed
                    if (!options.CanOpen || !options.CanRead || !option.CanOpen(true) || !option.CanRead(true))
                    {
                        throw new NotSupportedException(nameof(Open));
                    }

                    // Request object
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
                    // Read token
                    ReadTokenToHeaders(uri, option, request.Headers);
                    // Read authentication token
                    AuthenticationHeaderValue authenticationHeader;
                    if (this.token.TryGetToken(uri, out authenticationHeader) || option.TryGetToken(uri, out authenticationHeader))
                    {
                        request.Headers.Authorization = authenticationHeader;
                    }

                    // Start GET
                    Task <HttpResponseMessage> t = _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
                    // Wait for headers to complete
                    t.Wait(cancel);
                    // Get result object
                    HttpResponseMessage response = t.Result;
                    // Assert ok
                    if (!response.IsSuccessStatusCode)
                    {
                        throw new FileSystemException(this, uri, response.StatusCode.ToString());
                    }

                    // Stream Task
                    Task <Stream> tt = response.Content.ReadAsStreamAsync();
                    // Wait for stream
                    tt.Wait(cancel);
                    // return stream
                    return(tt.Result);
                }
                // PUT
                else if ((fileMode == FileMode.Create || fileMode == FileMode.CreateNew || fileMode == FileMode.OpenOrCreate || fileMode == FileMode.Truncate) && fileAccess == FileAccess.Write)
                {
                    // Assert allowed
                    if ((!options.CanOpen && !options.CanCreateFile && !option.CanOpen(true) && !option.CanCreateFile(true)) || !options.CanWrite || !option.CanWrite(true))
                    {
                        throw new NotSupportedException(nameof(Open));
                    }
                    // Request
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, uri);
                    // Read token
                    ReadTokenToHeaders(uri, option, request.Headers);

                    // Content
                    FileSystemHttpContent httpContent = new FileSystemHttpContent();
                    // Start PUT
                    Task <HttpResponseMessage> responseTask = _httpClient.PutAsync(uri, httpContent, cancel);
                    responseTask.ContinueWith(t => httpContent.Semaphore.Release());
                    // Wait for http-content to start writing content
                    httpContent.Semaphore.Wait(cancel);
                    // Get write stream
                    Stream writeStream = httpContent.Stream;

                    // Got an error on t
                    if (writeStream == null)
                    {
                        // Wait
                        responseTask.Wait(cancel);
                        // Get result object
                        HttpResponseMessage response = responseTask.Result;
                        // Assert ok
                        if (!response.IsSuccessStatusCode)
                        {
                            throw new FileSystemException(this, uri, response.StatusCode.ToString());
                        }
                        // Something went unexpectedly wrong
                        throw new FileSystemException(this, uri, "Operation failed, unknown reason.");
                    }

                    // Wrap write stream
                    Stream wrappedStream = new WriteStream(writeStream, httpContent.tcs, responseTask, this, uri);
                    // Return stream for writing
                    return(wrappedStream);
                }
                // Combination not supported
                else
                {
                    throw new NotSupportedException($"FileMode={fileMode}, FileAccess={fileAccess}");
                }
            }
            catch (AggregateException e)
            {
                Exception _e = e;
                if (e.InnerExceptions.Count == 1)
                {
                    _e = e.InnerExceptions.First();
                }
                throw new FileSystemException(this, uri, _e.Message, _e);
            }
            catch (Exception e) when(e is FileSystemException == false)
            {
                throw new FileSystemException(this, uri, e.Message, e);
            }
        }