📄 ftpd.c
字号:
{
if (tran->filehandle >= 0)
{
tran->size = (u32_t) fsys_seek(tran->filehandle, 0, FSSEEK_END);
if ((tran->upload == 0) || (tran->append == 0) ||
(tran->owner->resumePos != 0))
{
fsys_seek(tran->filehandle, (sint_t) tran->owner->resumePos, FSSEEK_SET);
}
}
else
{
tran->size = 0;
}
if (tran->state == TSTATE_GOTPASV)
{
tran->state = TSTATE_WAITONPASV;
}
else
if (tran->state == TSTATE_GOTPORT)
{
tran->state = TSTATE_WAITFORPORT;
connect(tran->sock, (struct sockaddr*)&tran->sin, sizeof(tran->sin));
ft_addSendSocket(tran->sock);
}
tran->starttime = COUNTERVAR;
}
/* Do a directory listing.
* If fulllist is set to 1, a ls -l is performed.
*/
static void ft_doListing(connection_t *conn, char *param, sint_t fulllist)
{
transfer_t *tran = conn->transfer;
char *fn, *c;
sint_t i, ol;
if ((tran == NULL) ||
((tran->state != TSTATE_GOTPASV) &&
(tran->state != TSTATE_GOTPORT)))
{
ft_reply(conn, 425, "No data connection.");
return;
}
fn = NULL;
ol = 0;
for (c = param; *c != 0; c++)
{
while (*c == ' ') c++;
if (c[0] == '-')
{
if (((c[1] == 'l') || (c[1] == 'L')) &&
((c[2] == ' ') || (c[2] == 0)))
{
ol = 1;
c++;
continue;
}
while ((*c != ' ') && (*c != 0)) c++;
}
else
{
if (fn == NULL)
fn = c;
}
}
if (fn == NULL)
{
tran->filename[0] = '*';
tran->filename[1] = 0;
}
else
{
sysStrcpy(tran->filename, fn);
fn = tran->filename;
for (i = 0; (fn[i] != ' ') && (fn[i] != 0); i++);
if ((i > 0) && ((fn[i-1] == '/') || (fn[i-1] == '\\')))
fn[i++] = '*';
fn[i] = 0;
}
if (fulllist)
ol = 1;
if (tran->dirhandle >= 0)
fsys_findclose(tran->dirhandle);
tran->dirhandle = -1;
tran->dirlisting = 1 + ol;
tran->upload = 0;
ft_prepTransfer(tran);
}
/* Get only the filename from the buffer
* (remove the path name).
*/
static void ft_getFilename(connection_t *conn, char *param, char *dst)
{
#if FS_SUBDIRECTORIES
fsys_buildPathName(dst, conn->curpath, param);
#else /* FS_SUBDIRECTORIES */
char *s = param;
char *d = dst;
(void) conn;
while ((*s == '/') || (*s == '\\')) s++;
while (*s != 0)
{
*d = (*s == '\\') ? '/' : *s;
s++;
if ((*d == '/') && (*s == 0))
{
d++;
break;
}
d++;
}
*d = 0;
#endif /* FS_SUBDIRECTORIES */
}
/* Send a numeric and human readable reply to the client.
*/
static void ft_reply(connection_t *conn, u16_t num, const char *fmt, ...)
{
va_list args;
int l;
sprintf(reply_buf_g, "%03u ", num);
va_start(args, fmt);
vsprintf(reply_buf_g+4, fmt, args);
va_end(args);
l = sysStrlen(reply_buf_g);
reply_buf_g[l++] = '\r';
reply_buf_g[l++] = '\n';
conn->lastTrans = COUNTERVAR;
if (send(conn->sock, reply_buf_g, l, 0) < 0)
{
if (sysGetErrno() == EPIPE)
{
ft_destroyConnection(conn);
}
}
}
/* Fill buffer with next line of directory listing
*/
static sint_t ft_getNextDirEntry(transfer_t *tran, char *buf)
{
struct fsys_finddata finfo;
sint_t rc;
char d;
*buf = 0;
if (tran->dirhandle == -2)
return 0;
if (tran->dirhandle < 0)
{
#if FS_SUBDIRECTORIES
if (fsys_buildPathName(fnamebuf_g, tran->owner->curpath,
tran->filename) >= 0)
{
tran->dirhandle = fsys_findfirst(fnamebuf_g, &finfo);
}
#else
tran->dirhandle = fsys_findfirst(tran->filename, &finfo);
#endif
}
else
{
rc = fsys_findnext(tran->dirhandle, &finfo);
if (rc < 0)
{
return 0;
}
}
if (tran->dirhandle >= 0)
{
if (tran->dirlisting == 2)
{
/* long directory listing */
d = (finfo.attrib & FSA_SUBDIR) ? 'd' : '-';
if (finfo.attrib & FSA_RDONLY)
{
sprintf(buf + sysStrlen(buf),
"%cr--r--r-- 1 ftp root ", d);
}
else
{
sprintf(buf + sysStrlen(buf),
"%crw-rw-rw- 1 ftp root ", d);
}
sprintf(buf + sysStrlen(buf), "%8lu ", (unsigned long) finfo.size);
#if 0
sprintf(buf + sysStrlen(buf), "%s %2u %04u ",
month_g[finfo.time.month],
(uint_t) finfo.time.day, (uint_t) finfo.time.year);
#else
sprintf(buf + sysStrlen(buf), "%s %2u %02u:%02u ",
month_g[finfo.time.month],
(uint_t) finfo.time.day,
(uint_t) finfo.time.hour, (uint_t) finfo.time.min);
#endif
}
sysStrcat(buf, finfo.name);
sysStrcat(buf, "\r\n");
}
else
{
tran->dirhandle = -2;
}
return sysStrlen(buf);
}
/*---------------------------------------------------------------------------
* CONNECTION HANDLING
*-------------------------------------------------------------------------*/
/* Add a socket to the global socket send set.
*/
static sint_t ft_addSendSocket(const int sock)
{
if (sock >= 0)
{
FD_CLR(sock, &globalSocketSendSet);
FD_SET(sock, &globalSocketSendSet);
return 0;
}
return -1;
}
/* Add a socket to the global socket set.
*/
static sint_t ft_addSocket(const int sock)
{
if (sock >= 0)
{
FD_CLR(sock, &globalSocketSet);
FD_SET(sock, &globalSocketSet);
return 0;
}
return -1;
}
/* Remove socket from fdsets and close it.
*/
static void ft_delSocket(const int sock)
{
if (sock >= 0)
{
FD_CLR(sock, &globalSocketSet);
FD_CLR(sock, &globalSocketSendSet);
closesocket(sock);
}
}
/*-------------------------------------------------------------------------*/
/* Insert an element to the tail of a double linked list.
*/
static void ft_listAddTail(lelem_t *headelem, lelem_t *elem)
{
elem->prev = headelem->prev;
elem->next = headelem;
headelem->prev->next = elem;
headelem->prev = elem;
}
/* Insert an element to the head of a double linked list.
*/
static void ft_listAddHead(lelem_t *headelem, lelem_t *elem)
{
elem->next = headelem->next;
elem->prev = headelem;
headelem->next->prev = elem;
headelem->next = elem;
}
/* Remove an element from a double linked list
* and free its memory.
*/
static void ft_listDel(lelem_t *elem)
{
lelem_t *next = elem->next;
lelem_t *prev = elem->prev;
next->prev = prev;
prev->next = next;
}
/*-------------------------------------------------------------------------*/
/* Create and initialize a new connection structure.
* On success, the connection is established and a 220 status is sent.
*/
static sint_t ft_newConnection(int socket)
{
unsigned long one = 1;
connection_t *conn;
if ((socket != -1) &&
((open_connections_g >= FTP_MAXCON) ||
(open_connections_g >= FD_SETSIZE)))
{
/* too many connections opened */
send(socket, "221 Maximum number of connections established, "
"try later again.\r\n", 65, 0);
return -1;
}
conn = (connection_t *)(sysMemAlloc(sizeof(connection_t)));
if (conn == NULL)
return -1;
conn->transfer = NULL;
conn->sock = socket;
conn->buflen = 0;
conn->auth = 0;
conn->resumePos = 0;
conn->renfrom[0] = 0;
conn->lastTrans = COUNTERVAR;
#if FS_SUBDIRECTORIES
conn->curpath[0] = 0;
#endif
/* set nonblocking mode */
ioctlsocket(socket, FIONBIO, (void*)&one);
/* add socket and connection to list of active connections */
ft_addSocket(socket);
ft_listAddTail(&connListRoot_g, (lelem_t*)(void*)conn);
open_connections_g++;
ft_reply(conn, 220, "Connection established, FTPD ready.");
return 0;
}
/* Create and initialize a new filetransfer structure.
*/
static transfer_t *ft_newTransfer(int socket, connection_t *conn)
{
transfer_t *tran;
tran = (transfer_t *)(sysMemAlloc(sizeof(transfer_t)));
if (tran == NULL)
return NULL;
tran->owner = conn;
tran->sock = socket;
tran->state = TSTATE_NONE;
tran->dlbufpos = 0;
tran->dlbufremain = 0;
tran->filehandle = -1;
tran->dirhandle = -1;
tran->dirlisting = 0;
tran->wrDisabled = 0;
ft_listAddTail(&transfListRoot_g, (lelem_t*)(void*)tran);
return tran;
}
/* Destroys a ctrl connection and
* cleans up the connection structure.
*/
static void ft_destroyConnection(connection_t *conn)
{
if (conn == NULL)
return;
if ((conn->sock >= 0) && (open_connections_g > 0))
{
open_connections_g--;
}
ft_delSocket(conn->sock);
ft_destroyTransfer(conn->transfer);
ft_listDel((lelem_t*)(void*)conn);
sysMemFree(conn);
}
/* Destroys a data connection and
* cleans up the connection structure.
*/
static void ft_destroyTransfer(transfer_t *tran)
{
#if defined(TCP_CORK) && defined(SOL_TCP)
unsigned long zero = 0;
#endif
if (tran == NULL)
return;
if (tran->sock >= 0)
{
#if defined(TCP_CORK) && defined(SOL_TCP)
/* ensure that all data is flushed out when closing the socket */
setsockopt(tran->sock, SOL_TCP, TCP_CORK, (void *)&zero, sizeof(zero));
#endif
ft_delSocket(tran->sock);
}
if (tran->filehandle != -1)
{
fsys_close(tran->filehandle);
}
if (tran->dirhandle != -1)
{
fsys_findclose(tran->dirhandle);
}
if (tran->owner != NULL)
{
tran->owner->transfer = NULL;
}
if (tran->wrDisabled != 0)
{
blockedTrans_g--;
}
ft_listDel((lelem_t*)(void*)tran);
sysMemFree(tran);
}
/*-------------------------------------------------------------------------*/
/* This function processes all open control connections.
* If data was received over the connection, it is
* passed to the command line parser.
*/
static sint_t ft_processCtrlConnections(fd_set *clientset, int fdcount)
{
connection_t *conn, *next;
sint_t checked;
int bytes;
next = FIRST_LIST_ELEM(&connListRoot_g, connection_t*);
checked = 0;
/* process all connections in the list */
while (!END_OF_LIST(&connListRoot_g, next) && (checked < fdcount))
{
conn = next;
next = NEXT_LIST_ELEM(conn, connection_t*);
if (!FD_ISSET(conn->sock, clientset))
{
continue;
}
checked++;
bytes = recv(conn->sock, conn->rxbuffer + conn->buflen,
(FTP_INPBUFSIZE-1) - conn->buflen, 0);
if (bytes <= 0)
{
/* If no bytes are available or -1 is returned,
* the client must have closed the connection since
* select told us that there was something with the socket.
*/
ft_destroyConnection(conn);
continue;
}
/* safety check: buffer overrun (should never happen) */
if ((conn->buflen + (u16_t) bytes) >= (FTP_INPBUFSIZE-1))
{
ft_reply(conn, 500, "Buffer error, connection shut down.");
ft_destroyConnection(conn);
continue;
}
conn->buflen += (u16_t) bytes;
conn->lastTrans = COUNTERVAR;
ft_execCommand(conn);
}
return checked;
}
/* Do a data connection upload.
*/
static sint_t ft_handleUpload(transfer_t *tran)
{
int size;
tran->owner->lastTrans = COUNTERVAR;
size = recv(tran->sock, upload_buf_g, UPLOADBUF_SIZE, 0);
if (size > 0)
{
tran->pos += (u32_t) size;
if (fsys_write(tran->filehandle, upload_buf_g, (sint_t) size) == size)
{
return 1;
}
}
else
if (size == 0)
{
return 0;
}
ft_abortTransfer(tran->owner);
return 1;
}
/* Do a data connection download.
*/
static sint_t ft_handleDownload(transfer_t *tran)
{
#if defined(TCP_CORK) && defined(SOL_TCP)
unsigned long zero = 0;
#endif
sint_t moreToSend = 0;
int bytes, size;
/* fill buffer */
if (tran->dlbufremain == 0)
{
tran->dlbufpos = 0;
if (tran->dirlisting)
{
bytes = ft_getNextDirEntry(tran, tran->dlbuf);
}
else
{
bytes = fsys_read(tran->filehandle, tran->dlbuf, MAX_BLOCKSIZE);
}
if (bytes >= MAX_BLOCKSIZE)
{
moreToSend = 1;
}
if (bytes > 0)
{
if (bytes > MAX_BLOCKSIZE)
bytes = MAX_BLOCKSIZE;
tran->dlbufremain = (u16_t) bytes;
}
}
/* send data */
if (tran->dlbufremain != 0)
{
#if defined(TCP_CORK) && defined(SOL_TCP)
/* flush buffer if we believe we send the last block */
if (moreToSend == 0)
{
setsockopt(tran->sock, SOL_TCP, TCP_CORK, (void*)&zero, sizeof(zero));
}
#endif
size = send(tran->sock, tran->dlbuf + tran->dlbufpos,
tran->dlbufremain, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -