diff --git a/netutils/ftpc/Kconfig b/netutils/ftpc/Kconfig index 9df86947f..6a3efc806 100644 --- a/netutils/ftpc/Kconfig +++ b/netutils/ftpc/Kconfig @@ -50,4 +50,15 @@ config FTPC_DISABLE_EPSV if you need to use PASV instead, use this option to disable EPSV and fallback to using PASV. +config FTPC_OVER_SENDFILE + bool "Use sendfile() in ftpc binary transfer mode of PUT operation" + default y + depends on NET_SENDFILE + ---help--- + This option enables using sendfile() in ftpc binary transfer mode of PUT + operation. If the option is enabled but ASCII transfer mode is activated, + ftpc falls back to the combination of read() and write(). + Using sendfile() provides a higher performance compared + to the combination of read() and write(). + endif diff --git a/netutils/ftpc/ftpc_putfile.c b/netutils/ftpc/ftpc_putfile.c index 2cdeecb3f..5b51c39c2 100644 --- a/netutils/ftpc/ftpc_putfile.c +++ b/netutils/ftpc/ftpc_putfile.c @@ -25,6 +25,7 @@ #include "ftpc_config.h" #include +#include #include #include #include @@ -65,11 +66,60 @@ * ****************************************************************************/ +#ifdef CONFIG_FTPC_OVER_SENDFILE static int ftpc_sendbinary(FAR struct ftpc_session_s *session, - FAR FILE *linstream, FILE *routstream) + FAR FILE *linstream) +{ + struct stat stat_buf; + off_t offset = session->offset; + ssize_t result; + ssize_t len; + int linfd = fileno(linstream); + + if (linfd == -1 || fstat(linfd, &stat_buf) == -1) + { + ftpc_xfrabort(session, NULL); + return ERROR; + } + + /* Loop until the entire file is sent */ + + len = stat_buf.st_size - offset; + + while (len > 0) + { + result = sendfile(session->data.sd, linfd, &offset, len); + + if (result == -1 && errno == EAGAIN) + { + continue; + } + else if (result == -1) + { + ftpc_xfrabort(session, NULL); + return ERROR; + } + + len -= result; + + /* Increment the size of the file sent */ + + session->size += result; + } + + /* Return success */ + + return OK; +} + +#else + +static int ftpc_sendbinary(FAR struct ftpc_session_s *session, + FAR FILE *linstream) { ssize_t nread; ssize_t nwritten; + FILE *routstream = session->data.outstream; /* Loop until the entire file is sent */ @@ -111,6 +161,7 @@ static int ftpc_sendbinary(FAR struct ftpc_session_s *session, session->size += nread; } } +#endif /**************************************************************************** * Name: ftpc_sendtext @@ -121,10 +172,11 @@ static int ftpc_sendbinary(FAR struct ftpc_session_s *session, ****************************************************************************/ static int ftpc_sendtext(FAR struct ftpc_session_s *session, - FAR FILE *linstream, FAR FILE *routstream) + FAR FILE *linstream) { int ch; int ret = OK; + FILE *routstream = session->data.outstream; /* Write characters one at a time. */ @@ -174,7 +226,6 @@ static int ftpc_sendtext(FAR struct ftpc_session_s *session, static int ftpc_sendfile(struct ftpc_session_s *session, const char *path, FILE *stream, uint8_t how, uint8_t xfrmode) { - long offset = session->offset; #ifdef CONFIG_DEBUG_FEATURES FAR char *rname; FAR char *str; @@ -182,8 +233,6 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path, #endif int ret; - session->offset = 0; - /* Were we asked to store a file uniquely? Does the host support the STOU * command? */ @@ -212,10 +261,10 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path, * allow REST immediately before STOR for binary files. */ - if (offset > 0) + if (session->offset > 0) { - ret = ftpc_cmd(session, "REST %ld", offset); - session->size = offset; + ret = ftpc_cmd(session, "REST %ld", session->offset); + session->size = session->offset; } /* Send the file using STOR, STOU, or APPE: @@ -331,11 +380,11 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path, if (xfrmode == FTPC_XFRMODE_ASCII) { - ret = ftpc_sendtext(session, stream, session->data.outstream); + ret = ftpc_sendtext(session, stream); } else { - ret = ftpc_sendbinary(session, stream, session->data.outstream); + ret = ftpc_sendbinary(session, stream); } ftpc_sockflush(&session->data);