private bool DeleteFtpDirectory(FtpPath path) { Log(path.Depth, ItemAction.Delete, path.Name); var parentWorkingDirectory = _remoteWorkingDirectory; var itemsRemain = false; foreach (var child in _mainClient.GetListing(path.Name, FtpListOption.AllFiles)) { var childPath = path.GetChildPath(child.Name); var exclude = MatchExcludes(childPath.Relative); if (exclude != null) { Log(path.Depth + 1, ItemAction.Skip, child.Name, $"excluded ({exclude.Original})"); itemsRemain = true; continue; } EnsureRemoteWorkingDirectory(path.Absolute); if (!DeleteFtpAny(childPath, child.Type)) { itemsRemain = true; } } EnsureRemoteWorkingDirectory(parentWorkingDirectory); if (itemsRemain) { Log(path.Depth + 1, ItemAction.Skip, $"# dir '{path.Name}' not deleted (items remain)"); return(false); } FtpRetry.ConnectedCall(_mainClient, parentWorkingDirectory, c => c.DeleteDirectory(path.Name)); return(true); }
private void PushDirectory(LocalDirectory localDirectory, FtpPath ftpParentPath) { var ftpPath = ftpParentPath.GetChildPath(localDirectory.Name); FtpRetry.ConnectedCall(_mainClient, ftpParentPath.Absolute, c => c.CreateDirectory(localDirectory.Name)); PushDirectoryContents(localDirectory, ftpPath); }
private void PushFile(LocalFile localFile, string ftpParentPath, string ftpPath, FtpClient client) { // https://github.com/hgupta9/FluentFTP/issues/46 using (var readStream = localFile.OpenRead()) using (var writeStream = FtpRetry.ConnectedCall(client, ftpParentPath, c => c.OpenWrite(ftpPath))) { readStream.CopyTo(writeStream, 256 * 1024); } FtpRetry.ConnectedCall(client, ftpParentPath, c => c.SetModifiedTime(ftpPath, localFile.LastWriteTimeUtc)); }
private void EnsureRemoteWorkingDirectory(string absolutePath, int?retryCount = null) { if (_remoteWorkingDirectory == absolutePath) { return; } FtpRetry.ConnectedCall(_mainClient, "/", c => c.SetWorkingDirectory(absolutePath), retryCount); _remoteWorkingDirectory = absolutePath; }
public void SynchronizeTopLevel(FileSystemInfo local, string ftpPath) { var ftpPathObject = new FtpPath(ftpPath.SubstringAfterLast("/"), ftpPath, "", 0); var remoteIsDirectory = false; try { EnsureRemoteWorkingDirectory(ftpPath, retryCount: 0); remoteIsDirectory = true; } catch (FtpCommandException ex) when(ex.CompletionCode == "550") { } var localAsDirectory = local as DirectoryInfo; if (!remoteIsDirectory) { if (localAsDirectory == null) { Log(0, ItemAction.Replace, local.Name); PushFile(new LocalFile((FileInfo)local, local.Name, 0), "/", ftpPath, _mainClient); return; } if (!_mainClient.HasFeature(FtpCapability.MLSD)) { throw new NotSupportedException($"FTP server does not support MLST and no other way to know whether file {ftpPath} exists was implemented."); } if (_mainClient.GetObjectInfo(ftpPath) != null) { DeleteFtpFile(ftpPathObject); } Log(0, ItemAction.Add, localAsDirectory.Name); FtpRetry.ConnectedCall(_mainClient, "/", c => c.CreateDirectory(localAsDirectory.Name)); PushDirectoryContents(new LocalDirectory(localAsDirectory, "", 0), ftpPathObject); return; } if (localAsDirectory == null) { var remoteChild = _mainClient.GetListing(".", FtpListOption.AllFiles).FirstOrDefault(l => l.Name.Equals(local.Name, StringComparison.OrdinalIgnoreCase)); SynchronizeFileAsync(new LocalFile((FileInfo)local, local.Name, 0), ftpPathObject, remoteChild)?.GetAwaiter().GetResult(); } SynchronizeDirectory(new LocalDirectory(localAsDirectory, "", 0), ftpPathObject); }
private async Task PushFileAsync(LocalFile localFile) { var remoteWorkingDirectory = _remoteWorkingDirectory; using (var pushLease = _backgroundPool.LeaseClient()) { // ReSharper disable AccessToDisposedClosure await Task.Run(() => { try { FtpRetry.ConnectedCall(pushLease.Client, "/", c => c.SetWorkingDirectory(remoteWorkingDirectory)); PushFile(localFile, remoteWorkingDirectory, localFile.Name, pushLease.Client); } catch (Exception ex) { throw new Exception($"Failed to push file '{localFile.RelativePath}': {ex.Message}", ex); } }).ConfigureAwait(false); // ReSharper restore AccessToDisposedClosure } }
private static FtpClient CreateFtpClient(Uri url, NetworkCredential credentials, bool active, bool retry) { var encryptionMode = FtpEncryptionMode.None; if (url.Scheme.Equals("ftps", StringComparison.OrdinalIgnoreCase)) { encryptionMode = FtpEncryptionMode.Explicit; } else if (!url.Scheme.Equals("ftp", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentValidationException($"URL scheme '{url.Scheme}' is not supported."); } FtpClient client = null; try { client = new FtpClient { DataConnectionType = active ? FtpDataConnectionType.AutoActive : FtpDataConnectionType.AutoPassive, Host = url.Host, Port = !url.IsDefaultPort ? url.Port : 0, EncryptionMode = encryptionMode, Credentials = credentials, SslProtocols = SslProtocols.Default | SslProtocols.Tls11 | SslProtocols.Tls12 }; if (retry) { FtpRetry.ConnectedCall(client, "/", c => { /* ConnectedCall will call Connect() for us */ }); } else { client.Connect(); } return(client); } catch (Exception) { client?.Dispose(); throw; } }
private void SynchronizeDirectory(LocalDirectory localDirectory, FtpPath ftpPath) { Log(localDirectory.Depth, ItemAction.Synchronize, localDirectory.Name); EnsureRemoteWorkingDirectory(ftpPath.Absolute); var allRemote = FtpRetry.ConnectedCall(_mainClient, ftpPath.Absolute, c => c.GetListing(".", FtpListOption.AllFiles)) .ToDictionary(l => l.Name, StringComparer.OrdinalIgnoreCase); var allRemoteFound = new HashSet <FtpListItem>(); var pushTasks = new List <Task>(); foreach (var local in localDirectory.EnumerateChildren()) { var remote = allRemote.GetValueOrDefault(local.Name); var exclude = MatchExcludes(local.RelativePath); if (exclude != null) { Log(localDirectory.Depth + 1, ItemAction.Skip, local.Name, $"excluded ({exclude.Original})"); allRemoteFound.Add(remote); continue; } EnsureRemoteWorkingDirectory(ftpPath.Absolute); if (remote != null) { allRemoteFound.Add(remote); } var localAsDirectory = local as LocalDirectory; if (localAsDirectory != null) { if (remote == null) { Log(localDirectory.Depth + 1, ItemAction.Add, localAsDirectory.Name); PushDirectory(localAsDirectory, ftpPath); continue; } if (remote.Type == FtpFileSystemObjectType.Directory) { SynchronizeDirectory(localAsDirectory, ftpPath.GetChildPath(remote.Name)); continue; } DeleteFtpFile(ftpPath.GetChildPath(remote.Name)); Log(localDirectory.Depth + 1, ItemAction.Add, localAsDirectory.Name); PushDirectory(localAsDirectory, ftpPath); continue; } var localAsFile = (LocalFile)local; var pushTask = SynchronizeFileAsync(localAsFile, ftpPath, remote); if (pushTask != null) { pushTasks.Add(pushTask); } } if (pushTasks.Count > 0) { Task.WaitAll(pushTasks.ToArray()); } EnsureRemoteWorkingDirectory(ftpPath.Absolute); foreach (var missing in allRemote.Values.Except(allRemoteFound)) { var missingPath = ftpPath.GetChildPath(missing.Name); var exclude = MatchExcludes(missingPath.Relative); if (exclude != null) { Log(localDirectory.Depth + 1, ItemAction.Skip, missing.Name, $"excluded ({exclude.Original})"); continue; } DeleteFtpAny(missingPath, missing.Type); } }
private void DeleteFtpFile(FtpPath path) { Log(path.Depth, ItemAction.Delete, path.Name); FtpRetry.ConnectedCall(_mainClient, _remoteWorkingDirectory, c => c.DeleteFile(path.Name)); }