/// <summary>
        /// Function to copy the contents of a file system to the writable area.
        /// </summary>
        /// <param name="sourceFileSystem">The <see cref="IGorgonFileSystem"/> to copy.</param>
        /// <param name="copyProgress">A method callback used to track the progress of the copy operation.</param>
        /// <param name="allowOverwrite">[Optional] <b>true</b> to allow overwriting of files that already exist in the file system with the same path, <b>false</b> to throw an exception when a file with the same path is encountered.</param>
        /// <returns>A <see cref="ValueTuple{T1,T2}"/> containing the number of directories (<c>item1</c>) and the number of files (<c>item2</c>) copied, or <b>null</b> if the operation was cancelled.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="sourceFileSystem"/> parameter is <b>null</b>.</exception>
        /// <exception cref="IOException">Thrown when the a file exists in <see cref="IGorgonFileSystemWriter{T}.FileSystem"/>, and the <paramref name="allowOverwrite"/> parameter is set to <b>false</b>.</exception>
        /// <remarks>
        /// <para>
        /// This copies all the file and directory information from one file system, into the <see cref="IGorgonFileSystemWriter{T}.FileSystem"/> linked to this writer.
        /// </para>
        /// <para>
        /// When the <paramref name="allowOverwrite"/> is set to <b>false</b>, and a <see cref="IGorgonVirtualFile"/> already exists with the same path as another <see cref="IGorgonVirtualFile"/> in the
        /// <paramref name="sourceFileSystem"/>, then an exception will be raised.
        /// </para>
        /// </remarks>
        public (int DirectoryCount, int FileCount)? CopyFrom(IGorgonFileSystem sourceFileSystem, Func <GorgonWriterCopyProgress, bool> copyProgress = null, bool allowOverwrite = true)
        {
            if (sourceFileSystem == null)
            {
                throw new ArgumentNullException(nameof(sourceFileSystem));
            }

            IGorgonVirtualFile[]      files       = sourceFileSystem.FindFiles("/", "*").ToArray();
            IGorgonVirtualDirectory[] directories = sourceFileSystem.FindDirectories("/", "*").ToArray();

            return((files.Length == 0) && (directories.Length == 0)
                ? ((int DirectoryCount, int FileCount)?)(0, 0)
                       : CopyInternal(copyProgress, allowOverwrite, files, directories, CancellationToken.None));
        }
        /// <summary>
        /// Function to asynchronously copy the contents of a file system to the writable area.
        /// </summary>
        /// <param name="sourceFileSystem">The <see cref="IGorgonFileSystem"/> to copy.</param>
        /// <param name="cancelToken">The <see cref="CancellationToken"/> used to cancel an in progress copy.</param>
        /// <param name="copyProgress">A method callback used to track the progress of the copy operation.</param>
        /// <param name="allowOverwrite">[Optional] <b>true</b> to allow overwriting of files that already exist in the file system with the same path, <b>false</b> to throw an exception when a file with the same path is encountered.</param>
        /// <returns>A <see cref="ValueTuple{T1,T2}"/> containing the number of directories (<c>item1</c>) and the number of files (<c>item2</c>) copied, or <b>null</b> if the operation was cancelled.</returns>
        /// <remarks>
        /// <para>
        /// This copies all the file and directory information from one file system, into the <see cref="IGorgonFileSystemWriter{T}.FileSystem"/> linked to this writer.
        /// </para>
        /// <para>
        /// When the <paramref name="allowOverwrite"/> is set to <b>false</b>, and a <see cref="IGorgonVirtualFile"/> already exists with the same path as another <see cref="IGorgonVirtualFile"/> in the
        /// <paramref name="sourceFileSystem"/>, then an exception will be raised.
        /// </para>
        /// <para>
        /// This version of the copy method allows for an asynchronous copy of a set of a files and directories from another <see cref="IGorgonFileSystem"/>. This method should be used when there is a large
        /// amount of data to transfer between the file systems.
        /// </para>
        /// <para>
        /// Unlike the <see cref="IGorgonFileSystemWriter{T}.CopyFrom"/> method, this method will report the progress of the copy through the <paramref name="copyProgress"/> callback. This callback is a method that takes a
        /// <see cref="GorgonWriterCopyProgress"/> value as a parameter that will report the current state, and will return a <see cref="bool"/> to indicate whether to continue the copy or not (<b>true</b> to
        /// continue, <b>false</b> to stop).
        /// </para>
        /// <para>
        /// <note type="warning">
        /// <para>
        /// The <paramref name="copyProgress"/> method does not switch back to the UI context. Ensure that you invoke any operations that update a UI on the appropriate thread (e.g <c>BeginInvoke</c> on a
        /// WinForms UI element or <c>Dispatcher</c> on a WPF element).
        /// </para>
        /// </note>
        /// </para>
        /// <para>
        /// This method also allows for cancellation of the copy operation by passing a <see cref="CancellationToken"/> to the <paramref name="cancelToken"/> parameter.
        /// </para>
        /// </remarks>
        public async Task <(int DirectoryCount, int FileCount)?> CopyFromAsync(IGorgonFileSystem sourceFileSystem, CancellationToken cancelToken, Func <GorgonWriterCopyProgress, bool> copyProgress = null, bool allowOverwrite = true)
        {
            if (sourceFileSystem == null)
            {
                throw new ArgumentNullException(nameof(sourceFileSystem));
            }

            // ReSharper disable MethodSupportsCancellation
            (IGorgonVirtualFile[] Files, IGorgonVirtualDirectory[] Directories) = await Task.Run(() =>
            {
                IGorgonVirtualFile[] files            = sourceFileSystem.FindFiles("/", "*").ToArray();
                IGorgonVirtualDirectory[] directories = sourceFileSystem.FindDirectories("/", "*").ToArray();

                return(Files : files, Directories : directories);
            }).ConfigureAwait(false);

            return((Files.Length == 0) && (Directories.Length == 0)
                ? ((int DirectoryCount, int FileCount)?)(0, 0)
                       : await Task.Run(() => CopyInternal(copyProgress, allowOverwrite, Files, Directories, cancelToken), cancelToken).ConfigureAwait(false));

            // ReSharper restore MethodSupportsCancellation
        }
