UNPKG

ftp-srv-esm

Version:

Modern, extensible FTP server (daemon) for Node.js with ESM support. Based on ftp-srv.

66 lines (57 loc) 2.49 kB
import getFileStat from '../../helpers/file-stat.js'; // http://cr.yp.to/ftp/list.html // http://cr.yp.to/ftp/list/eplf.html export default { directive: 'LIST', handler: function ({log, command} = {}) { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.get) return this.reply(402, 'Not supported by file system'); if (!this.fs.list) return this.reply(402, 'Not supported by file system'); // Parse command arguments: extract options and path let path = '.'; let showHidden = false; if (command.arg) { // Split by spaces, filter out empty strings const args = command.arg.split(/\s+/).filter(Boolean); // Check for options const options = args.filter(arg => arg.startsWith('-')); showHidden = options.some(opt => opt.includes('a')); // -a or -al // Find the path (non-option argument) const nonOption = args.find(arg => !arg.startsWith('-')); if (nonOption) path = nonOption; } return this.connector.waitForConnection() .then(() => { this.commandSocket.pause(); }) .then(() => this.fs.get(path)) .then((stat) => stat.isDirectory() ? this.fs.list(path, { showHidden }) : [stat]) .then((files) => { this.reply(150, `Accepted data connection, returning ${files.length} file(s)`); if (!files) { return this.reply({ raw: true, socket: this.connector.socket, useEmptyMessage: true}); } Promise.try(() => files.map((file) => { // Use connection-specific format if set via OPTS LIST, otherwise use server default const fileFormat = this.listFormat || this?.server?.options?.list_format || 'ls'; return getFileStat(file, fileFormat); })) .then((files) => { this.reply({}, {raw: true, message: files.join('\r\n'), socket: this.connector.socket}); }) }) .then(() => this.reply(226)) .catch((err) => { if (err && err.name === 'TimeoutError') { log.error(err); return this.reply(425, 'No connection established'); } log.error(err); return this.reply(451, err.message || 'No directory'); }) .then(() => { this.connector.end(); this.commandSocket.resume(); }); }, syntax: '{{cmd}} [<path>]', description: 'Returns information of a file or directory if specified, else information of the current working directory is returned' };