/// <summary> /// Asynchronously removes a directory. Used by <see cref="DeleteDirectoryAsync(string)"/> and /// <see cref="DeleteDirectoryAsync(string, FtpListOption)"/>. /// </summary> /// <param name="path">The full or relative path of the directory to delete</param> /// <param name="deleteContents">Delete the contents before deleting the folder</param> /// <param name="options">Useful to delete hidden files or dot-files.</param> /// <param name="token">The token that can be used to cancel the entire process</param> /// <returns></returns> private async Task DeleteDirInternalAsync(string path, bool deleteContents, FtpListOption options, CancellationToken token = default(CancellationToken)) { FtpReply reply; path = path.GetFtpPath(); // server-specific directory deletion if (!path.IsFtpRootDirectory()) { // ask the server handler to delete a directory if (ServerHandler != null) { if (await ServerHandler.DeleteDirectoryAsync(this, path, path, deleteContents, options, token)) { return; } } } // DELETE CONTENTS OF THE DIRECTORY if (deleteContents) { // when GetListing is called with recursive option, then it does not // make any sense to call another DeleteDirectory with force flag set. // however this requires always delete files first. var recurse = !WasGetListingRecursive(options); // items that are deeper in directory tree are listed first, // then files will be listed before directories. This matters // only if GetListing was called with recursive option. FtpListItem[] itemList; if (recurse) { itemList = await GetListingAsync(path, options, token); } else { itemList = (await GetListingAsync(path, options, token)).OrderByDescending(x => x.FullName.Count(c => c.Equals('/'))).ThenBy(x => x.Type).ToArray(); } // delete the item based on the type foreach (var item in itemList) { switch (item.Type) { case FtpFileSystemObjectType.File: await DeleteFileAsync(item.FullName, token); break; case FtpFileSystemObjectType.Directory: await DeleteDirInternalAsync(item.FullName, recurse, options, token); break; default: throw new FtpException("Don't know how to delete object type: " + item.Type); } } } // SKIP DELETING ROOT DIRS // can't delete the working directory and // can't delete the server root. if (path.IsFtpRootDirectory()) { return; } // DELETE ACTUAL DIRECTORY if (!(reply = await ExecuteAsync("RMD " + path, token)).Success) { throw new FtpCommandException(reply); } }