Fixes all known FTP server bugs

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4398 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2012-02-15 23:37:37 +00:00
parent 3a3ea574c4
commit 715c9987ee

View File

@ -914,9 +914,25 @@ static ssize_t ftpd_recv(int sd, FAR void *data, size_t size, int timeout)
ret = recv(sd, data, size, 0); ret = recv(sd, data, size, 0);
if (ret < 0) if (ret < 0)
{ {
ssize_t errval = errno; int errval = errno;
ndbg("recv() failed: %d\n", errval);
return -errval; /* Special case some TCP read errors. The client side will break the
* connection after the file has been sent. The NuttX socket layer
* will return an error with errno == ENOTCONN. But perhaps that is
* wrong, perhaps it should return 0 (end-of-file) in that case? In
* that event, we will want to report end-of-file here.
*/
if (errval == ENOTCONN)
{
nvdbg("Connection lost, returning end-of-file\n");
ret = 0;
}
else
{
ndbg("recv() failed: %d\n", errval);
return -errval;
}
} }
return ret; return ret;
@ -1716,6 +1732,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
ssize_t rdbytes; ssize_t rdbytes;
ssize_t wrbytes; ssize_t wrbytes;
off_t pos = 0; off_t pos = 0;
int errval = 0;
int ret; int ret;
ret = ftpd_getpath(session, session->param, &abspath, NULL); ret = ftpd_getpath(session, session->param, &abspath, NULL);
@ -1798,7 +1815,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (session->restartpos > 0) if (session->restartpos > 0)
{ {
off_t seekoffs; off_t seekoffs = (off_t)-1;
off_t seekpos; off_t seekpos;
/* Get the seek position */ /* Get the seek position */
@ -1809,8 +1826,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (seekpos < 0) if (seekpos < 0)
{ {
ndbg("ftpd_offsatoi failed: %d\n", seekpos); ndbg("ftpd_offsatoi failed: %d\n", seekpos);
seekoffs = (off_t)-1; errval = -seekpos;
ret = seekpos;
} }
} }
else else
@ -1819,8 +1835,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (seekpos < 0) if (seekpos < 0)
{ {
ndbg("Bad restartpos: %d\n", seekpos); ndbg("Bad restartpos: %d\n", seekpos);
seekoffs = (off_t)-1; errval = EINVAL;
ret = -EINVAL;
} }
} }
@ -1831,18 +1846,20 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
seekoffs = lseek(session->fd, seekpos, SEEK_SET); seekoffs = lseek(session->fd, seekpos, SEEK_SET);
if (seekoffs < 0) if (seekoffs < 0)
{ {
int errval = errno; errval = errno;
ndbg("lseek failed: %d\n", errval); ndbg("lseek failed: %d\n", errval);
ret = -errval;
} }
} }
/* Report errors */ /* Report errors. If an error occurred, seekoffs will be negative and
* errval will hold the (positive) error code.
*/
if (seekoffs < 0) if (seekoffs < 0)
{ {
(void)ftpd_response(session->cmd.sd, session->txtimeout, (void)ftpd_response(session->cmd.sd, session->txtimeout,
g_respfmt1, 550, ' ', "Can not seek file !"); g_respfmt1, 550, ' ', "Can not seek file !");
ret = -errval;
goto errout_with_session; goto errout_with_session;
} }
@ -1861,6 +1878,8 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
for (;;) for (;;)
{ {
/* Read from the source (file or TCP connection) */
if (session->type == FTPD_SESSIONTYPE_A) if (session->type == FTPD_SESSIONTYPE_A)
{ {
buffer = &session->data.buffer[session->data.buflen >> 2]; buffer = &session->data.buffer[session->data.buflen >> 2];
@ -1874,33 +1893,60 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (cmdtype == 0) if (cmdtype == 0)
{ {
/* Read from the file. Read returns the error condition via errno. */
rdbytes = read(session->fd, session->data.buffer, wantsize); rdbytes = read(session->fd, session->data.buffer, wantsize);
if (rdbytes < 0)
{
errval = errno;
}
} }
else else
{ {
/* Read from the TCP connection, ftpd_recve returns the negated error
* condition.
*/
rdbytes = ftpd_recv(session->data.sd, session->data.buffer, rdbytes = ftpd_recv(session->data.sd, session->data.buffer,
wantsize, session->rxtimeout); wantsize, session->rxtimeout);
if (rdbytes < 0)
{
errval = -rdbytes;
}
} }
/* A negative vaule of rdbytes indicates a read error. errval has the
* (positive) error code associated with the failure.
*/
if (rdbytes < 0) if (rdbytes < 0)
{ {
ndbg("Read failed: rdbytes=%d errno=%d\n", rdbytes, errno); ndbg("Read failed: rdbytes=%d errval=%d\n", rdbytes, errval);
(void)ftpd_response(session->cmd.sd, session->txtimeout, (void)ftpd_response(session->cmd.sd, session->txtimeout,
g_respfmt1, 550, ' ', "Data read error !"); g_respfmt1, 550, ' ', "Data read error !");
ret = rdbytes; ret = -errval;
break; break;
} }
/* A value of rdbytes == 0 means that we have read the entire source
* stream.
*/
if (rdbytes == 0) if (rdbytes == 0)
{ {
/* EOF */ /* End-of-file */
ret = -ECONNRESET;
(void)ftpd_response(session->cmd.sd, session->txtimeout, (void)ftpd_response(session->cmd.sd, session->txtimeout,
g_respfmt1, 226, ' ', "Transfer complete"); g_respfmt1, 226, ' ', "Transfer complete");
/* Return success */
ret = 0;
break; break;
} }
/* Write to the destination (file or TCP connection) */
if (session->type == FTPD_SESSIONTYPE_A) if (session->type == FTPD_SESSIONTYPE_A)
{ {
/* Change to ascii */ /* Change to ascii */
@ -1924,33 +1970,45 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (cmdtype == 0) if (cmdtype == 0)
{ {
/* Write to the TCP connection */
wrbytes = ftpd_send(session->data.sd, buffer, buflen, session->txtimeout); wrbytes = ftpd_send(session->data.sd, buffer, buflen, session->txtimeout);
if (wrbytes < 0) if (wrbytes < 0)
{ {
ndbg("ftpd_send failed: %d\n", wrbytes); errval = -wrbytes;
ret = wrbytes; ndbg("ftpd_send failed: %d\n", errval);
} }
} }
else else
{ {
wrbytes = (ssize_t)write(session->fd, (const void *)buffer, buflen); /* Write to the file */
wrbytes = write(session->fd, buffer, buflen);
if (wrbytes < 0) if (wrbytes < 0)
{ {
int errval = errno; errval = errno;
ndbg("ftpd_send failed: %d\n", errval); ndbg("ftpd_send failed: %d\n", errval);
ret = -errval;
} }
} }
/* If the number of bytes returned by the write is not equal to the
* number that we wanted to write, then an error (or at least an
* unhandled condition) has occurred. errval should should hold
* the (positive) error code.
*/
if (wrbytes != ((ssize_t)buflen)) if (wrbytes != ((ssize_t)buflen))
{ {
ndbg("Write failed: wrbytes=%d errno=%d\n", wrbytes, errno); ndbg("Write failed: wrbytes=%d errval=%d\n", wrbytes, errval);
(void)ftpd_response(session->cmd.sd, session->txtimeout, (void)ftpd_response(session->cmd.sd, session->txtimeout,
g_respfmt1, 550, ' ', "Data send error !"); g_respfmt1, 550, ' ', "Data send error !");
ret = -errval;
break; break;
} }
pos += (off_t)wrbytes; /* Get the next file offset */
pos += (off_t)wrbytes;
} }
errout_with_session:; errout_with_session:;