コード例 #1
0
        private async Task <FtpResponse> ExecuteSend(TcpClient responseSocket, FtpCommand command, CancellationToken cancellationToken)
        {
            // Parse arguments in a way that's compatible with broken FTP clients
            var argument   = new ListArguments(command.Argument);
            var showHidden = argument.All;

            // Instantiate the formatter
            IListFormatter formatter;

            if (string.Equals(command.Name, "NLST", StringComparison.OrdinalIgnoreCase))
            {
                formatter = new ShortListFormatter();
            }
            else if (string.Equals(command.Name, "LS", StringComparison.OrdinalIgnoreCase))
            {
                if (argument.PreferLong)
                {
                    formatter = new LongListFormatter();
                }
                else
                {
                    formatter = new ShortListFormatter();
                }
            }
            else
            {
                formatter = new LongListFormatter();
            }

            // Parse the given path to determine the mask (e.g. when information about a file was requested)
            var directoriesToProcess = new Queue <DirectoryQueueItem>();

            // Use braces to avoid the definition of mask and path in the following parts
            // of this function.
            {
                var mask = "*";
                var path = Data.Path.Clone();

                foreach (var searchPath in argument.Paths)
                {
                    var foundEntry = await Data.FileSystem.SearchEntryAsync(path, searchPath, cancellationToken).ConfigureAwait(false);

                    if (foundEntry?.Directory == null)
                    {
                        return(new FtpResponse(550, "File system entry not found."));
                    }

                    if (!(foundEntry.Entry is IUnixDirectoryEntry dirEntry))
                    {
                        mask = foundEntry.FileName;
                    }
コード例 #2
0
        /// <inheritdoc/>
        public override async Task <IFtpResponse> Process(FtpCommand command, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(command.Argument))
            {
                var taskStates    = _backgroundTransferWorker.GetStates();
                var statusMessage = new StringBuilder();
                statusMessage.AppendFormat(
                    "Server functional, {0} open connections",
                    _server.Statistics.ActiveConnections);
                if (taskStates.Count != 0)
                {
                    statusMessage.AppendFormat(", {0} active background transfers", taskStates.Count);
                }

                return(new FtpResponse(211, statusMessage.ToString()));
            }

            var mask = command.Argument;

            if (!mask.EndsWith("*"))
            {
                mask += "*";
            }

            var fsFeature = Connection.Features.Get <IFileSystemFeature>();

            var globOptions = new GlobOptions();

            globOptions.Evaluation.CaseInsensitive = fsFeature.FileSystem.FileSystemEntryComparer.Equals("a", "A");

            var glob = Glob.Parse(mask, globOptions);

            var formatter = new LongListFormatter();

            var entries = await fsFeature.FileSystem.GetEntriesAsync(fsFeature.CurrentDirectory, cancellationToken)
                          .ConfigureAwait(false);

            var lines = entries.Where(x => glob.IsMatch(x.Name))
                        .Select(x => formatter.Format(x, x.Name))
                        .ToList();

            return(new FtpResponseList(
                       211,
                       $"STAT {command.Argument}",
                       "STAT",
                       lines));
        }
コード例 #3
0
        /// <inheritdoc/>
        public override async Task <FtpResponse> Process(FtpCommand command, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(command.Argument))
            {
                var taskStates    = _backgroundTransferWorker.GetStates();
                var statusMessage = new StringBuilder();
                statusMessage.AppendFormat("Server functional, {0} open connections", _server.Statistics.ActiveConnections);
                if (taskStates.Count != 0)
                {
                    statusMessage.AppendFormat(", {0} active background transfers", taskStates.Count);
                }

                return(new FtpResponse(211, statusMessage.ToString()));
            }

            var mask = command.Argument;

            if (!mask.EndsWith("*"))
            {
                mask += "*";
            }

            var globOptions = new GlobOptions();

            globOptions.Evaluation.CaseInsensitive = Data.FileSystem.FileSystemEntryComparer.Equals("a", "A");

            var glob = Glob.Parse(mask, globOptions);

            var formatter = new LongListFormatter();
            await Connection.WriteAsync($"211-STAT {command.Argument}", cancellationToken).ConfigureAwait(false);

            var entries = await Data.FileSystem.GetEntriesAsync(Data.CurrentDirectory, cancellationToken)
                          .ConfigureAwait(false);

            foreach (var entry in entries.Where(x => glob.IsMatch(x.Name)))
            {
                var line = formatter.Format(entry, entry.Name);
                Connection.Log?.LogDebug(line);
                await Connection.WriteAsync($" {line}", cancellationToken).ConfigureAwait(false);
            }

            return(new FtpResponse(211, "STAT"));
        }
コード例 #4
0
        /// <inheritdoc/>
        public override async Task<FtpResponse> Process(FtpCommand command, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(command.Argument))
            {
                var taskStates = Server.GetBackgroundTaskStates();
                var statusMessage = new StringBuilder();
                statusMessage.AppendFormat("Server functional, {0} open connections", Server.Statistics.ActiveConnections);
                if (taskStates.Count != 0)
                    statusMessage.AppendFormat(", {0} active background transfers", taskStates.Count);
                return new FtpResponse(211, statusMessage.ToString());
            }

            var mask = command.Argument;
            if (!mask.EndsWith("*"))
                mask += "*";

            var mmOptions = new Options()
            {
                IgnoreCase = Data.FileSystem.FileSystemEntryComparer.Equals("a", "A"),
                NoGlobStar = true,
                Dot = true,
            };

            var mm = new Minimatcher(mask, mmOptions);

            var formatter = new LongListFormatter();
            await Connection.WriteAsync($"211-STAT {command.Argument}", cancellationToken);

            foreach (var entry in (await Data.FileSystem.GetEntriesAsync(Data.CurrentDirectory, cancellationToken)).Where(x => mm.IsMatch(x.Name)))
            {
                var line = formatter.Format(entry, entry.Name);
                Connection.Log?.Debug(line);
                await Connection.WriteAsync($" {line}", cancellationToken);
            }

            return new FtpResponse(211, "STAT");
        }
