mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-12-22 19:11:47 +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
|
||||
------------------
|
||||
|
||||
- APPE
|
||||
- CDUP
|
||||
- CWD
|
||||
- DELE
|
||||
@ -57,7 +58,6 @@ Planned Commands
|
||||
----------------
|
||||
|
||||
- ALLO
|
||||
- APPE
|
||||
- NLST
|
||||
- REST
|
||||
- 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_SEND = BIT(4), /*!< data transfer in sink mode */
|
||||
SESSION_RENAME = BIT(5), /*!< last command was RNFR and buffer contains path */
|
||||
SESSION_RETRY = BIT(6),
|
||||
} session_flags_t;
|
||||
|
||||
/*! ftp session */
|
||||
@ -288,7 +287,8 @@ ftp_set_socket_options(int fd)
|
||||
* @param[in] connected whether this socket is connected
|
||||
*/
|
||||
static void
|
||||
ftp_closesocket(int fd, int connected)
|
||||
ftp_closesocket(int fd,
|
||||
bool connected)
|
||||
{
|
||||
int rc;
|
||||
struct sockaddr_in addr;
|
||||
@ -328,7 +328,7 @@ ftp_session_close_cmd(ftp_session_t *session)
|
||||
{
|
||||
/* close command socket */
|
||||
if(session->cmd_fd >= 0)
|
||||
ftp_closesocket(session->cmd_fd, 1);
|
||||
ftp_closesocket(session->cmd_fd, true);
|
||||
session->cmd_fd = -1;
|
||||
}
|
||||
|
||||
@ -346,7 +346,7 @@ ftp_session_close_pasv(ftp_session_t *session)
|
||||
inet_ntoa(session->pasv_addr.sin_addr),
|
||||
ntohs(session->pasv_addr.sin_port));
|
||||
|
||||
ftp_closesocket(session->pasv_fd, 0);
|
||||
ftp_closesocket(session->pasv_fd, false);
|
||||
}
|
||||
|
||||
session->pasv_fd = -1;
|
||||
@ -360,7 +360,7 @@ ftp_session_close_data(ftp_session_t *session)
|
||||
{
|
||||
/* close data connection */
|
||||
if(session->data_fd >= 0)
|
||||
ftp_closesocket(session->data_fd, 1);
|
||||
ftp_closesocket(session->data_fd, true);
|
||||
session->data_fd = -1;
|
||||
|
||||
/* clear send/recv flags */
|
||||
@ -458,18 +458,24 @@ ftp_session_read_file(ftp_session_t *session)
|
||||
/*! open file for writing for ftp session
|
||||
*
|
||||
* @param[in] session ftp session
|
||||
* @param[in] append whether to append
|
||||
*
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note truncates file
|
||||
*/
|
||||
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 */
|
||||
session->fp = fopen(session->buffer, "wb");
|
||||
session->fp = fopen(session->buffer, mode);
|
||||
if(session->fp == NULL)
|
||||
{
|
||||
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)
|
||||
{
|
||||
console_print(RED "failed to allocate session\n" RESET);
|
||||
ftp_closesocket(new_fd, 1);
|
||||
ftp_closesocket(new_fd, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -801,7 +807,7 @@ ftp_session_accept(ftp_session_t *session)
|
||||
rc = ftp_set_socket_nonblocking(new_fd);
|
||||
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_send_response(session, 425, "Failed to establish connection\r\n");
|
||||
return -1;
|
||||
@ -849,7 +855,7 @@ ftp_session_connect(ftp_session_t *session)
|
||||
rc = ftp_set_socket_options(session->data_fd);
|
||||
if(rc != 0)
|
||||
{
|
||||
ftp_closesocket(session->data_fd, 0);
|
||||
ftp_closesocket(session->data_fd, false);
|
||||
session->data_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
@ -860,7 +866,7 @@ ftp_session_connect(ftp_session_t *session)
|
||||
if(rc != 0)
|
||||
{
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
@ -1212,7 +1218,7 @@ ftp_exit(void)
|
||||
|
||||
/* stop listening for new clients */
|
||||
if(listenfd >= 0)
|
||||
ftp_closesocket(listenfd, 0);
|
||||
ftp_closesocket(listenfd, false);
|
||||
|
||||
#ifdef _3DS
|
||||
/* deinitialize SOC service */
|
||||
@ -1510,6 +1516,101 @@ store_transfer(ftp_session_t *session)
|
||||
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 *
|
||||
@ -1527,12 +1628,9 @@ FTP_DECLARE(ALLO)
|
||||
|
||||
FTP_DECLARE(APPE)
|
||||
{
|
||||
/* TODO */
|
||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||
|
||||
ftp_session_set_state(session, COMMAND_STATE, CLOSE_PASV | CLOSE_DATA);
|
||||
|
||||
return ftp_send_response(session, 502, "unavailable\r\n");
|
||||
return ftp_xfer_file(session, args, XFER_FILE_APPE);
|
||||
}
|
||||
|
||||
FTP_DECLARE(CDUP)
|
||||
@ -1936,57 +2034,9 @@ FTP_DECLARE(REST)
|
||||
|
||||
FTP_DECLARE(RETR)
|
||||
{
|
||||
int rc;
|
||||
|
||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||
|
||||
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(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");
|
||||
return ftp_xfer_file(session, args, XFER_FILE_RETR);
|
||||
}
|
||||
|
||||
FTP_DECLARE(RMD)
|
||||
@ -2063,59 +2113,12 @@ FTP_DECLARE(RNTO)
|
||||
|
||||
FTP_DECLARE(STOR)
|
||||
{
|
||||
int rc;
|
||||
|
||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||
|
||||
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(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");
|
||||
return ftp_xfer_file(session, args, XFER_FILE_STOR);
|
||||
}
|
||||
|
||||
|
||||
FTP_DECLARE(STOU)
|
||||
{
|
||||
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
|
||||
|
Loading…
Reference in New Issue
Block a user