Exemple #1
0
        /// <summary>
        /// Delete the extra remote files if in mirror mode and the directory was pre-existing
        /// </summary>
        private async Task DeleteExtraServerFilesAsync(FtpFolderSyncMode mode, Dictionary <string, bool> shouldExist, FtpListItem[] remoteListing, CancellationToken token)
        {
            if (mode == FtpFolderSyncMode.Mirror && remoteListing != null)
            {
                LogFunc(nameof(DeleteExtraServerFilesAsync));

                // delete files that are not in listed in shouldExist
                foreach (var existingServerFile in remoteListing)
                {
                    if (existingServerFile.Type == FtpFileSystemObjectType.File)
                    {
                        if (!shouldExist.ContainsKey(existingServerFile.FullName.ToLower()))
                        {
                            LogStatus(FtpTraceLevel.Info, "Delete extra file from server: " + existingServerFile.FullName);

                            // delete the file from the server
                            try {
                                await DeleteFileAsync(existingServerFile.FullName, token);
                            }
                            catch (Exception ex) { }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Delete the extra local files if in mirror mode
        /// </summary>
        private void DeleteExtraLocalFiles(string localFolder, FtpFolderSyncMode mode, Dictionary <string, bool> shouldExist)
        {
            if (mode == FtpFolderSyncMode.Mirror)
            {
                LogFunc("DeleteExtraLocalFiles");

                // get all the local files
                var localListing = Directory.GetFiles(localFolder, "*.*", SearchOption.AllDirectories);

                // delete files that are not in listed in shouldExist
                foreach (var existingLocalFile in localListing)
                {
                    if (!shouldExist.ContainsKey(existingLocalFile.ToLower()))
                    {
                        LogStatus(FtpTraceLevel.Info, "Delete extra file from disk: " + existingLocalFile);

                        // delete the file from disk
                        try {
                            File.Delete(existingLocalFile);
                        }
                        catch (Exception ex) { }
                    }
                }
            }
        }
        /// <summary>
        /// Delete the extra remote files if in mirror mode and the directory was pre-existing
        /// </summary>
        private void DeleteExtraServerFiles(FtpFolderSyncMode mode, string remoteFolder, Dictionary <string, bool> shouldExist, FtpListItem[] remoteListing, List <FtpRule> rules)
        {
            if (mode == FtpFolderSyncMode.Mirror && remoteListing != null)
            {
                LogFunc(nameof(DeleteExtraServerFiles));

                // delete files that are not in listed in shouldExist
                foreach (var existingServerFile in remoteListing)
                {
                    if (existingServerFile.Type == FtpFileSystemObjectType.File)
                    {
                        if (!shouldExist.ContainsKey(existingServerFile.FullName.ToLower()))
                        {
                            // only delete the remote file if its permitted by the configuration
                            if (CanDeleteRemoteFile(rules, existingServerFile))
                            {
                                LogStatus(FtpTraceLevel.Info, "Delete extra file from server: " + existingServerFile.FullName);

                                // delete the file from the server
                                try {
                                    DeleteFile(existingServerFile.FullName);
                                }
                                catch (Exception ex) { }
                            }
                        }
                    }
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Transfer the specified directory from the source FTP Server onto the remote FTP Server using the FXP protocol.
        /// You will need to create a valid connection to your remote FTP Server before calling this method.
        /// In Update mode, we will only transfer missing files and preserve any extra files on the remote FTP Server. This is useful when you want to simply transfer missing files from an FTP directory.
        /// Currently Mirror mode is not implemented.
        /// Only transfers the files and folders matching all the rules provided, if any.
        /// All exceptions during transfer are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="sourceFolder">The full or relative path to the folder on the source FTP Server. If it does not exist, an empty result list is returned.</param>
        /// <param name="remoteClient">Valid FTP connection to the destination FTP Server</param>
        /// <param name="remoteFolder">The full or relative path to destination folder on the remote FTP Server</param>
        /// <param name="mode">Only Update mode is currently implemented</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the download or restart the download?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful download and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide a callback to track download progress.</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public List <FtpResult> TransferDirectory(string sourceFolder, FtpClient remoteClient, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update,
                                                  FtpRemoteExists existsMode = FtpRemoteExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, Action <FtpProgress> progress = null)
        {
            if (sourceFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "sourceFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            LogFunc(nameof(TransferDirectory), new object[] { sourceFolder, remoteClient, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // cleanup the FTP paths
            sourceFolder = sourceFolder.GetFtpPath().EnsurePostfix("/");
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            // if the source dir does not exist, fail fast
            if (!DirectoryExists(sourceFolder))
            {
                return(results);
            }

            // flag to determine if existence checks are required
            var checkFileExistence = true;

            // ensure the remote dir exists
            if (!remoteClient.DirectoryExists(remoteFolder))
            {
                remoteClient.CreateDirectory(remoteFolder);
                checkFileExistence = false;
            }

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // get all the folders in the local directory
            var dirListing = GetListing(sourceFolder, FtpListOption.Recursive).Where(x => x.Type == FtpFileSystemObjectType.Directory).Select(x => x.FullName).ToArray();

            // get all the already existing files
            var remoteListing = checkFileExistence ? remoteClient.GetListing(remoteFolder, FtpListOption.Recursive) : null;

            // loop thru each folder and ensure it exists
            var dirsToUpload = GetSubDirectoriesToTransfer(sourceFolder, remoteFolder, rules, results, dirListing);

            CreateSubDirectories(remoteClient, dirsToUpload);

            // get all the files in the local directory
            var fileListing = GetListing(sourceFolder, FtpListOption.Recursive).Where(x => x.Type == FtpFileSystemObjectType.File).Select(x => x.FullName).ToArray();

            // loop thru each file and transfer it
            var filesToUpload = GetFilesToTransfer(sourceFolder, remoteFolder, rules, results, shouldExist, fileListing);

            TransferServerFiles(filesToUpload, remoteClient, existsMode, verifyOptions, progress, remoteListing);

            // delete the extra remote files if in mirror mode and the directory was pre-existing
            // DeleteExtraServerFiles(mode, shouldExist, remoteListing);

            return(results);
        }
        /// <summary>
        /// Uploads the specified directory onto the server.
        /// In Mirror mode, we will upload missing files, and delete any extra files from the server that are not present on disk. This is very useful when publishing an exact copy of a local folder onto an FTP server.
        /// In Update mode, we will only upload missing files and preserve any extra files on the server. This is useful when you want to simply upload missing files to a server.
        /// Only uploads the files and folders matching all the rules provided, if any.
        /// All exceptions during uploading are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="localFolder">The full path of the local folder on disk that you want to upload. If it does not exist, an empty result list is returned.</param>
        /// <param name="remoteFolder">The full path of the remote FTP folder to upload into. It is created if it does not exist.</param>
        /// <param name="mode">Mirror or Update mode, as explained above</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the upload or restart the upload?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful upload and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide a callback to track upload progress.</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public List <FtpResult> UploadDirectory(string localFolder, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update, FtpRemoteExists existsMode = FtpRemoteExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, Action <FtpProgress> progress = null)
        {
            if (localFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "localFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            LogFunc("UploadDirectory", new object[] { localFolder, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // ensure the local path ends with slash
            localFolder = localFolder.EnsurePostfix(Path.DirectorySeparatorChar.ToString());

            // cleanup the remote path
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            // if the dir does not exist, fail fast
            if (!Directory.Exists(localFolder))
            {
                return(results);
            }

            // ensure the remote dir exists
            if (!DirectoryExists(remoteFolder))
            {
                CreateDirectory(remoteFolder);
            }

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // get all the folders in the local directory
            var dirListing = Directory.GetDirectories(localFolder, "*.*", SearchOption.AllDirectories);

            // loop thru each folder and ensure it exists
            foreach (var localFile in dirListing)
            {
                // calculate the local path
                var relativePath = localFile.Replace(localFolder, "").EnsurePostfix(Path.DirectorySeparatorChar.ToString());
                var remoteFile   = remoteFolder + relativePath.Replace('\\', '/');

                // create the result object
                var result = new FtpResult()
                {
                    Type       = FtpFileSystemObjectType.Directory,
                    Size       = 0,
                    Name       = Path.GetDirectoryName(localFile),
                    RemotePath = remoteFile,
                    LocalPath  = localFile
                };

                // record the folder
                results.Add(result);

                // if the folder passes all rules
                if (rules != null && rules.Count > 0)
                {
                    var passes = FtpRule.IsAllAllowed(rules, result.ToListItem(true));
                    if (!passes)
                    {
                        // mark that the file was skipped due to a rule
                        result.IsSkipped       = true;
                        result.IsSkippedByRule = true;

                        // skip uploading the file
                        continue;
                    }
                }

                // absorb errors
                try {
                    // create directory on the server
                    // to ensure we upload the blank remote dirs as well
                    if (!DirectoryExists(remoteFile))
                    {
                        CreateDirectory(remoteFile);
                        result.IsSuccess = true;
                        result.IsSkipped = false;
                    }
                    else
                    {
                        result.IsSkipped = true;
                    }
                }
                catch (Exception ex) {
                    // mark that the folder failed to upload
                    result.IsFailed  = true;
                    result.Exception = ex;
                }
            }

            // get all the files in the local directory
            var fileListing = Directory.GetFiles(localFolder, "*.*", SearchOption.AllDirectories);

            // loop thru each file and transfer it
            foreach (var localFile in fileListing)
            {
                // calculate the local path
                var relativePath = localFile.Replace(localFolder, "");
                var remoteFile   = remoteFolder + relativePath.Replace('\\', '/');

                // create the result object
                var result = new FtpResult()
                {
                    Type       = FtpFileSystemObjectType.File,
                    Size       = new FileInfo(localFile).Length,
                    Name       = Path.GetFileName(localFile),
                    RemotePath = remoteFile,
                    LocalPath  = localFile
                };

                // record the file
                results.Add(result);

                // if the file passes all rules
                if (rules != null && rules.Count > 0)
                {
                    var passes = FtpRule.IsAllAllowed(rules, result.ToListItem(true));
                    if (!passes)
                    {
                        // mark that the file was skipped due to a rule
                        result.IsSkipped       = true;
                        result.IsSkippedByRule = true;

                        // skip uploading the file
                        continue;
                    }
                }

                // record that this file should exist
                shouldExist.Add(remoteFile.ToLower(), true);

                // absorb errors
                try {
                    // upload the file
                    var transferred = this.UploadFile(result.LocalPath, result.RemotePath, existsMode, false, verifyOptions, progress);
                    result.IsSuccess = true;
                    result.IsSkipped = !transferred;
                }
                catch (Exception ex) {
                    // mark that the file failed to upload
                    result.IsFailed  = true;
                    result.Exception = ex;
                }
            }

            // delete the extra remote files if in mirror mode
            if (mode == FtpFolderSyncMode.Mirror)
            {
                // get all the files on the server
                var remoteListing = GetListing(remoteFolder, FtpListOption.Recursive);

                // delete files that are not in listed in shouldExist
                foreach (var existingServerFile in remoteListing)
                {
                    if (existingServerFile.Type == FtpFileSystemObjectType.File)
                    {
                        if (!shouldExist.ContainsKey(existingServerFile.FullName.ToLower()))
                        {
                            // delete the file from the server
                            try {
                                DeleteFile(existingServerFile.FullName);
                            }
                            catch (Exception ex) { }
                        }
                    }
                }
            }

            return(results);
        }
        /// <summary>
        /// Downloads the specified directory onto the local file system.
        /// In Mirror mode, we will download missing files, and delete any extra files from disk that are not present on the server. This is very useful when creating an exact local backup of an FTP directory.
        /// In Update mode, we will only download missing files and preserve any extra files on disk. This is useful when you want to simply download missing files from an FTP directory.
        /// Only downloads the files and folders matching all the rules provided, if any.
        /// All exceptions during downloading are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="localFolder">The full path of the local folder on disk to download into. It is created if it does not exist.</param>
        /// <param name="remoteFolder">The full path of the remote FTP folder that you want to download. If it does not exist, an empty result list is returned.</param>
        /// <param name="mode">Mirror or Update mode, as explained above</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the download or restart the download?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful download and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide a callback to track download progress.</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public List <FtpResult> DownloadDirectory(string localFolder, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update,
                                                  FtpLocalExists existsMode = FtpLocalExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, Action <FtpProgress> progress = null)
        {
            if (localFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "localFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            LogFunc("DownloadDirectory", new object[] { localFolder, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // ensure the local path ends with slash
            localFolder = localFolder.EnsurePostfix(Path.DirectorySeparatorChar.ToString());

            // cleanup the remote path
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            // if the dir does not exist, fail fast
            if (!DirectoryExists(remoteFolder))
            {
                return(results);
            }

            // ensure the local dir exists
            localFolder.EnsureDirectory();

            // get all the files in the remote directory
            var listing = GetListing(remoteFolder, FtpListOption.Recursive | FtpListOption.Size);

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // loop thru each file and transfer it
            var toDownload = GetFilesToDownload(localFolder, remoteFolder, rules, results, listing, shouldExist);

            DownloadServerFiles(toDownload, existsMode, verifyOptions, progress);

            // delete the extra local files if in mirror mode
            DeleteExtraLocalFiles(localFolder, mode, shouldExist);

            return(results);
        }
        /// <summary>
        /// Transfer the specified directory from the source FTP Server onto the remote FTP Server asynchronously using the FXP protocol.
        /// You will need to create a valid connection to your remote FTP Server before calling this method.
        /// In Update mode, we will only transfer missing files and preserve any extra files on the remote FTP Server. This is useful when you want to simply transfer missing files from an FTP directory.
        /// Currently Mirror mode is not implemented.
        /// Only transfers the files and folders matching all the rules provided, if any.
        /// All exceptions during transfer are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="sourceFolder">The full or relative path to the folder on the source FTP Server. If it does not exist, an empty result list is returned.</param>
        /// <param name="remoteClient">Valid FTP connection to the destination FTP Server</param>
        /// <param name="remoteFolder">The full or relative path to destination folder on the remote FTP Server</param>
        /// <param name="mode">Only Update mode is currently implemented</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the download or restart the download?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful download and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide a callback to track download progress.</param>
        /// <param name="token">The token that can be used to cancel the entire process</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public async Task <List <FtpResult> > TransferDirectoryAsync(string sourceFolder, FtpClient remoteClient, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update,
                                                                     FtpRemoteExists existsMode = FtpRemoteExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, IProgress <FtpProgress> progress = null, CancellationToken token = default(CancellationToken))
        {
            if (sourceFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "sourceFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            LogFunc(nameof(TransferDirectoryAsync), new object[] { sourceFolder, remoteClient, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // cleanup the FTP paths
            sourceFolder = sourceFolder.GetFtpPath().EnsurePostfix("/");
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            // if the source dir does not exist, fail fast
            if (!await DirectoryExistsAsync(sourceFolder, token))
            {
                return(results);
            }

            // flag to determine if existence checks are required
            var checkFileExistence = true;

            // ensure the remote dir exists
            if (!await remoteClient.DirectoryExistsAsync(remoteFolder, token))
            {
                await remoteClient.CreateDirectoryAsync(remoteFolder, token);

                checkFileExistence = false;
            }

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // get all the folders in the local directory
            var dirListing = (await GetListingAsync(sourceFolder, FtpListOption.Recursive, token)).Where(x => x.Type == FtpFileSystemObjectType.Directory).Select(x => x.FullName).ToArray();

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // get all the already existing files
            var remoteListing = checkFileExistence ? await remoteClient.GetListingAsync(remoteFolder, FtpListOption.Recursive, token) : null;

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // loop thru each folder and ensure it exists #1
            var dirsToUpload = GetSubDirectoriesToTransfer(sourceFolder, remoteFolder, rules, results, dirListing);

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            /*-------------------------------------------------------------------------------------/
            *   Cancelling after this point would leave the FTP server in an inconsistant state   *
            *-------------------------------------------------------------------------------------*/

            // loop thru each folder and ensure it exists #2
            await CreateSubDirectoriesAsync(remoteClient, dirsToUpload, token);

            // get all the files in the local directory
            var fileListing = (await GetListingAsync(sourceFolder, FtpListOption.Recursive, token)).Where(x => x.Type == FtpFileSystemObjectType.File).Select(x => x.FullName).ToArray();

            // loop thru each file and transfer it
            var filesToUpload = GetFilesToTransfer(sourceFolder, remoteFolder, rules, results, shouldExist, fileListing);

            await TransferServerFilesAsync(filesToUpload, remoteClient, existsMode, verifyOptions, progress, remoteListing, token);

            // delete the extra remote files if in mirror mode and the directory was pre-existing
            // DeleteExtraServerFiles(mode, shouldExist, remoteListing);

            return(results);
        }
        /// <summary>
        /// Downloads the specified directory onto the local file system.
        /// In Mirror mode, we will download missing files, and delete any extra files from disk that are not present on the server. This is very useful when creating an exact local backup of an FTP directory.
        /// In Update mode, we will only download missing files and preserve any extra files on disk. This is useful when you want to simply download missing files from an FTP directory.
        /// Only downloads the files and folders matching all the rules provided, if any.
        /// All exceptions during downloading are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="localFolder">The full path of the local folder on disk to download into. It is created if it does not exist.</param>
        /// <param name="remoteFolder">The full path of the remote FTP folder that you want to download. If it does not exist, an empty result list is returned.</param>
        /// <param name="mode">Mirror or Update mode, as explained above</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the download or restart the download?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful download and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide an implementation of IProgress to track upload progress.</param>
        /// <param name="token">The token that can be used to cancel the entire process</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public async Task <List <FtpResult> > DownloadDirectoryAsync(string localFolder, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update,
                                                                     FtpLocalExists existsMode = FtpLocalExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, IProgress <FtpProgress> progress = null, CancellationToken token = default(CancellationToken))
        {
            if (localFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "localFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            // ensure the local path ends with slash
            localFolder = localFolder.EnsurePostfix(Path.DirectorySeparatorChar.ToString());

            // cleanup the remote path
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            LogFunc(nameof(DownloadDirectoryAsync), new object[] { localFolder, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // if the dir does not exist, fail fast
            if (!await DirectoryExistsAsync(remoteFolder, token))
            {
                return(results);
            }

            // ensure the local dir exists
            localFolder.EnsureDirectory();

            // get all the files in the remote directory
            var listing = await GetListingAsync(remoteFolder, FtpListOption.Recursive | FtpListOption.Size, token);

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // loop thru each file and transfer it #1
            var toDownload = GetFilesToDownload(localFolder, remoteFolder, rules, results, listing, shouldExist);

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            /*-------------------------------------------------------------------------------------/
            *   Cancelling after this point would leave the FTP server in an inconsistant state   *
            *-------------------------------------------------------------------------------------*/

            // loop thru each file and transfer it #2
            await DownloadServerFilesAsync(toDownload, existsMode, verifyOptions, progress, token);

            // delete the extra local files if in mirror mode
            DeleteExtraLocalFiles(localFolder, mode, shouldExist, rules);

            return(results);
        }
Exemple #9
0
        /// <summary>
        /// Uploads the specified directory onto the server.
        /// In Mirror mode, we will upload missing files, and delete any extra files from the server that are not present on disk. This is very useful when publishing an exact copy of a local folder onto an FTP server.
        /// In Update mode, we will only upload missing files and preserve any extra files on the server. This is useful when you want to simply upload missing files to a server.
        /// Only uploads the files and folders matching all the rules provided, if any.
        /// All exceptions during uploading are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="localFolder">The full path of the local folder on disk that you want to upload. If it does not exist, an empty result list is returned.</param>
        /// <param name="remoteFolder">The full path of the remote FTP folder to upload into. It is created if it does not exist.</param>
        /// <param name="mode">Mirror or Update mode, as explained above</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the upload or restart the upload?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful upload and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide a callback to track upload progress.</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public List <FtpResult> UploadDirectory(string localFolder, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update,
                                                FtpRemoteExists existsMode = FtpRemoteExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, Action <FtpProgress> progress = null)
        {
            if (localFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "localFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            LogFunc(nameof(UploadDirectory), new object[] { localFolder, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // ensure the local path ends with slash
            localFolder = localFolder.EnsurePostfix(Path.DirectorySeparatorChar.ToString());

            // cleanup the remote path
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            // if the dir does not exist, fail fast
            if (!Directory.Exists(localFolder))
            {
                return(results);
            }

            // flag to determine if existence checks are required
            var checkFileExistence = true;

            // ensure the remote dir exists
            if (!DirectoryExists(remoteFolder))
            {
                CreateDirectory(remoteFolder);
                checkFileExistence = false;
            }

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // get all the folders in the local directory
            var dirListing = Directory.GetDirectories(localFolder, "*.*", SearchOption.AllDirectories);

            // get all the already existing files
            var remoteListing = checkFileExistence ? GetListing(remoteFolder, FtpListOption.Recursive) : null;

            // loop thru each folder and ensure it exists
            var dirsToUpload = GetSubDirectoriesToUpload(localFolder, remoteFolder, rules, results, dirListing);

            CreateSubDirectories(this, dirsToUpload);

            // get all the files in the local directory
            var fileListing = Directory.GetFiles(localFolder, "*.*", SearchOption.AllDirectories);

            // loop thru each file and transfer it
            var filesToUpload = GetFilesToUpload(localFolder, remoteFolder, rules, results, shouldExist, fileListing);

            UploadDirectoryFiles(filesToUpload, existsMode, verifyOptions, progress, remoteListing);

            // delete the extra remote files if in mirror mode and the directory was pre-existing
            DeleteExtraServerFiles(mode, shouldExist, remoteListing);

            return(results);
        }
        /// <summary>
        /// Uploads the specified directory onto the server.
        /// In Mirror mode, we will upload missing files, and delete any extra files from the server that are not present on disk. This is very useful when publishing an exact copy of a local folder onto an FTP server.
        /// In Update mode, we will only upload missing files and preserve any extra files on the server. This is useful when you want to simply upload missing files to a server.
        /// Only uploads the files and folders matching all the rules provided, if any.
        /// All exceptions during uploading are caught, and the exception is stored in the related FtpResult object.
        /// </summary>
        /// <param name="localFolder">The full path of the local folder on disk that you want to upload. If it does not exist, an empty result list is returned.</param>
        /// <param name="remoteFolder">The full path of the remote FTP folder to upload into. It is created if it does not exist.</param>
        /// <param name="mode">Mirror or Update mode, as explained above</param>
        /// <param name="existsMode">If the file exists on disk, should we skip it, resume the upload or restart the upload?</param>
        /// <param name="verifyOptions">Sets if checksum verification is required for a successful upload and what to do if it fails verification (See Remarks)</param>
        /// <param name="rules">Only files and folders that pass all these rules are downloaded, and the files that don't pass are skipped. In the Mirror mode, the files that fail the rules are also deleted from the local folder.</param>
        /// <param name="progress">Provide an implementation of IProgress to track upload progress.</param>
        /// <param name="token">The token that can be used to cancel the entire process</param>
        /// <remarks>
        /// If verification is enabled (All options other than <see cref="FtpVerify.None"/>) the hash will be checked against the server.  If the server does not support
        /// any hash algorithm, then verification is ignored.  If only <see cref="FtpVerify.OnlyChecksum"/> is set then the return of this method depends on both a successful
        /// upload &amp; verification.  Additionally, if any verify option is set and a retry is attempted then overwrite will automatically switch to true for subsequent attempts.
        /// If <see cref="FtpVerify.Throw"/> is set and <see cref="FtpError.Throw"/> is <i>not set</i>, then individual verification errors will not cause an exception
        /// to propagate from this method.
        /// </remarks>
        /// <returns>
        /// Returns a listing of all the remote files, indicating if they were downloaded, skipped or overwritten.
        /// Returns a blank list if nothing was transfered. Never returns null.
        /// </returns>
        public async Task <List <FtpResult> > UploadDirectoryAsync(string localFolder, string remoteFolder, FtpFolderSyncMode mode = FtpFolderSyncMode.Update,
                                                                   FtpRemoteExists existsMode = FtpRemoteExists.Skip, FtpVerify verifyOptions = FtpVerify.None, List <FtpRule> rules = null, IProgress <FtpProgress> progress = null, CancellationToken token = default(CancellationToken))
        {
            if (localFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "localFolder");
            }

            if (remoteFolder.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "remoteFolder");
            }

            // ensure the local path ends with slash
            localFolder = localFolder.EnsurePostfix(Path.DirectorySeparatorChar.ToString());

            // cleanup the remote path
            remoteFolder = remoteFolder.GetFtpPath().EnsurePostfix("/");

            LogFunc(nameof(UploadDirectoryAsync), new object[] { localFolder, remoteFolder, mode, existsMode, verifyOptions, (rules.IsBlank() ? null : rules.Count + " rules") });

            var results = new List <FtpResult>();

            // if the dir does not exist, fail fast
            if (!Directory.Exists(localFolder))
            {
                return(results);
            }

            // flag to determine if existence checks are required
            var checkFileExistence = true;

            // ensure the remote dir exists
            if (!await DirectoryExistsAsync(remoteFolder, token))
            {
                await CreateDirectoryAsync(remoteFolder, token);

                checkFileExistence = false;
            }

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // collect paths of the files that should exist (lowercase for CI checks)
            var shouldExist = new Dictionary <string, bool>();

            // get all the folders in the local directory
            var dirListing = Directory.GetDirectories(localFolder, "*.*", SearchOption.AllDirectories);

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // get all the already existing files
            var remoteListing = checkFileExistence ? GetListing(remoteFolder, FtpListOption.Recursive) : null;

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            // loop thru each folder and ensure it exists #1
            var dirsToUpload = GetSubDirectoriesToUpload(localFolder, remoteFolder, rules, results, dirListing);

            // break if task is cancelled
            token.ThrowIfCancellationRequested();

            /*-------------------------------------------------------------------------------------/
            *   Cancelling after this point would leave the FTP server in an inconsistant state   *
            *-------------------------------------------------------------------------------------*/

            // loop thru each folder and ensure it exists #2
            await CreateSubDirectoriesAsync(this, dirsToUpload, token);

            // get all the files in the local directory
            var fileListing = Directory.GetFiles(localFolder, "*.*", SearchOption.AllDirectories);

            // loop thru each file and transfer it
            var filesToUpload = GetFilesToUpload(localFolder, remoteFolder, rules, results, shouldExist, fileListing);

            await UploadDirectoryFilesAsync(filesToUpload, existsMode, verifyOptions, progress, remoteListing, token);

            // delete the extra remote files if in mirror mode and the directory was pre-existing
            await DeleteExtraServerFilesAsync(mode, remoteFolder, shouldExist, remoteListing, rules, token);

            return(results);
        }