/// <summary>
 /// Gets a file listing from the server asynchronously. Each <see cref="FtpListItem"/> object returned
 /// contains information about the file that was able to be retrieved.
 /// </summary>
 /// <remarks>
 /// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
 /// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
 /// is equal to 0, then it means the size of the object could also not
 /// be retrieved.
 /// </remarks>
 /// <param name="path">The path to list</param>
 /// <param name="options">Options that dictate how the list operation is performed</param>
 /// <returns>An array of items retrieved in the listing</returns>
 public async Task <FtpListItem[]> GetListingAsync(string path, FtpListOption options)
 {
     //TODO:  Rewrite as true async method with cancellation support
     return(await Task.Factory.FromAsync <string, FtpListOption, FtpListItem[]>(
                (p, o, ac, s) => BeginGetListing(p, o, ac, s),
                ar => EndGetListing(ar),
                path, options, null));
 }
        private void CalculateGetListingCommand(string path, FtpListOption options, out string listcmd, out bool machineList)
        {
            // read flags
            var isForceList = (options & FtpListOption.ForceList) == FtpListOption.ForceList;
            var isNoPath    = (options & FtpListOption.NoPath) == FtpListOption.NoPath;
            var isNameList  = (options & FtpListOption.NameList) == FtpListOption.NameList;
            var isUseLS     = (options & FtpListOption.UseLS) == FtpListOption.UseLS;
            var isAllFiles  = (options & FtpListOption.AllFiles) == FtpListOption.AllFiles;
            var isRecursive = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;

            machineList = false;

            // use machine listing if supported by the server
            if ((!isForceList || m_parser == FtpParser.Machine) && HasFeature(FtpCapability.MLSD))
            {
                listcmd     = "MLSD";
                machineList = true;
            }
            else
            {
                // otherwise use one of the legacy name listing commands
                if (isUseLS)
                {
                    listcmd = "LS";
                }
                else if (isNameList)
                {
                    listcmd = "NLST";
                }
                else
                {
                    var listopts = "";

                    listcmd = "LIST";

                    // add option flags
                    if (isAllFiles)
                    {
                        listopts += "a";
                    }

                    if (isRecursive)
                    {
                        listopts += "R";
                    }

                    if (listopts.Length > 0)
                    {
                        listcmd += " -" + listopts;
                    }
                }
            }

            if (!isNoPath)
            {
                listcmd = listcmd + " " + path.GetFtpPath();
            }
        }
        /// <summary>
        /// Asynchronously removes a directory and all its contents.
        /// </summary>
        /// <param name="path">The full or relative path of the directory to delete</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>
        public Task DeleteDirectoryAsync(string path, FtpListOption options, CancellationToken token = default(CancellationToken))
        {
            // verify args
            if (path.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "path");
            }

            LogFunc(nameof(DeleteDirectoryAsync), new object[] { path, options });
            return(DeleteDirInternalAsync(path, true, options, token));
        }
        /// <summary>
        /// Deletes the specified directory and all its contents.
        /// </summary>
        /// <param name="path">The full or relative path of the directory to delete</param>
        /// <param name="options">Useful to delete hidden files or dot-files.</param>
        /// <example><code source="..\Examples\DeleteDirectory.cs" lang="cs" /></example>
        public void DeleteDirectory(string path, FtpListOption options)
        {
            // verify args
            if (path.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "path");
            }

            LogFunc(nameof(DeleteDirectory), new object[] { path, options });
            DeleteDirInternal(path, true, options);
        }
        /// <summary>
        /// Begins an asynchronous operation to delete the specified directory and all its contents.
        /// </summary>
        /// <param name="path">The full or relative path of the directory to delete</param>
        /// <param name="options">Useful to delete hidden files or dot-files.</param>
        /// <param name="callback">Async callback</param>
        /// <param name="state">State object</param>
        /// <returns>IAsyncResult</returns>
        /// <example><code source="..\Examples\BeginDeleteDirectory.cs" lang="cs" /></example>
        public IAsyncResult BeginDeleteDirectory(string path, FtpListOption options, AsyncCallback callback, object state)
        {
            AsyncDeleteDirectory func;
            IAsyncResult         ar;

            lock (m_asyncmethods) {
                ar = (func = DeleteDirectory).BeginInvoke(path, options, callback, state);
                m_asyncmethods.Add(ar, func);
            }

            return(ar);
        }
