Fixes all known FTP server bugs

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4398 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2012-02-15 23:37:37 +00:00
parent a2e2f34390
commit 4d73d93489
1 changed files with 80 additions and 22 deletions

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);
if (ret < 0)
{
ssize_t errval = errno;
ndbg("recv() failed: %d\n", errval);
return -errval;
int errval = errno;
/* 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;
@ -1716,6 +1732,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
ssize_t rdbytes;
ssize_t wrbytes;
off_t pos = 0;
int errval = 0;
int ret;
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)
{
off_t seekoffs;
off_t seekoffs = (off_t)-1;
off_t seekpos;
/* Get the seek position */
@ -1809,8 +1826,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (seekpos < 0)
{
ndbg("ftpd_offsatoi failed: %d\n", seekpos);
seekoffs = (off_t)-1;
ret = seekpos;
errval = -seekpos;
}
}
else
@ -1819,8 +1835,7 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (seekpos < 0)
{
ndbg("Bad restartpos: %d\n", seekpos);
seekoffs = (off_t)-1;
ret = -EINVAL;
errval = EINVAL;
}
}
@ -1831,18 +1846,20 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
seekoffs = lseek(session->fd, seekpos, SEEK_SET);
if (seekoffs < 0)
{
int errval = errno;
errval = errno;
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)
{
(void)ftpd_response(session->cmd.sd, session->txtimeout,
g_respfmt1, 550, ' ', "Can not seek file !");
ret = -errval;
goto errout_with_session;
}
@ -1861,6 +1878,8 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
for (;;)
{
/* Read from the source (file or TCP connection) */
if (session->type == FTPD_SESSIONTYPE_A)
{
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)
{
/* Read from the file. Read returns the error condition via errno. */
rdbytes = read(session->fd, session->data.buffer, wantsize);
if (rdbytes < 0)
{
errval = errno;
}
}
else
{
/* Read from the TCP connection, ftpd_recve returns the negated error
* condition.
*/
rdbytes = ftpd_recv(session->data.sd, session->data.buffer,
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)
{
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,
g_respfmt1, 550, ' ', "Data read error !");
ret = rdbytes;
ret = -errval;
break;
}
/* A value of rdbytes == 0 means that we have read the entire source
* stream.
*/
if (rdbytes == 0)
{
/* EOF */
/* End-of-file */
ret = -ECONNRESET;
(void)ftpd_response(session->cmd.sd, session->txtimeout,
g_respfmt1, 226, ' ', "Transfer complete");
/* Return success */
ret = 0;
break;
}
/* Write to the destination (file or TCP connection) */
if (session->type == FTPD_SESSIONTYPE_A)
{
/* Change to ascii */
@ -1924,33 +1970,45 @@ static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
if (cmdtype == 0)
{
/* Write to the TCP connection */
wrbytes = ftpd_send(session->data.sd, buffer, buflen, session->txtimeout);
if (wrbytes < 0)
{
ndbg("ftpd_send failed: %d\n", wrbytes);
ret = wrbytes;
errval = -wrbytes;
ndbg("ftpd_send failed: %d\n", errval);
}
}
else
{
wrbytes = (ssize_t)write(session->fd, (const void *)buffer, buflen);
/* Write to the file */
wrbytes = write(session->fd, buffer, buflen);
if (wrbytes < 0)
{
int errval = errno;
errval = errno;
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))
{
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,
g_respfmt1, 550, ' ', "Data send error !");
ret = -errval;
break;
}
pos += (off_t)wrbytes;
/* Get the next file offset */
pos += (off_t)wrbytes;
}
errout_with_session:;