예제 #3
0
        /// <summary>
        /// Function to copy data from a file system to the file system linked to this writer.
        /// </summary>
        /// <param name="sourceFileSystem">The file system to copy from.</param>
        /// <param name="progress">The callback for copy progress.</param>
        /// <param name="allowOverwrite">Flag to indicate whether to allow overwriting files or not.</param>
        /// <param name="token">The cancellation token for asynchronous copy.</param>
        /// <returns>A tuple containing the count of the directories and files copied.</returns>
        private (int DirectoryCount, int FileCount)? CopyInternal(IGorgonFileSystem sourceFileSystem,
                                                                  Func <GorgonWriterCopyProgress, bool> progress,
                                                                  bool allowOverwrite,
                                                                  CancellationToken token)
        {
            int directoryCount = 0;
            int fileCount      = 0;

            // Enumerate files and directories from the source.
            IGorgonVirtualFile[]      files       = sourceFileSystem.FindFiles("/", "*").ToArray();
            IGorgonVirtualDirectory[] directories = sourceFileSystem.FindDirectories("/", "*").ToArray();

            if ((files.Length == 0) && (directories.Length == 0))
            {
                return(0, 0);
            }

            // Create all the directories.
            foreach (IGorgonVirtualDirectory directory in directories)
            {
                if (token.IsCancellationRequested)
                {
                    return(null);
                }

                CreateDirectory(directory.FullPath);
                ++directoryCount;
            }

            foreach (IGorgonVirtualFile file in files)
            {
                IGorgonVirtualFile destFile = FileSystem.GetFile(file.FullPath);

                if (token.IsCancellationRequested)
                {
                    return(null);
                }

                // Do not allow overwrite if the user requested it.
                if ((destFile != null) && (!allowOverwrite))
                {
                    throw new IOException(string.Format(Resources.GORFS_ERR_FILE_EXISTS, destFile.FullPath));
                }

                // Copy the file.
                using (Stream sourceStream = file.OpenStream())
                {
                    using (Stream destStream = OpenStream(file.FullPath, FileMode.Create))
                    {
                        sourceStream.CopyTo(destStream, 80000);
                    }
                }

                ++fileCount;

                if (progress == null)
                {
                    continue;
                }

                if (!progress(new GorgonWriterCopyProgress(file, fileCount, files.Length, directories.Length)))
                {
                    return(null);
                }
            }

            return(directoryCount, fileCount);
        }