Example #6
0
        /// <summary>
        /// Gets a file listing from the server asynchronously
        /// </summary>
        /// <param name="path">The path to list</param>
        /// <param name="options">Options that dictate how the list operation is performed</param>
        /// <param name="callback">AsyncCallback method</param>
        /// <param name="state">State object</param>
        /// <returns>IAsyncResult</returns>
        /// <example><code source="..\Examples\BeginGetListing.cs" lang="cs" /></example>
        public IAsyncResult BeginGetListing(string path, FtpListOption options, AsyncCallback callback, Object state)
        {
            IAsyncResult    ar;
            AsyncGetListing func;

            lock (m_asyncmethods) {
                ar = (func = new AsyncGetListing(GetListing)).BeginInvoke(path, options, callback, state);
                m_asyncmethods.Add(ar, func);
            }

            return(ar);
        }
        /// <summary>
        /// Checks if a file exsts on the server by taking a
        /// file listing of the parent directory in the path
        /// and comparing the results the path supplied.
        /// </summary>
        /// <param name="path">The full or relative path to the file</param>
        /// <param name="options">Options for controling the file listing used to
        /// determine if the file exists.</param>
        /// <returns>True if the file exists</returns>
        public async Task <bool> FileExistsAsync(string path, FtpListOption options = 0)
        {
            string dirname = path.GetFtpDirectoryName();

            if (!(await DirectoryExistsAsync(dirname)))
            {
                return(false);
            }

            var directoryListing = await GetListingAsync(dirname);

            if (directoryListing.Any(item => item.Type == FtpFileSystemObjectType.File && item.Name.GetFtpFileName() == path.GetFtpFileName()))
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Recursive method of GetListingAsync, to recurse through directories on servers that do not natively support recursion.
        /// Automatically called by GetListingAsync where required.
        /// Uses flat recursion instead of head recursion.
        /// </summary>
        /// <param name="path">The path of the directory to list</param>
        /// <param name="options">Options that dictacte how a list is performed and what information is gathered.</param>
        /// <returns>An array of FtpListItem objects</returns>
        protected async Task <FtpListItem[]> GetListingRecursiveAsync(string path, FtpListOption options)
        {
            // remove the recursive flag
            options &= ~FtpListOption.Recursive;

            // add initial path to list of folders to explore
            var stack = new Stack <string>();

            stack.Push(path);
            var allFiles = new List <FtpListItem>();

            // explore folders
            while (stack.Count > 0)
            {
                // get path of folder to list
                var currentPath = stack.Pop();
                if (!currentPath.EndsWith("/"))
                {
                    currentPath += "/";
                }

                // list it
                FtpListItem[] items = await GetListingAsync(currentPath, options);

                // add it to the final listing
                allFiles.AddRange(items);

                // extract the directories
                foreach (var item in items)
                {
                    if (item.Type == FtpFileSystemObjectType.Directory)
                    {
                        stack.Push(item.FullName);
                    }
                }

                items = null;

                // recurse
            }

            // final list of all files and dirs
            return(allFiles.ToArray());
        }
Example #9
0
        /// <summary>
        /// Получение файлов с проверкой имени делегатом пропуска файлов
        /// </summary>
        public int GetFiles(SkipFilesDelegate skipFiles, string destDir, FtpListOption options)
        {
            int count = 0;

            if (ftpClient.IsConnected)
            {
                FtpListItem[] items = GetFtpItemsList(Path.AltDirectorySeparatorChar + WorkDir, options);

                foreach (FtpListItem itemData in items)
                {
                    if (!skipFiles(itemData.Name))
                    {
                        string path = itemData.FullName.Replace(WorkDir, string.Empty).Trim('/').Replace('/', Path.DirectorySeparatorChar);
                        GetFile(itemData.FullName, Path.Combine(destDir, path));
                        count++;
                    }
                }
            }

            return(count);
        }
Example #10
0
        /// <summary>
        /// Формирование списка файлов на ftp
        /// </summary>
        private FtpListItem[] GetFtpItemsList(string topDirectory, FtpListOption options)
        {
            List <FtpListItem> files = new List <FtpListItem>();

            FtpListItem[] items = ftpClient.GetListing(topDirectory);

            foreach (FtpListItem item in items)
            {
                if (item.Type != FtpFileSystemObjectType.Directory)
                {
                    files.Add(item);
                }
                else
                if (options == FtpListOption.Recursive)
                {
                    if (!item.Name.IsMatch(@"^\.+$"))
                    {
                        files.AddRange(GetFtpItemsList(topDirectory + Path.AltDirectorySeparatorChar + item.Name, options));
                    }
                }
            }

            return(files.ToArray());
        }
 /// <summary>
 /// Deletes the directory asynchronous.
 /// </summary>
 /// <typeparam name="TFtpClient">The type of the FTP client.</typeparam>
 /// <param name="client">The client.</param>
 /// <param name="path">The path.</param>
 /// <param name="force">if set to <c>true</c> [force].</param>
 /// <param name="options">The options.</param>
 /// <param name="factory">The factory.</param>
 /// <param name="creationOptions">The creation options.</param>
 /// <param name="scheduler">The scheduler.</param>
 /// <returns></returns>
 public static Task DeleteDirectoryAsync <TFtpClient>(this TFtpClient client, string path, bool force, FtpListOption options,
                                                      TaskFactory factory = null,
                                                      TaskCreationOptions creationOptions = default(TaskCreationOptions),
                                                      TaskScheduler scheduler             = null)
     where TFtpClient : IFtpClient
 {
     return((factory = factory ?? Task.Factory).FromAsync(
                client.BeginDeleteDirectory(path, force, options, null, null),
                client.EndDeleteDirectory,
                creationOptions, scheduler ?? factory.Scheduler ?? TaskScheduler.Current));
 }
 /// <summary>
 /// Files the exists asynchronous.
 /// </summary>
 /// <typeparam name="TFtpClient">The type of the FTP client.</typeparam>
 /// <param name="client">The client.</param>
 /// <param name="path">The path.</param>
 /// <param name="options">The options.</param>
 /// <param name="factory">The factory.</param>
 /// <param name="creationOptions">The creation options.</param>
 /// <param name="scheduler">The scheduler.</param>
 /// <returns></returns>
 public static Task <bool> FileExistsAsync <TFtpClient>(this TFtpClient client, string path, FtpListOption options,
                                                        TaskFactory <bool> factory          = null,
                                                        TaskCreationOptions creationOptions = default(TaskCreationOptions),
                                                        TaskScheduler scheduler             = null)
     where TFtpClient : IFtpClient
 {
     return((factory = factory ?? Task <bool> .Factory).FromAsync(
                client.BeginFileExists(path, options, null, null),
                client.EndFileExists,
                creationOptions, scheduler ?? factory.Scheduler ?? TaskScheduler.Current));
 }
 /// <summary>
 /// Gets the listing asynchronous.
 /// </summary>
 /// <typeparam name="TFtpClient">The type of the FTP client.</typeparam>
 /// <param name="client">The client.</param>
 /// <param name="path">The path.</param>
 /// <param name="options">The options.</param>
 /// <param name="factory">The factory.</param>
 /// <param name="creationOptions">The creation options.</param>
 /// <param name="scheduler">The scheduler.</param>
 /// <returns></returns>
 public static Task <FtpListItem[]> GetListingAsync <TFtpClient>(this TFtpClient client, string path, FtpListOption options,
                                                                 TaskFactory <FtpListItem[]> factory = null,
                                                                 TaskCreationOptions creationOptions = default(TaskCreationOptions),
                                                                 TaskScheduler scheduler             = null)
     where TFtpClient : IFtpClient
 {
     return((factory = factory ?? Task <FtpListItem[]> .Factory).FromAsync(
                client.BeginGetListing(path, options, null, null),
                client.EndGetListing,
                creationOptions, scheduler ?? factory.Scheduler ?? TaskScheduler.Current));
 }
 /// <summary>
 /// Checks whether <see cref="o:GetListing"/> will be called recursively or not.
 /// </summary>
 /// <param name="options"></param>
 /// <returns></returns>
 private bool WasGetListingRecursive(FtpListOption options)
 {
     // FIX: GetListing() now supports recursive listing for all types of lists (name list, file list, machine list)
     //		even if the server does not support recursive listing, because it does its own internal recursion.
     return((options & FtpListOption.Recursive) == FtpListOption.Recursive);
 }
Example #15
0
        /// <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);
            }
        }
