mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-11-04 20:15:09 +01:00
Add APPE command
This commit is contained in:
parent
17dfdfcf01
commit
60bab0735e
@ -26,6 +26,7 @@ Create a **ftbrony** (double check that it is spelt **exactly** like this) direc
|
|||||||
Supported Commands
|
Supported Commands
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- APPE
|
||||||
- CDUP
|
- CDUP
|
||||||
- CWD
|
- CWD
|
||||||
- DELE
|
- DELE
|
||||||
@ -57,7 +58,6 @@ Planned Commands
|
|||||||
----------------
|
----------------
|
||||||
|
|
||||||
- ALLO
|
- ALLO
|
||||||
- APPE
|
|
||||||
- NLST
|
- NLST
|
||||||
- REST
|
- REST
|
||||||
- STOU
|
- STOU
|
||||||
|
233
source/ftp.c
233
source/ftp.c
@ -94,7 +94,6 @@ 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_RETRY = BIT(6),
|
|
||||||
} session_flags_t;
|
} session_flags_t;
|
||||||
|
|
||||||
/*! ftp session */
|
/*! ftp session */
|
||||||
@ -288,7 +287,8 @@ ftp_set_socket_options(int fd)
|
|||||||
* @param[in] connected whether this socket is connected
|
* @param[in] connected whether this socket is connected
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ftp_closesocket(int fd, int connected)
|
ftp_closesocket(int fd,
|
||||||
|
bool connected)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
@ -328,7 +328,7 @@ ftp_session_close_cmd(ftp_session_t *session)
|
|||||||
{
|
{
|
||||||
/* close command socket */
|
/* close command socket */
|
||||||
if(session->cmd_fd >= 0)
|
if(session->cmd_fd >= 0)
|
||||||
ftp_closesocket(session->cmd_fd, 1);
|
ftp_closesocket(session->cmd_fd, true);
|
||||||
session->cmd_fd = -1;
|
session->cmd_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +346,7 @@ ftp_session_close_pasv(ftp_session_t *session)
|
|||||||
inet_ntoa(session->pasv_addr.sin_addr),
|
inet_ntoa(session->pasv_addr.sin_addr),
|
||||||
ntohs(session->pasv_addr.sin_port));
|
ntohs(session->pasv_addr.sin_port));
|
||||||
|
|
||||||
ftp_closesocket(session->pasv_fd, 0);
|
ftp_closesocket(session->pasv_fd, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
session->pasv_fd = -1;
|
session->pasv_fd = -1;
|
||||||
@ -360,7 +360,7 @@ ftp_session_close_data(ftp_session_t *session)
|
|||||||
{
|
{
|
||||||
/* close data connection */
|
/* close data connection */
|
||||||
if(session->data_fd >= 0)
|
if(session->data_fd >= 0)
|
||||||
ftp_closesocket(session->data_fd, 1);
|
ftp_closesocket(session->data_fd, true);
|
||||||
session->data_fd = -1;
|
session->data_fd = -1;
|
||||||
|
|
||||||
/* clear send/recv flags */
|
/* clear send/recv flags */
|
||||||
@ -458,18 +458,24 @@ ftp_session_read_file(ftp_session_t *session)
|
|||||||
/*! open file for writing for ftp session
|
/*! open file for writing for ftp session
|
||||||
*
|
*
|
||||||
* @param[in] session ftp session
|
* @param[in] session ftp session
|
||||||
|
* @param[in] append whether to append
|
||||||
*
|
*
|
||||||
* @returns -1 for error
|
* @returns -1 for error
|
||||||
*
|
*
|
||||||
* @note truncates file
|
* @note truncates file
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ftp_session_open_file_write(ftp_session_t *session)
|
ftp_session_open_file_write(ftp_session_t *session,
|
||||||
|
bool append)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
const char *mode = "wb";
|
||||||
|
|
||||||
|
if(append)
|
||||||
|
mode = "ab";
|
||||||
|
|
||||||
/* open file in write and create mode with truncation */
|
/* open file in write and create mode with truncation */
|
||||||
session->fp = fopen(session->buffer, "wb");
|
session->fp = fopen(session->buffer, mode);
|
||||||
if(session->fp == NULL)
|
if(session->fp == NULL)
|
||||||
{
|
{
|
||||||
console_print(RED "fopen '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno));
|
console_print(RED "fopen '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno));
|
||||||
@ -718,7 +724,7 @@ ftp_session_new(int listen_fd)
|
|||||||
if(session == NULL)
|
if(session == NULL)
|
||||||
{
|
{
|
||||||
console_print(RED "failed to allocate session\n" RESET);
|
console_print(RED "failed to allocate session\n" RESET);
|
||||||
ftp_closesocket(new_fd, 1);
|
ftp_closesocket(new_fd, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -801,7 +807,7 @@ ftp_session_accept(ftp_session_t *session)
|
|||||||
rc = ftp_set_socket_nonblocking(new_fd);
|
rc = ftp_set_socket_nonblocking(new_fd);
|
||||||
if(rc != 0)
|
if(rc != 0)
|
||||||
{
|
{
|
||||||
ftp_closesocket(new_fd, 1);
|
ftp_closesocket(new_fd, true);
|
||||||
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
||||||
ftp_send_response(session, 425, "Failed to establish connection\r\n");
|
ftp_send_response(session, 425, "Failed to establish connection\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -849,7 +855,7 @@ ftp_session_connect(ftp_session_t *session)
|
|||||||
rc = ftp_set_socket_options(session->data_fd);
|
rc = ftp_set_socket_options(session->data_fd);
|
||||||
if(rc != 0)
|
if(rc != 0)
|
||||||
{
|
{
|
||||||
ftp_closesocket(session->data_fd, 0);
|
ftp_closesocket(session->data_fd, false);
|
||||||
session->data_fd = -1;
|
session->data_fd = -1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -860,7 +866,7 @@ ftp_session_connect(ftp_session_t *session)
|
|||||||
if(rc != 0)
|
if(rc != 0)
|
||||||
{
|
{
|
||||||
console_print(RED "connect: %d %s\n" RESET, errno, strerror(errno));
|
console_print(RED "connect: %d %s\n" RESET, errno, strerror(errno));
|
||||||
ftp_closesocket(session->data_fd, 0);
|
ftp_closesocket(session->data_fd, false);
|
||||||
session->data_fd = -1;
|
session->data_fd = -1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1212,7 +1218,7 @@ ftp_exit(void)
|
|||||||
|
|
||||||
/* stop listening for new clients */
|
/* stop listening for new clients */
|
||||||
if(listenfd >= 0)
|
if(listenfd >= 0)
|
||||||
ftp_closesocket(listenfd, 0);
|
ftp_closesocket(listenfd, false);
|
||||||
|
|
||||||
#ifdef _3DS
|
#ifdef _3DS
|
||||||
/* deinitialize SOC service */
|
/* deinitialize SOC service */
|
||||||
@ -1510,6 +1516,101 @@ store_transfer(ftp_session_t *session)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! ftp_xfer_file mode */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
XFER_FILE_RETR, /*!< Retrieve a file */
|
||||||
|
XFER_FILE_STOR, /*!< Store a file */
|
||||||
|
XFER_FILE_APPE, /*!< Append a file */
|
||||||
|
} xfer_file_mode_t;
|
||||||
|
|
||||||
|
/*! Transfer a file
|
||||||
|
*
|
||||||
|
* @param[in] session ftp session
|
||||||
|
* @param[in] args ftp arguments
|
||||||
|
* @param[in] mode transfer mode
|
||||||
|
*
|
||||||
|
* @returns failure
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ftp_xfer_file(ftp_session_t *session,
|
||||||
|
const char *args,
|
||||||
|
xfer_file_mode_t mode)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(build_path(session, args) != 0)
|
||||||
|
{
|
||||||
|
rc = errno;
|
||||||
|
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
||||||
|
return ftp_send_response(session, 553, "%s\r\n", strerror(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode == XFER_FILE_RETR)
|
||||||
|
rc = ftp_session_open_file_read(session);
|
||||||
|
else
|
||||||
|
rc = ftp_session_open_file_write(session, mode == XFER_FILE_APPE);
|
||||||
|
|
||||||
|
if(rc != 0)
|
||||||
|
{
|
||||||
|
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
||||||
|
return ftp_send_response(session, 450, "failed to open file\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);
|
||||||
|
|
||||||
|
if(mode == XFER_FILE_RETR)
|
||||||
|
{
|
||||||
|
session->flags |= SESSION_SEND;
|
||||||
|
session->transfer = retrieve_transfer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
session->flags |= SESSION_RECV;
|
||||||
|
session->transfer = store_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);
|
||||||
|
|
||||||
|
if(mode == XFER_FILE_RETR)
|
||||||
|
{
|
||||||
|
session->flags |= SESSION_SEND;
|
||||||
|
session->transfer = retrieve_transfer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
session->flags |= SESSION_RECV;
|
||||||
|
session->transfer = store_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 *
|
||||||
@ -1527,12 +1628,9 @@ FTP_DECLARE(ALLO)
|
|||||||
|
|
||||||
FTP_DECLARE(APPE)
|
FTP_DECLARE(APPE)
|
||||||
{
|
{
|
||||||
/* 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_file(session, args, XFER_FILE_APPE);
|
||||||
|
|
||||||
return ftp_send_response(session, 502, "unavailable\r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FTP_DECLARE(CDUP)
|
FTP_DECLARE(CDUP)
|
||||||
@ -1936,57 +2034,9 @@ FTP_DECLARE(REST)
|
|||||||
|
|
||||||
FTP_DECLARE(RETR)
|
FTP_DECLARE(RETR)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||||
|
|
||||||
if(build_path(session, args) != 0)
|
return ftp_xfer_file(session, args, XFER_FILE_RETR);
|
||||||
{
|
|
||||||
rc = errno;
|
|
||||||
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
|
||||||
return ftp_send_response(session, 553, "%s\r\n", strerror(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ftp_session_open_file_read(session) != 0)
|
|
||||||
{
|
|
||||||
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
|
||||||
return ftp_send_response(session, 450, "failed to open file\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 = retrieve_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 = retrieve_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(RMD)
|
FTP_DECLARE(RMD)
|
||||||
@ -2063,59 +2113,12 @@ FTP_DECLARE(RNTO)
|
|||||||
|
|
||||||
FTP_DECLARE(STOR)
|
FTP_DECLARE(STOR)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||||
|
|
||||||
if(build_path(session, args) != 0)
|
return ftp_xfer_file(session, args, XFER_FILE_STOR);
|
||||||
{
|
|
||||||
rc = errno;
|
|
||||||
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
|
||||||
return ftp_send_response(session, 553, "%s\r\n", strerror(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ftp_session_open_file_write(session) != 0)
|
|
||||||
{
|
|
||||||
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
|
||||||
return ftp_send_response(session, 450, "failed to open file\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_RECV;
|
|
||||||
|
|
||||||
session->transfer = store_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_RECV;
|
|
||||||
|
|
||||||
session->transfer = store_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(STOU)
|
FTP_DECLARE(STOU)
|
||||||
{
|
{
|
||||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||||
|
Loading…
Reference in New Issue
Block a user