コード例 #5
0
        private async Task <IFtpResponse?> ExecuteSend(IFtpDataConnection dataConnection, FtpCommand command, CancellationToken cancellationToken)
        {
            var encodingFeature = Connection.Features.Get <IEncodingFeature>();

            // Parse arguments in a way that's compatible with broken FTP clients
            var argument   = new ListArguments(command.Argument);
            var showHidden = argument.All;

            // Instantiate the formatter
            Encoding       encoding;
            IListFormatter formatter;

            if (string.Equals(command.Name, "NLST", StringComparison.OrdinalIgnoreCase))
            {
                encoding  = encodingFeature.NlstEncoding;
                formatter = new ShortListFormatter();
            }
            else if (string.Equals(command.Name, "LS", StringComparison.OrdinalIgnoreCase))
            {
                encoding = encodingFeature.Encoding;
                if (argument.PreferLong)
                {
                    formatter = new LongListFormatter();
                }
                else
                {
                    formatter = new ShortListFormatter();
                }
            }
            else
            {
                encoding  = encodingFeature.Encoding;
                formatter = new LongListFormatter();
            }

            // Parse the given path to determine the mask (e.g. when information about a file was requested)
            var directoriesToProcess = new Queue <DirectoryQueueItem>();

            var fsFeature = Connection.Features.Get <IFileSystemFeature>();

            // Use braces to avoid the definition of mask and path in the following parts
            // of this function.
            {
                if (argument.Paths.Count != 0)
                {
                    foreach (var searchPath in argument.Paths)
                    {
                        var mask = "*";
                        var path = fsFeature.Path.Clone();

                        var foundEntry = await fsFeature.FileSystem.SearchEntryAsync(path, searchPath, cancellationToken).ConfigureAwait(false);

                        if (foundEntry?.Directory == null)
                        {
                            return(new FtpResponse(550, T("File system entry not found.")));
                        }

                        if (!(foundEntry.Entry is IUnixDirectoryEntry dirEntry))
                        {
                            if (!string.IsNullOrEmpty(foundEntry.FileName))
                            {
                                mask = foundEntry.FileName !;
                            }
                        }
                        else if (!dirEntry.IsRoot)
                        {
                            path.Push(dirEntry);
                        }

                        directoriesToProcess.Enqueue(new DirectoryQueueItem(path, mask));
                    }
                }
コード例 #6
0
        /// <inheritdoc/>
        public override async Task <FtpResponse> Process(FtpCommand command, CancellationToken cancellationToken)
        {
            await Connection.WriteAsync(new FtpResponse(150, "Opening data connection."), cancellationToken);

            ITcpSocketClient responseSocket;

            try
            {
                responseSocket = await Connection.CreateResponseSocket();
            }
            catch (Exception)
            {
                return(new FtpResponse(425, "Can't open data connection."));
            }
            try
            {
                // Parse arguments in a way that's compatible with broken FTP clients
                var argument   = new ListArguments(command.Argument);
                var showHidden = argument.All;

                // Instantiate the formatter
                IListFormatter formatter;
                if (string.Equals(command.Name, "NLST", StringComparison.OrdinalIgnoreCase))
                {
                    formatter = new ShortListFormatter();
                }
                else if (string.Equals(command.Name, "LS", StringComparison.OrdinalIgnoreCase))
                {
                    formatter = new LongListFormatter();
                }
                else
                {
                    formatter = new LongListFormatter();
                }

                // Parse the given path to determine the mask (e.g. when information about a file was requested)
                var directoriesToProcess = new Queue <DirectoryQueueItem>();

                // Use braces to avoid the definition of mask and path in the following parts
                // of this function.
                {
                    var mask = "*";
                    var path = Data.Path.Clone();

                    if (!string.IsNullOrEmpty(argument.Path))
                    {
                        var foundEntry = await Data.FileSystem.SearchEntryAsync(path, argument.Path, cancellationToken);

                        if (foundEntry?.Directory == null)
                        {
                            return(new FtpResponse(550, "File system entry not found."));
                        }
                        var dirEntry = foundEntry.Entry as IUnixDirectoryEntry;
                        if (dirEntry == null)
                        {
                            mask = foundEntry.FileName;
                        }
                        else if (!dirEntry.IsRoot)
                        {
                            path.Push(dirEntry);
                        }
                    }
                    directoriesToProcess.Enqueue(new DirectoryQueueItem(path, mask));
                }

                var encoding = Data.NlstEncoding ?? Connection.Encoding;

                using (var stream = await Connection.CreateEncryptedStream(responseSocket.WriteStream))
                {
                    using (var writer = new StreamWriter(stream, encoding, 4096, true)
                    {
                        NewLine = "\r\n",
                    })
                    {
                        while (directoriesToProcess.Count != 0)
                        {
                            var queueItem = directoriesToProcess.Dequeue();

                            var currentPath     = queueItem.Path;
                            var mask            = queueItem.Mask;
                            var currentDirEntry = currentPath.Count != 0 ? currentPath.Peek() : Data.FileSystem.Root;

                            if (argument.Recursive)
                            {
                                var line = currentPath.ToDisplayString() + ":";
                                Connection.Log?.Debug(line);
                                await writer.WriteLineAsync(line);
                            }

                            var mmOptions = new Options()
                            {
                                IgnoreCase = Data.FileSystem.FileSystemEntryComparer.Equals("a", "A"),
                                NoGlobStar = true,
                                Dot        = true,
                            };

                            var mm = new Minimatcher(mask, mmOptions);

                            var entries = await Data.FileSystem.GetEntriesAsync(currentDirEntry, cancellationToken);

                            var enumerator = new DirectoryListingEnumerator(entries, Data.FileSystem, currentPath, true);
                            while (enumerator.MoveNext())
                            {
                                var name = enumerator.Name;
                                if (!enumerator.IsDotEntry)
                                {
                                    if (!mm.IsMatch(name))
                                    {
                                        continue;
                                    }
                                    if (name.StartsWith(".") && !showHidden)
                                    {
                                        continue;
                                    }
                                }

                                var entry = enumerator.Entry;

                                if (argument.Recursive && !enumerator.IsDotEntry)
                                {
                                    var dirEntry = entry as IUnixDirectoryEntry;
                                    if (dirEntry != null)
                                    {
                                        var subDirPath = currentPath.Clone();
                                        subDirPath.Push(dirEntry);
                                        directoriesToProcess.Enqueue(new DirectoryQueueItem(subDirPath, "*"));
                                    }
                                }

                                var line = formatter.Format(entry, name);
                                Connection.Log?.Debug(line);
                                await writer.WriteLineAsync(line);
                            }
                        }
                    }
                }
            }
            finally
            {
                responseSocket.Dispose();
            }

            // Use 250 when the connection stays open.
            return(new FtpResponse(250, "Closing data connection."));
        }