Example #16
0
        /// <summary>
        /// Perform server-specific delete directory commands here.
        /// Return true if you executed a server-specific command.
        /// </summary>
        public override bool DeleteDirectory(FtpClient client, string path, string ftppath, bool deleteContents, FtpListOption options)
        {
            // Support #378 - Support RMDIR command for ProFTPd
            if (deleteContents && client.HasFeature(FtpCapability.SITE_RMDIR))
            {
                if ((client.Execute("SITE RMDIR " + ftppath)).Success)
                {
                    client.LogStatus(FtpTraceLevel.Verbose, "Used the server-specific SITE RMDIR command to quickly delete directory: " + ftppath);
                    return(true);
                }
                else
                {
                    client.LogStatus(FtpTraceLevel.Verbose, "Failed to use the server-specific SITE RMDIR command to quickly delete directory: " + ftppath);
                }
            }

            return(false);
        }
Example #17
0
        private bool ServerDeleteDirectory(string path, string ftppath, bool deleteContents, FtpListOption options)
        {
            FtpReply reply;

            // Support #378 - Support RMDIR command for ProFTPd
            if (deleteContents && ServerType == FtpServer.ProFTPD && HasFeature(FtpCapability.SITE_RMDIR))
            {
                if ((reply = Execute("SITE RMDIR " + ftppath)).Success)
                {
                    this.LogStatus(FtpTraceLevel.Verbose, "Used the server-specific SITE RMDIR command to quickly delete: " + ftppath);
                    return(true);
                }
                else
                {
                    this.LogStatus(FtpTraceLevel.Verbose, "Failed to use the server-specific SITE RMDIR command to quickly delete: " + ftppath);
                }
            }

            return(false);
        }
Example #18
0
        /// <summary>
        /// Получение файлов с проверкой имени делегатом пропуска файлов и делегатом получения пути-назначения файла
        /// </summary>
        public int GetFiles(SkipFilesDelegate skipFiles, DestinationDirectoryFilesDelegate destDir, FtpListOption options)
        {
            int count = 0;

            if (ftpClient.IsConnected)
            {
                FtpListItem[] items = ftpClient.GetListing(Path.AltDirectorySeparatorChar + WorkDir, options);

                foreach (FtpListItem itemData in items)
                {
                    if (!skipFiles(itemData.FullName))
                    {
                        string outDirectory = destDir(itemData.Name);
                        if (!Directory.Exists(outDirectory))
                        {
                            Directory.CreateDirectory(outDirectory);
                        }

                        GetFile(itemData.FullName, Path.Combine(outDirectory, itemData.Name));
                        count++;
                    }
                }
            }
            return(count);
        }
Example #19
0
 /// <summary>
 /// Perform async server-specific delete directory commands here.
 /// Return true if you executed a server-specific command.
 /// </summary>
 public virtual async Task <bool> DeleteDirectoryAsync(FtpClient client, string path, string ftppath, bool deleteContents, FtpListOption options, CancellationToken token)
 {
     return(false);
 }
Example #20
0
        /// <summary>
        /// Checks if a file exsts on the server by taking a 
        /// file listing of the parent directory in the path
        /// and comparing the results the path supplied.
        /// </summary>
        /// <param name="path">The full or relative path to the file</param>
        /// <param name="options">Options for controling the file listing used to
        /// determine if the file exists.</param>
        /// <returns>True if the file exists</returns>
        public async Task<bool> FileExistsAsync(string path, FtpListOption options = 0)
        {
            string dirname = path.GetFtpDirectoryName();

            if (!(await DirectoryExistsAsync(dirname)))
                return false;

            var directoryListing = await GetListingAsync(dirname);

            if (
                directoryListing.Any(
                    item =>
                        item.Type == FtpFileSystemObjectType.File && item.Name.GetFtpFileName() == path.GetFtpFileName()))
            {
                return true;
            }

            return false;
        }
