Add NLST command

This commit is contained in:
Michael Theall 2016-01-15 17:47:18 -06:00
parent 60bab0735e
commit 3da67ce57a
2 changed files with 103 additions and 63 deletions

View File

@ -34,6 +34,7 @@ Supported Commands
- LIST - LIST
- MKD - MKD
- MODE (no-op) - MODE (no-op)
- NLST
- NOOP - NOOP
- PASS (no-op) - PASS (no-op)
- PASV - PASV
@ -58,6 +59,5 @@ Planned Commands
---------------- ----------------
- ALLO - ALLO
- NLST
- REST - REST
- STOU - STOU

View File

@ -19,6 +19,7 @@
#include <3ds.h> #include <3ds.h>
#define lstat stat #define lstat stat
#else #else
#include <stdbool.h>
#define BIT(x) (1<<(x)) #define BIT(x) (1<<(x))
#endif #endif
#include "console.h" #include "console.h"
@ -94,6 +95,7 @@ typedef enum
SESSION_RECV = BIT(3), /*!< data transfer in source mode */ SESSION_RECV = BIT(3), /*!< data transfer in source mode */
SESSION_SEND = BIT(4), /*!< data transfer in sink mode */ SESSION_SEND = BIT(4), /*!< data transfer in sink mode */
SESSION_RENAME = BIT(5), /*!< last command was RNFR and buffer contains path */ SESSION_RENAME = BIT(5), /*!< last command was RNFR and buffer contains path */
SESSION_NLST = BIT(6), /*!< list command is NLST */
} session_flags_t; } session_flags_t;
/*! ftp session */ /*! ftp session */
@ -1389,6 +1391,13 @@ list_transfer(ftp_session_t *session)
else else
snprintf(session->buffer, sizeof(session->buffer), snprintf(session->buffer, sizeof(session->buffer),
"%s/%s", session->cwd, dent->d_name); "%s/%s", session->cwd, dent->d_name);
if(session->flags & SESSION_NLST)
{
session->buffersize =
sprintf(session->buffer, "%s\r\n", dent->d_name);
}
else
{
rc = lstat(session->buffer, &st); rc = lstat(session->buffer, &st);
if(rc != 0) if(rc != 0)
{ {
@ -1405,6 +1414,7 @@ list_transfer(ftp_session_t *session)
S_ISLNK(st.st_mode) ? 'l' : '-', S_ISLNK(st.st_mode) ? 'l' : '-',
(unsigned long long)st.st_size, (unsigned long long)st.st_size,
dent->d_name); dent->d_name);
}
session->bufferpos = 0; session->bufferpos = 0;
} }
@ -1611,6 +1621,80 @@ ftp_xfer_file(ftp_session_t *session,
return ftp_send_response(session, 503, "Bad sequence of commands\r\n"); return ftp_send_response(session, 503, "Bad sequence of commands\r\n");
} }
/*! ftp_xfer_dir mode */
typedef enum
{
XFER_DIR_LIST, /*!< Long list */
XFER_DIR_NLST, /*!< Short list */
} xfer_dir_mode_t;
/*! Transfer a directory
*
* @param[in] session ftp session
* @param[in] args ftp arguments
* @param[in] mode transfer mode
*
* @returns failure
*/
static int
ftp_xfer_dir(ftp_session_t *session,
const char *args,
xfer_dir_mode_t mode)
{
ssize_t rc;
if(ftp_session_open_cwd(session) != 0)
{
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
return ftp_send_response(session, 550, "unavailable\r\n");
}
if(session->flags & SESSION_PORT)
{
ftp_session_set_state(session, DATA_TRANSFER_STATE, CLOSE_PASV);
rc = ftp_session_connect(session);
if(rc != 0)
{
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
return ftp_send_response(session, 425, "can't open data connection\r\n");
}
session->flags &= ~(SESSION_RECV|SESSION_SEND);
session->flags |= SESSION_SEND;
if(mode == XFER_DIR_LIST)
session->flags &= ~SESSION_NLST;
else
session->flags |= SESSION_NLST;
session->transfer = list_transfer;
session->bufferpos = 0;
session->buffersize = 0;
return ftp_send_response(session, 150, "Ready\r\n");
}
else if(session->flags & SESSION_PASV)
{
session->flags &= ~(SESSION_RECV|SESSION_SEND);
session->flags |= SESSION_SEND;
if(mode == XFER_DIR_LIST)
session->flags &= ~SESSION_NLST;
else
session->flags |= SESSION_NLST;
session->transfer = list_transfer;
session->bufferpos = 0;
session->buffersize = 0;
ftp_session_set_state(session, DATA_CONNECT_STATE, CLOSE_DATA);
return 0;
}
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
return ftp_send_response(session, 503, "Bad sequence of commands\r\n");
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* F T P C O M M A N D S * * F T P C O M M A N D S *
@ -1711,50 +1795,9 @@ FTP_DECLARE(FEAT)
FTP_DECLARE(LIST) FTP_DECLARE(LIST)
{ {
ssize_t rc;
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : ""); console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
if(ftp_session_open_cwd(session) != 0) return ftp_xfer_dir(session, args, XFER_DIR_LIST);
{
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
return ftp_send_response(session, 550, "unavailable\r\n");
}
if(session->flags & SESSION_PORT)
{
ftp_session_set_state(session, DATA_TRANSFER_STATE, CLOSE_PASV);
rc = ftp_session_connect(session);
if(rc != 0)
{
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
return ftp_send_response(session, 425, "can't open data connection\r\n");
}
session->flags &= ~(SESSION_RECV|SESSION_SEND);
session->flags |= SESSION_SEND;
session->transfer = list_transfer;
session->bufferpos = 0;
session->buffersize = 0;
return ftp_send_response(session, 150, "Ready\r\n");
}
else if(session->flags & SESSION_PASV)
{
session->flags &= ~(SESSION_RECV|SESSION_SEND);
session->flags |= SESSION_SEND;
session->transfer = list_transfer;
session->bufferpos = 0;
session->buffersize = 0;
ftp_session_set_state(session, DATA_CONNECT_STATE, CLOSE_DATA);
return 0;
}
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
return ftp_send_response(session, 503, "Bad sequence of commands\r\n");
} }
FTP_DECLARE(MKD) FTP_DECLARE(MKD)
@ -1792,12 +1835,9 @@ FTP_DECLARE(MODE)
FTP_DECLARE(NLST) FTP_DECLARE(NLST)
{ {
/* TODO */
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : ""); console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA); return ftp_xfer_dir(session, args, XFER_DIR_NLST);
return ftp_send_response(session, 504, "unavailable\r\n");
} }
FTP_DECLARE(NOOP) FTP_DECLARE(NOOP)