Example #21
0
        /// <summary>
        /// Gets a file listing from the server asynchronously. Each <see cref="FtpListItem"/> object returned
        /// contains information about the file that was able to be retrieved.
        /// </summary>
        /// <remarks>
        /// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
        /// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
        /// is equal to 0, then it means the size of the object could also not
        /// be retrieved.
        /// </remarks>
        /// <param name="path">The path to list</param>
        /// <param name="options">Options that dictate how the list operation is performed</param>
        /// <param name="token">Cancellation Token</param>
        /// <returns>An array of items retrieved in the listing</returns>
        public async Task <FtpListItem[]> GetListingAsync(string path, FtpListOption options, CancellationToken token = default(CancellationToken))
        {
            // start recursive process if needed and unsupported by the server
            if ((options & FtpListOption.Recursive) == FtpListOption.Recursive && !RecursiveList)
            {
                return(await GetListingRecursiveAsync(GetAbsolutePath(path), options));
            }

            this.LogFunc(nameof(GetListingAsync), new object[] { path, options });

            FtpListItem        item       = null;
            List <FtpListItem> lst        = new List <FtpListItem>();
            List <string>      rawlisting = new List <string>();
            string             listcmd    = null;
            string             buf        = null;

            // read flags
            bool isIncludeSelf = (options & FtpListOption.IncludeSelfAndParent) == FtpListOption.IncludeSelfAndParent;
            bool isForceList   = (options & FtpListOption.ForceList) == FtpListOption.ForceList;
            bool isNoPath      = (options & FtpListOption.NoPath) == FtpListOption.NoPath;
            bool isNameList    = (options & FtpListOption.NameList) == FtpListOption.NameList;
            bool isUseLS       = (options & FtpListOption.UseLS) == FtpListOption.UseLS;
            bool isAllFiles    = (options & FtpListOption.AllFiles) == FtpListOption.AllFiles;
            bool isRecursive   = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;
            bool isDerefLinks  = (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks;
            bool isGetModified = (options & FtpListOption.Modify) == FtpListOption.Modify;
            bool isGetSize     = (options & FtpListOption.Size) == FtpListOption.Size;

            // calc path to request
            path = await GetAbsolutePathAsync(path, token);

            // MLSD provides a machine readable format with 100% accurate information
            // so always prefer MLSD over LIST unless the caller of this method overrides it with the ForceList option
            bool machineList = false;

            if ((!isForceList || m_parser == FtpParser.Machine) && HasFeature(FtpCapability.MLSD))
            {
                listcmd     = "MLSD";
                machineList = true;
            }
            else
            {
                if (isUseLS)
                {
                    listcmd = "LS";
                }
                else if (isNameList)
                {
                    listcmd = "NLST";
                }
                else
                {
                    string listopts = "";

                    listcmd = "LIST";

                    if (isAllFiles)
                    {
                        listopts += "a";
                    }

                    if (isRecursive)
                    {
                        listopts += "R";
                    }

                    if (listopts.Length > 0)
                    {
                        listcmd += " -" + listopts;
                    }
                }
            }

            if (!isNoPath)
            {
                listcmd = (listcmd + " " + path.GetFtpPath());
            }

            await ExecuteAsync("TYPE I", token);

            // read in raw file listing
            try
            {
                using (FtpDataStream stream = await OpenDataStreamAsync(listcmd, 0, token))
                {
                    try
                    {
                        this.LogLine(FtpTraceLevel.Verbose, "+---------------------------------------+");

                        if (this.BulkListing)
                        {
                            // increases performance of GetListing by reading multiple lines of the file listing at once
                            foreach (var line in await stream.ReadAllLinesAsync(Encoding, this.BulkListingLength, token))
                            {
                                if (!FtpExtensions.IsNullOrWhiteSpace(line))
                                {
                                    rawlisting.Add(line);
                                    this.LogLine(FtpTraceLevel.Verbose, "Listing:  " + line);
                                }
                            }
                        }
                        else
                        {
                            // GetListing will read file listings line-by-line (actually byte-by-byte)
                            while ((buf = await stream.ReadLineAsync(Encoding, token)) != null)
                            {
                                if (buf.Length > 0)
                                {
                                    rawlisting.Add(buf);
                                    this.LogLine(FtpTraceLevel.Verbose, "Listing:  " + buf);
                                }
                            }
                        }

                        this.LogLine(FtpTraceLevel.Verbose, "-----------------------------------------");
                    }
                    finally
                    {
                        stream.Close();
                    }
                }
            }
            catch (FtpMissingSocketException)
            {
                // Some FTP server does not send any response when listing an empty directory
                // and the authentication fails, if no communication socket is provided by the server
            }

            for (int i = 0; i < rawlisting.Count; i++)
            {
                buf = rawlisting[i];

                if (isNameList)
                {
                    // if NLST was used we only have a file name so
                    // there is nothing to parse.
                    item = new FtpListItem()
                    {
                        FullName = buf
                    };

                    if (await DirectoryExistsAsync(item.FullName, token))
                    {
                        item.Type = FtpFileSystemObjectType.Directory;
                    }
                    else
                    {
                        item.Type = FtpFileSystemObjectType.File;
                    }

                    lst.Add(item);
                }
                else
                {
                    // if this is a result of LIST -R then the path will be spit out
                    // before each block of objects
                    if (listcmd.StartsWith("LIST") && isRecursive)
                    {
                        if (buf.StartsWith("/") && buf.EndsWith(":"))
                        {
                            path = buf.TrimEnd(':');
                            continue;
                        }
                    }

                    // if the next line in the listing starts with spaces
                    // it is assumed to be a continuation of the current line
                    if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
                    {
                        buf += rawlisting[++i];
                    }

                    try
                    {
                        item = m_listParser.ParseSingleLine(path, buf, m_caps, machineList);
                    }
                    catch (FtpListParser.CriticalListParseException)
                    {
                        this.LogStatus(FtpTraceLevel.Verbose, "Restarting parsing from first entry in list");
                        i = -1;
                        lst.Clear();
                        continue;
                    }

                    // FtpListItem.Parse() returns null if the line
                    // could not be parsed
                    if (item != null)
                    {
                        if (isIncludeSelf || !(item.Name == "." || item.Name == ".."))
                        {
                            lst.Add(item);
                        }
                        else
                        {
                            //this.LogStatus(FtpTraceLevel.Verbose, "Skipped self or parent item: " + item.Name);
                        }
                    }
                    else
                    {
                        this.LogStatus(FtpTraceLevel.Warn, "Failed to parse file listing: " + buf);
                    }
                }

                // load extended information that wasn't available if the list options flags say to do so.
                if (item != null)
                {
                    // try to dereference symbolic links if the appropriate list
                    // option was passed
                    if (item.Type == FtpFileSystemObjectType.Link && isDerefLinks)
                    {
                        item.LinkObject = await DereferenceLinkAsync(item, token);
                    }

                    // if need to get file modified date
                    if (isGetModified && HasFeature(FtpCapability.MDTM))
                    {
                        // if the modified date was not loaded or the modified date is more than a day in the future
                        // and the server supports the MDTM command, load the modified date.
                        // most servers do not support retrieving the modified date
                        // of a directory but we try any way.
                        if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST"))
                        {
                            DateTime modify;

                            if (item.Type == FtpFileSystemObjectType.Directory)
                            {
                                this.LogStatus(FtpTraceLevel.Verbose, "Trying to retrieve modification time of a directory, some servers don't like this...");
                            }

                            if ((modify = await GetModifiedTimeAsync(item.FullName, token: token)) != DateTime.MinValue)
                            {
                                item.Modified = modify;
                            }
                        }
                    }

                    // if need to get file size
                    if (isGetSize && HasFeature(FtpCapability.SIZE))
                    {
                        // if no size was parsed, the object is a file and the server
                        // supports the SIZE command, then load the file size
                        if (item.Size == -1)
                        {
                            if (item.Type != FtpFileSystemObjectType.Directory)
                            {
                                item.Size = await GetFileSizeAsync(item.FullName, token);
                            }
                            else
                            {
                                item.Size = 0;
                            }
                        }
                    }
                }
            }

            return(lst.ToArray());
        }
Example #22
0
        private bool ServerDeleteDirectory(string path, string ftppath, bool deleteContents, FtpListOption options)
        {
            // Support #378 - Support RMDIR command for ProFTPd
            if (deleteContents && HasFeature(FtpCapability.SITE_RMDIR))
            {
                if ((Execute("SITE RMDIR " + ftppath)).Success)
                {
                    LogStatus(FtpTraceLevel.Verbose, "Used the server-specific SITE RMDIR command to quickly delete directory: " + ftppath);
                    return(true);
                }
                else
                {
                    LogStatus(FtpTraceLevel.Verbose, "Failed to use the server-specific SITE RMDIR command to quickly delete directory: " + ftppath);
                }
            }

            // Support #88 - Support RMDA command for Serv-U
            if (deleteContents && HasFeature(FtpCapability.RMDA))
            {
                if ((Execute("RMDA " + ftppath)).Success)
                {
                    LogStatus(FtpTraceLevel.Verbose, "Used the server-specific RMDA command to quickly delete directory: " + ftppath);
                    return(true);
                }
                else
                {
                    LogStatus(FtpTraceLevel.Verbose, "Failed to use the server-specific RMDA command to quickly delete directory: " + ftppath);
                }
            }

            return(false);
        }
Example #23
0
        /// <summary>
        /// Perform async server-specific delete directory commands here.
        /// Return true if you executed a server-specific command.
        /// </summary>
        public override async Task <bool> DeleteDirectoryAsync(FtpClient client, string path, string ftppath, bool deleteContents, FtpListOption options, CancellationToken token)
        {
            // Support #88 - Support RMDA command for Serv-U
            if (deleteContents && client.HasFeature(FtpCapability.RMDA))
            {
                if ((await client.ExecuteAsync("RMDA " + ftppath, token)).Success)
                {
                    client.LogStatus(FtpTraceLevel.Verbose, "Used the server-specific RMDA command to quickly delete directory: " + ftppath);
                    return(true);
                }
                else
                {
                    client.LogStatus(FtpTraceLevel.Verbose, "Failed to use the server-specific RMDA command to quickly delete directory: " + ftppath);
                }
            }

            return(false);
        }
        /// <summary>
        /// Deletes the specified directory and all its contents.
        /// </summary>
        /// <param name="path">The full or relative path of the directory to delete</param>
        /// <param name="deleteContents">If the directory is not empty, remove its contents</param>
        /// <param name="options">Useful to delete hidden files or dot-files.</param>
        /// <example><code source="..\Examples\DeleteDirectory.cs" lang="cs" /></example>
        private void DeleteDirInternal(string path, bool deleteContents, FtpListOption options)
        {
            FtpReply reply;
            var      ftppath = path.GetFtpPath();


#if !CORE14
            lock (m_lock) {
#endif


            // server-specific directory deletion
            if (!ftppath.IsFtpRootDirectory())
            {
                if (FtpServerSpecificHandler.ServerDeleteDirectory(this, path, ftppath, deleteContents, options))
                {
                    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 = GetListing(path, options);
                }
                else
                {
                    itemList = GetListing(path, options).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:
                        DeleteFile(item.FullName);
                        break;

                    case FtpFileSystemObjectType.Directory:
                        DeleteDirInternal(item.FullName, recurse, options);
                        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 (ftppath.IsFtpRootDirectory())
            {
                return;
            }


            // DELETE ACTUAL DIRECTORY

            if (!(reply = Execute("RMD " + ftppath)).Success)
            {
                throw new FtpCommandException(reply);
            }

#if !CORE14
        }
#endif
        }
        /// <summary>
        /// Gets a file listing from the server. Each <see cref="FtpListItem"/> object returned
        /// contains information about the file that was able to be retrieved.
        /// </summary>
        /// <remarks>
        /// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
        /// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
        /// is equal to 0, then it means the size of the object could also not
        /// be retrieved.
        /// </remarks>
        /// <param name="path">The path of the directory to list</param>
        /// <param name="options">Options that dictacte how a list is performed and what information is gathered.</param>
        /// <returns>An array of FtpListItem objects</returns>
        /// <example><code source="..\Examples\GetListing.cs" lang="cs" /></example>
        public FtpListItem[] GetListing(string path, FtpListOption options)
        {
            FtpTrace.WriteFunc("GetListing", new object[] { path, options });

            FtpListItem        item       = null;
            List <FtpListItem> lst        = new List <FtpListItem>();
            List <string>      rawlisting = new List <string>();
            string             listcmd    = null;
            string             buf        = null;

            // read flags
            bool isIncludeSelf = (options & FtpListOption.IncludeSelfAndParent) == FtpListOption.IncludeSelfAndParent;
            bool isForceList   = (options & FtpListOption.ForceList) == FtpListOption.ForceList;
            bool isNoPath      = (options & FtpListOption.NoPath) == FtpListOption.NoPath;
            bool isNameList    = (options & FtpListOption.NameList) == FtpListOption.NameList;
            bool isUseLS       = (options & FtpListOption.UseLS) == FtpListOption.UseLS;
            bool isAllFiles    = (options & FtpListOption.AllFiles) == FtpListOption.AllFiles;
            bool isRecursive   = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;
            bool isDerefLinks  = (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks;
            bool isGetModified = (options & FtpListOption.Modify) == FtpListOption.Modify;
            bool isGetSize     = (options & FtpListOption.Size) == FtpListOption.Size;

            // calc path to request
            path = GetAbsolutePath(path);

            // MLSD provides a machine readable format with 100% accurate information
            // so always prefer MLSD over LIST unless the caller of this method overrides it with the ForceList option
            bool machineList = false;

            if ((!isForceList || m_parser == FtpParser.Machine) && HasFeature(FtpCapability.MLSD))
            {
                listcmd     = "MLSD";
                machineList = true;
            }
            else
            {
                if (isUseLS)
                {
                    listcmd = "LS";
                }
                else if (isNameList)
                {
                    listcmd = "NLST";
                }
                else
                {
                    string listopts = "";

                    listcmd = "LIST";

                    if (isAllFiles)
                    {
                        listopts += "a";
                    }

                    if (isRecursive)
                    {
                        listopts += "R";
                    }

                    if (listopts.Length > 0)
                    {
                        listcmd += " -" + listopts;
                    }
                }
            }

            if (!isNoPath)
            {
                listcmd = (listcmd + " " + path.GetFtpPath());
            }

#if !CORE14
            lock (m_lock) {
#endif
            Execute("TYPE I");

            // read in raw file listing
            using (FtpDataStream stream = OpenDataStream(listcmd, 0)) {
                try {
                    FtpTrace.WriteLine(FtpTraceLevel.Verbose, "+---------------------------------------+");
                    while ((buf = stream.ReadLine(Encoding)) != null)
                    {
                        if (buf.Length > 0)
                        {
                            rawlisting.Add(buf);
                            FtpTrace.WriteLine(FtpTraceLevel.Verbose, "Listing:  " + buf);
                        }
                    }
                    FtpTrace.WriteLine(FtpTraceLevel.Verbose, "-----------------------------------------");
                } finally {
                    stream.Close();
                }
            }
#if !CORE14
        }
#endif

            for (int i = 0; i < rawlisting.Count; i++)
            {
                buf = rawlisting[i];

                if (isNameList)
                {
                    // if NLST was used we only have a file name so
                    // there is nothing to parse.
                    item = new FtpListItem()
                    {
                        FullName = buf
                    };

                    if (DirectoryExists(item.FullName))
                    {
                        item.Type = FtpFileSystemObjectType.Directory;
                    }
                    else
                    {
                        item.Type = FtpFileSystemObjectType.File;
                    }

                    lst.Add(item);
                }
                else
                {
                    // if this is a result of LIST -R then the path will be spit out
                    // before each block of objects
                    if (listcmd.StartsWith("LIST") && isRecursive)
                    {
                        if (buf.StartsWith("/") && buf.EndsWith(":"))
                        {
                            path = buf.TrimEnd(':');
                            continue;
                        }
                    }

                    // if the next line in the listing starts with spaces
                    // it is assumed to be a continuation of the current line
                    if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
                    {
                        buf += rawlisting[++i];
                    }

                    item = m_listParser.ParseSingleLine(path, buf, m_caps, machineList);

                    // FtpListItem.Parse() returns null if the line
                    // could not be parsed
                    if (item != null)
                    {
                        if (isIncludeSelf || !(item.Name == "." || item.Name == ".."))
                        {
                            lst.Add(item);
                        }
                        else
                        {
                            //FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped self or parent item: " + item.Name);
                        }
                    }
                    else
                    {
                        FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to parse file listing: " + buf);
                    }
                }

                // load extended information that wasn't available if the list options flags say to do so.
                if (item != null)
                {
                    // try to dereference symbolic links if the appropriate list
                    // option was passed
                    if (item.Type == FtpFileSystemObjectType.Link && isDerefLinks)
                    {
                        item.LinkObject = DereferenceLink(item);
                    }

                    // if need to get file modified date
                    if (isGetModified && HasFeature(FtpCapability.MDTM))
                    {
                        // if the modified date was not loaded or the modified date is more than a day in the future
                        // and the server supports the MDTM command, load the modified date.
                        // most servers do not support retrieving the modified date
                        // of a directory but we try any way.
                        if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST"))
                        {
                            DateTime modify;

                            if (item.Type == FtpFileSystemObjectType.Directory)
                            {
                                FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Trying to retrieve modification time of a directory, some servers don't like this...");
                            }

                            if ((modify = GetModifiedTime(item.FullName)) != DateTime.MinValue)
                            {
                                item.Modified = modify;
                            }
                        }
                    }

                    // if need to get file size
                    if (isGetSize && HasFeature(FtpCapability.SIZE))
                    {
                        // if no size was parsed, the object is a file and the server
                        // supports the SIZE command, then load the file size
                        if (item.Size == -1)
                        {
                            if (item.Type != FtpFileSystemObjectType.Directory)
                            {
                                item.Size = GetFileSize(item.FullName);
                            }
                            else
                            {
                                item.Size = 0;
                            }
                        }
                    }
                }
            }

            return(lst.ToArray());
        }
Example #26
0
        private async Task <bool> ServerDeleteDirectoryAsync(string path, string ftppath, bool deleteContents, FtpListOption options, CancellationToken token)
        {
            // Support #378 - Support RMDIR command for ProFTPd
            if (deleteContents && ServerType == FtpServer.ProFTPD && HasFeature(FtpCapability.SITE_RMDIR))
            {
                if ((await ExecuteAsync("SITE RMDIR " + ftppath, token)).Success)
                {
                    LogStatus(FtpTraceLevel.Verbose, "Used the server-specific SITE RMDIR command to quickly delete: " + ftppath);
                    return(true);
                }
                else
                {
                    LogStatus(FtpTraceLevel.Verbose, "Failed to use the server-specific SITE RMDIR command to quickly delete: " + ftppath);
                }
            }

            return(false);
        }
Example #27
0
        /// <summary>
        /// Gets a file listing from the server asynchronously. Each <see cref="FtpListItem"/> object returned
        /// contains information about the file that was able to be retrieved.
        /// </summary>
        /// <remarks>
        /// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
        /// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
        /// is equal to 0, then it means the size of the object could also not
        /// be retrieved.
        /// </remarks>
        /// <param name="path">The path to list</param>
        /// <param name="options">Options that dictate how the list operation is performed</param>
        /// <param name="token">Cancellation Token</param>
        /// <returns>An array of items retrieved in the listing</returns>
        public async Task <FtpListItem[]> GetListingAsync(string path, FtpListOption options, CancellationToken token = default(CancellationToken))
        {
            // start recursive process if needed and unsupported by the server
            if ((options & FtpListOption.Recursive) == FtpListOption.Recursive && !RecursiveList)
            {
                return(await GetListingRecursiveAsync(GetAbsolutePath(path), options));
            }

            this.LogFunc(nameof(GetListingAsync), new object[] { path, options });

            FtpListItem        item       = null;
            List <FtpListItem> lst        = new List <FtpListItem>();
            List <string>      rawlisting = new List <string>();
            string             listcmd    = null;
            string             buf        = null;

            // read flags
            bool isIncludeSelf = (options & FtpListOption.IncludeSelfAndParent) == FtpListOption.IncludeSelfAndParent;
            bool isNameList    = (options & FtpListOption.NameList) == FtpListOption.NameList;
            bool isRecursive   = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;
            bool isDerefLinks  = (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks;
            bool isGetModified = (options & FtpListOption.Modify) == FtpListOption.Modify;
            bool isGetSize     = (options & FtpListOption.Size) == FtpListOption.Size;

            // calc path to request
            path = await GetAbsolutePathAsync(path, token);

            // MLSD provides a machine readable format with 100% accurate information
            // so always prefer MLSD over LIST unless the caller of this method overrides it with the ForceList option
            bool machineList;

            CalculateGetListingCommand(path, options, out listcmd, out machineList);

            // read in raw file listing
            rawlisting = await GetListingInternalAsync(listcmd, true, token);

            for (int i = 0; i < rawlisting.Count; i++)
            {
                buf = rawlisting[i];

                if (isNameList)
                {
                    // if NLST was used we only have a file name so
                    // there is nothing to parse.
                    item = new FtpListItem()
                    {
                        FullName = buf
                    };

                    if (await DirectoryExistsAsync(item.FullName, token))
                    {
                        item.Type = FtpFileSystemObjectType.Directory;
                    }
                    else
                    {
                        item.Type = FtpFileSystemObjectType.File;
                    }

                    lst.Add(item);
                }
                else
                {
                    // if this is a result of LIST -R then the path will be spit out
                    // before each block of objects
                    if (listcmd.StartsWith("LIST") && isRecursive)
                    {
                        if (buf.StartsWith("/") && buf.EndsWith(":"))
                        {
                            path = buf.TrimEnd(':');
                            continue;
                        }
                    }

                    // if the next line in the listing starts with spaces
                    // it is assumed to be a continuation of the current line
                    if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
                    {
                        buf += rawlisting[++i];
                    }

                    try
                    {
                        item = m_listParser.ParseSingleLine(path, buf, m_capabilities, machineList);
                    }
                    catch (FtpListParseException)
                    {
                        this.LogStatus(FtpTraceLevel.Verbose, "Restarting parsing from first entry in list");
                        i = -1;
                        lst.Clear();
                        continue;
                    }

                    // FtpListItem.Parse() returns null if the line
                    // could not be parsed
                    if (item != null)
                    {
                        if (isIncludeSelf || !(item.Name == "." || item.Name == ".."))
                        {
                            lst.Add(item);
                        }
                        else
                        {
                            //this.LogStatus(FtpTraceLevel.Verbose, "Skipped self or parent item: " + item.Name);
                        }
                    }
                    else
                    {
                        this.LogStatus(FtpTraceLevel.Warn, "Failed to parse file listing: " + buf);
                    }
                }

                // load extended information that wasn't available if the list options flags say to do so.
                if (item != null)
                {
                    // try to dereference symbolic links if the appropriate list
                    // option was passed
                    if (item.Type == FtpFileSystemObjectType.Link && isDerefLinks)
                    {
                        item.LinkObject = await DereferenceLinkAsync(item, token);
                    }

                    // if need to get file modified date
                    if (isGetModified && HasFeature(FtpCapability.MDTM))
                    {
                        // if the modified date was not loaded or the modified date is more than a day in the future
                        // and the server supports the MDTM command, load the modified date.
                        // most servers do not support retrieving the modified date
                        // of a directory but we try any way.
                        if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST"))
                        {
                            DateTime modify;

                            if (item.Type == FtpFileSystemObjectType.Directory)
                            {
                                this.LogStatus(FtpTraceLevel.Verbose, "Trying to retrieve modification time of a directory, some servers don't like this...");
                            }

                            if ((modify = await GetModifiedTimeAsync(item.FullName, token: token)) != DateTime.MinValue)
                            {
                                item.Modified = modify;
                            }
                        }
                    }

                    // if need to get file size
                    if (isGetSize && HasFeature(FtpCapability.SIZE))
                    {
                        // if no size was parsed, the object is a file and the server
                        // supports the SIZE command, then load the file size
                        if (item.Size == -1)
                        {
                            if (item.Type != FtpFileSystemObjectType.Directory)
                            {
                                item.Size = await GetFileSizeAsync(item.FullName, token);
                            }
                            else
                            {
                                item.Size = 0;
                            }
                        }
                    }
                }
            }

            return(lst.ToArray());
        }
Example #28
0
 /// <summary>
 /// Perform server-specific delete directory commands here.
 /// Return true if you executed a server-specific command.
 /// </summary>
 public virtual bool DeleteDirectory(FtpClient client, string path, string ftppath, bool deleteContents, FtpListOption options)
 {
     return(false);
 }
Example #29
0
        /// <summary>
        /// Получить файлы с сервера по маске - регулярному выражению
        /// </summary>
        public int GetFiles(string mask, string destDir, FtpListOption options)
        {
            SkipFilesDelegate skipFiles = name => !name.IsMatch(mask);

            return(GetFiles(skipFiles, destDir, options));
        }
Example #30
0
 public static bool HasFlag(this FtpListOption flags, FtpListOption flag)
 {
     return((flags & flag) == flag);
 }
Example #31
0
        public static IEnumerable <FtpListItem> GetFileListingRecursiveParallel(this FtpClient client, string startPath, FtpListOption options)
        {
            Policy retrier = Policy
                             .Handle <Exception>()
                             .WaitAndRetry(new[]
            {
                TimeSpan.FromSeconds(1),
                TimeSpan.FromSeconds(5),
                TimeSpan.FromSeconds(15)
            });

            if (options.HasFlag(FtpListOption.Recursive))
            {
                throw new ArgumentException("Do not use recursive option when doing a recursive listing.", "options");
            }

            List <Task <FtpListItem[]> > pending = new List <Task <FtpListItem[]> >();
            IEnumerable <FtpListItem>    files   = new List <FtpListItem>();

            Func <string, Task <FtpListItem[]> > listFolderAsync = (string path) =>
            {
                return(Task.Factory.StartNew(() =>
                {
                    return retrier.Execute(() =>
                    {
                        return client.GetListing(path, options);
                    });
                }));
            };

            pending.Add(listFolderAsync(startPath));

            int completedTaskIndex;

            while ((completedTaskIndex = Task.WaitAny(pending.ToArray())) != -1 && pending.Count > 0)
            {
                var t = pending.ElementAt(completedTaskIndex);
                pending.RemoveAt(completedTaskIndex);
                var list = t.Result;

                foreach (var d in list.Where(x => x.Type == FtpFileSystemObjectType.Directory))
                {
                    pending.Add(listFolderAsync(d.FullName));
                }

                files = files.Concat(list.Where(x => x.Type != FtpFileSystemObjectType.Directory).ToList());
            }

            return(files);
        }