![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
A quick and dirty FTP server port to mbed, for file i/o ops via LwIP stack.
Revision 0:c9ac16a7dfb4, committed 2010-11-30
- Comitter:
- Airman50
- Date:
- Tue Nov 30 00:45:55 2010 +0000
- Commit message:
- Pre Alpha release.
Changed in this revision
diff -r 000000000000 -r c9ac16a7dfb4 NetFtp/ftpd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetFtp/ftpd.c Tue Nov 30 00:45:55 2010 +0000 @@ -0,0 +1,1478 @@ +/* + * Copyright (c) 2002 Florian Schulze. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the authors nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * ftpd.c - This file is part of the FTP daemon for lwIP + * + */ + +#include "mbed.h" // DRB +#include "SDFileSystem.h" // DRB +#include "EthernetNetIf.h" +#include "HTTPServer.h" + +#include "lwip/debug.h" + +#include "lwip/stats.h" + +#include "ftpd.h" + +#include "lwip/tcp.h" + +#include <stdio.h> +#include <stdarg.h> +//..#include <malloc.h> +#ifdef _WIN32 +#include <string.h> +#endif +#include <ctype.h> +#include <errno.h> +#include <time.h> + +#include "vfs.h" +} + + +extern void printit( char *p_buf ); + + +#ifdef FTPD_DEBUG +int dbg_printf(const char *fmt, ...); +#else +#ifdef _MSC_VER +#define dbg_printf(x) /* x */ +#else +#define dbg_printf(f, ...) /* */ +#endif +#endif + +#define msg110 "110 MARK %s = %s." +/* + 110 Restart marker reply. + In this case, the text is exact and not left to the + particular implementation; it must read: + MARK yyyy = mmmm + Where yyyy is User-process data stream marker, and mmmm + server's equivalent marker (note the spaces between markers + and "="). +*/ +#define msg120 "120 Service ready in nnn minutes." +#define msg125 "125 Data connection already open; transfer starting." +#define msg150 "150 File status okay; about to open data connection." +#define msg150recv "150 Opening BINARY mode data connection for %s (%i bytes)." +#define msg150stor "150 Opening BINARY mode data connection for %s." +#define msg200 "200 Command okay." +#define msg202 "202 Command not implemented, superfluous at this site." +#define msg211 "211 System status, or system help reply." +#define msg212 "212 Directory status." +#define msg213 "213 File status." +#define msg214 "214 %s." +/* + 214 Help message. + On how to use the server or the meaning of a particular + non-standard command. This reply is useful only to the + human user. +*/ +#define msg214SYST "214 %s system type." +/* + 215 NAME system type. + Where NAME is an official system name from the list in the + Assigned Numbers document. +*/ +#define msg220 "220 lwIP FTP Server ready." +/* + 220 Service ready for new user. +*/ +#define msg221 "221 Goodbye." +/* + 221 Service closing control connection. + Logged out if appropriate. +*/ +#define msg225 "225 Data connection open; no transfer in progress." +#define msg226 "226 Closing data connection." +/* + Requested file action successful (for example, file + transfer or file abort). +*/ +#define msg227 "227 Entering Passive Mode (%i,%i,%i,%i,%i,%i)." +/* + 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). +*/ +#define msg230 "230 User logged in, proceed." +#define msg250 "250 Requested file action okay, completed." +#define msg257PWD "257 \"%s\" is current directory." +#define msg257 "257 \"%s\" created." +/* + 257 "PATHNAME" created. +*/ +#define msg331 "331 User name okay, need password." +#define msg332 "332 Need account for login." +#define msg350 "350 Requested file action pending further information." +#define msg421 "421 Service not available, closing control connection." +/* + This may be a reply to any command if the service knows it + must shut down. +*/ +#define msg425 "425 Can't open data connection." +#define msg426 "426 Connection closed; transfer aborted." +#define msg450 "450 Requested file action not taken." +/* + File unavailable (e.g., file busy). +*/ +#define msg451 "451 Requested action aborted: local error in processing." +#define msg452 "452 Requested action not taken." +/* + Insufficient storage space in system. +*/ +#define msg500 "500 Syntax error, command unrecognized." +/* + This may include errors such as command line too long. +*/ +#define msg501 "501 Syntax error in parameters or arguments." +#define msg502 "502 Command not implemented." +#define msg503 "503 Bad sequence of commands." +#define msg504 "504 Command not implemented for that parameter." +#define msg530 "530 Not logged in." +#define msg532 "532 Need account for storing files." +#define msg550 "550 Requested action not taken." +/* + File unavailable (e.g., file not found, no access). +*/ +#define msg551 "551 Requested action aborted: page type unknown." +#define msg552 "552 Requested file action aborted." +/* + Exceeded storage allocation (for current directory or + dataset). +*/ +#define msg553 "553 Requested action not taken." +/* + File name not allowed. +*/ + +enum ftpd_state_e { + FTPD_USER, + FTPD_PASS, + FTPD_IDLE, + FTPD_NLST, + FTPD_LIST, + FTPD_RETR, + FTPD_RNFR, + FTPD_STOR, + FTPD_QUIT +}; + +static const char *month_table[12] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dez" +}; + +/* +------------------------------------------------------------ + SFIFO 1.3 +------------------------------------------------------------ + * Simple portable lock-free FIFO + * (c) 2000-2002, David Olofson + * + * Platform support: + * gcc / Linux / x86: Works + * gcc / Linux / x86 kernel: Works + * gcc / FreeBSD / x86: Works + * gcc / NetBSD / x86: Works + * gcc / Mac OS X / PPC: Works + * gcc / Win32 / x86: Works + * Borland C++ / DOS / x86RM: Works + * Borland C++ / Win32 / x86PM16: Untested + * ? / Various Un*ces / ?: Untested + * ? / Mac OS / PPC: Untested + * gcc / BeOS / x86: Untested + * gcc / BeOS / PPC: Untested + * ? / ? / Alpha: Untested + * + * 1.2: Max buffer size halved, to avoid problems with + * the sign bit... + * + * 1.3: Critical buffer allocation bug fixed! For certain + * requested buffer sizes, older version would + * allocate a buffer of insufficient size, which + * would result in memory thrashing. (Amazing that + * I've manage to use this to the extent I have + * without running into this... *heh*) + */ + +/* + * Porting note: + * Reads and writes of a variable of this type in memory + * must be *atomic*! 'int' is *not* atomic on all platforms. + * A safe type should be used, and sfifo should limit the + * maximum buffer size accordingly. + */ +typedef int sfifo_atomic_t; +#ifdef __TURBOC__ +# define SFIFO_MAX_BUFFER_SIZE 0x7fff +#else /* Kludge: Assume 32 bit platform */ +# define SFIFO_MAX_BUFFER_SIZE 0x7fffffff +#endif + +typedef struct sfifo_t +{ + char *buffer; + int size; /* Number of bytes */ + sfifo_atomic_t readpos; /* Read position */ + sfifo_atomic_t writepos; /* Write position */ +} sfifo_t; + +#define SFIFO_SIZEMASK(x) ((x)->size - 1) + +#define sfifo_used(x) (((x)->writepos - (x)->readpos) & SFIFO_SIZEMASK(x)) +#define sfifo_space(x) ((x)->size - 1 - sfifo_used(x)) + +//..DRB #define DBG(x) + +/* + * Alloc buffer, init FIFO etc... + */ +static int sfifo_init(sfifo_t *f, int size) +{ + memset(f, 0, sizeof(sfifo_t)); + + if(size > SFIFO_MAX_BUFFER_SIZE) + return -EINVAL; + + /* + * Set sufficient power-of-2 size. + * + * No, there's no bug. If you need + * room for N bytes, the buffer must + * be at least N+1 bytes. (The fifo + * can't tell 'empty' from 'full' + * without unsafe index manipulations + * otherwise.) + */ + f->size = 1; + for(; f->size <= size; f->size <<= 1) + ; + + /* Get buffer */ + if( 0 == (f->buffer = (char *)malloc(f->size)) ) + return -ENOMEM; + + return 0; +} + +/* + * Dealloc buffer etc... + */ +static void sfifo_close(sfifo_t *f) +{ + if(f->buffer) + free(f->buffer); +} + +/* + * Empty FIFO buffer + */ +static void sfifo_flush(sfifo_t *f) +{ + /* Reset positions */ + f->readpos = 0; + f->writepos = 0; +} + +/* + * Write bytes to a FIFO + * Return number of bytes written, or an error code + */ +static int sfifo_write(sfifo_t *f, const void *_buf, int len) +{ + int total; + int i; + const char *buf = (const char *)_buf; + + if(!f->buffer) + return -ENODEV; /* No buffer! */ + + /* total = len = min(space, len) */ + total = sfifo_space(f); + DBG(dbg_printf("sfifo_space() = %d\n",total)); + if(len > total) + len = total; + else + total = len; + + i = f->writepos; + if(i + len > f->size) + { + memcpy(f->buffer + i, buf, f->size - i); + buf += f->size - i; + len -= f->size - i; + i = 0; + } + memcpy(f->buffer + i, buf, len); + f->writepos = i + len; + + return total; +} + +/* + * Read bytes from a FIFO + * Return number of bytes read, or an error code + */ +static int sfifo_read(sfifo_t *f, void *_buf, int len) +{ + int total; + int i; + char *buf = (char *)_buf; + + if(!f->buffer) + return -ENODEV; /* No buffer! */ + + /* total = len = min(used, len) */ + total = sfifo_used(f); + DBG(dbg_printf("sfifo_used() = %d\n",total)); + if(len > total) + len = total; + else + total = len; + + i = f->readpos; + if(i + len > f->size) + { + memcpy(buf, f->buffer + i, f->size - i); + buf += f->size - i; + len -= f->size - i; + i = 0; + } + memcpy(buf, f->buffer + i, len); + f->readpos = i + len; + + return total; +} + +struct ftpd_datastate { + int connected; + vfs_dir_t *vfs_dir; + vfs_dirent_t *vfs_dirent; + vfs_file_t *vfs_file; + sfifo_t fifo; + struct tcp_pcb *msgpcb; + struct ftpd_msgstate *msgfs; +}; + +struct ftpd_msgstate { + enum ftpd_state_e state; + sfifo_t fifo; + vfs_t *vfs; + struct ip_addr dataip; + u16_t dataport; + struct tcp_pcb *datapcb; + struct ftpd_datastate *datafs; + int passive; + char *renamefrom; +}; + +static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg, ...); + +static void ftpd_dataerr(void *arg, err_t err) +{ + struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg; + + dbg_printf("ftpd_dataerr: %s (%i)\n", lwip_strerr(err), err); + if (fsd == NULL) + return; + fsd->msgfs->datafs = NULL; + fsd->msgfs->state = FTPD_IDLE; + free(fsd); +} + +static void ftpd_dataclose(struct tcp_pcb *pcb, struct ftpd_datastate *fsd) +{ + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); + fsd->msgfs->datafs = NULL; + sfifo_close(&fsd->fifo); + free(fsd); + tcp_arg(pcb, NULL); + tcp_close(pcb); +} + +static void send_data(struct tcp_pcb *pcb, struct ftpd_datastate *fsd) +{ + err_t err; + u16_t len; + + if (sfifo_used(&fsd->fifo) > 0) { + int i; + + /* We cannot send more data than space available in the send + buffer. */ + if (tcp_sndbuf(pcb) < sfifo_used(&fsd->fifo)) { + len = tcp_sndbuf(pcb); + } else { + len = (u16_t) sfifo_used(&fsd->fifo); + } + + i = fsd->fifo.readpos; + if ((i + len) > fsd->fifo.size) { + err = tcp_write(pcb, fsd->fifo.buffer + i, (u16_t)(fsd->fifo.size - i), 1); + if (err != ERR_OK) { + dbg_printf("send_data: error writing!\n"); + return; + } + len -= fsd->fifo.size - i; + fsd->fifo.readpos = 0; + i = 0; + } + + err = tcp_write(pcb, fsd->fifo.buffer + i, len, 1); + if (err != ERR_OK) { + dbg_printf("send_data: error writing!\n"); + return; + } + fsd->fifo.readpos += len; + } +} + +static void send_file( struct ftpd_datastate *fsd, struct tcp_pcb *pcb ) +{ + if (!fsd->connected) + return; + + if (fsd->vfs_file) + { + char buffer[ 2048 ]; + int len; + + len = sfifo_space( &fsd->fifo ); + if (len == 0) + { + send_data(pcb, fsd); + return; + } + if (len > 2048) + len = 2048; + len = vfs_read( buffer, 1, len, fsd->vfs_file ); + if( len == 0 ) + { + if( vfs_eof( fsd->vfs_file ) == 0) + return; + vfs_close( fsd->vfs_file ); + fsd->vfs_file = NULL; + return; + } + sfifo_write( &fsd->fifo, buffer, len ); + send_data( pcb, fsd ); + } else { + struct ftpd_msgstate *fsm; + struct tcp_pcb *msgpcb; + + if (sfifo_used(&fsd->fifo) > 0) { + send_data(pcb, fsd); + return; + } + fsm = fsd->msgfs; + msgpcb = fsd->msgpcb; + + vfs_close( fsd->vfs_file ); + fsd->vfs_file = NULL; + ftpd_dataclose( pcb, fsd ); + fsm->datapcb = NULL; + fsm->datafs = NULL; + fsm->state = FTPD_IDLE; + send_msg( msgpcb, fsm, msg226 ); +// printit( msg226 ); + return; + } +} + +static void send_next_directory(struct ftpd_datastate *fsd, struct tcp_pcb *pcb, int shortlist) +{ + char buffer[1024]; + int len; + + while (1) { + if (fsd->vfs_dirent == NULL) + fsd->vfs_dirent = vfs_readdir(fsd->vfs_dir); + + if (fsd->vfs_dirent) { + if (shortlist) { + len = sprintf(buffer, "%s\r\n", fsd->vfs_dirent->name); + if (sfifo_space(&fsd->fifo) < len) { + send_data(pcb, fsd); + return; + } + sfifo_write(&fsd->fifo, buffer, len); + fsd->vfs_dirent = NULL; + } else { + vfs_stat_t st; + time_t current_time; + int current_year; + struct tm *s_time; + + time(¤t_time); + s_time = gmtime(¤t_time); + current_year = s_time->tm_year; + +//..DRB vfs_stat(fsd->msgfs->vfs, fsd->vfs_dirent->name, &st); + s_time = gmtime(&st.st_mtime); + if (s_time->tm_year == current_year) + len = sprintf(buffer, "-rw-rw-rw- 1 user ftp %11ld %s %02i %02i:%02i %s\r\n", st.st_size, month_table[s_time->tm_mon], s_time->tm_mday, s_time->tm_hour, s_time->tm_min, fsd->vfs_dirent->name); + else + len = sprintf(buffer, "-rw-rw-rw- 1 user ftp %11ld %s %02i %5i %s\r\n", st.st_size, month_table[s_time->tm_mon], s_time->tm_mday, s_time->tm_year + 1900, fsd->vfs_dirent->name); + if (VFS_ISDIR(st.st_mode)) + buffer[0] = 'd'; + if (sfifo_space(&fsd->fifo) < len) { + send_data(pcb, fsd); + return; + } + sfifo_write(&fsd->fifo, buffer, len); + fsd->vfs_dirent = NULL; + } + } else { + struct ftpd_msgstate *fsm; + struct tcp_pcb *msgpcb; + + if (sfifo_used(&fsd->fifo) > 0) { + send_data(pcb, fsd); + return; + } + fsm = fsd->msgfs; + msgpcb = fsd->msgpcb; + + vfs_closedir(fsd->vfs_dir); + fsd->vfs_dir = NULL; + ftpd_dataclose(pcb, fsd); + fsm->datapcb = NULL; + fsm->datafs = NULL; + fsm->state = FTPD_IDLE; + send_msg(msgpcb, fsm, msg226); + return; + } + } +} + +static err_t ftpd_datasent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg; + + switch (fsd->msgfs->state) { + case FTPD_LIST: + send_next_directory(fsd, pcb, 0); + break; + case FTPD_NLST: + send_next_directory(fsd, pcb, 1); + break; + case FTPD_RETR: + send_file(fsd, pcb); + break; + default: + break; + } + + return ERR_OK; +} + +static err_t ftpd_datarecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg; + + if (err == ERR_OK && p != NULL) { + struct pbuf *q; + u16_t tot_len = 0; + + for (q = p; q != NULL; q = q->next) { + int len; + + len = vfs_write(q->payload, 1, q->len, fsd->vfs_file); + tot_len += len; + if (len != q->len) + break; + } + + /* Inform TCP that we have taken the data. */ + tcp_recved(pcb, tot_len); + + pbuf_free(p); + } + if (err == ERR_OK && p == NULL) { + struct ftpd_msgstate *fsm; + struct tcp_pcb *msgpcb; + + fsm = fsd->msgfs; + msgpcb = fsd->msgpcb; + + vfs_close(fsd->vfs_file); + fsd->vfs_file = NULL; + ftpd_dataclose(pcb, fsd); + fsm->datapcb = NULL; + fsm->datafs = NULL; + fsm->state = FTPD_IDLE; + send_msg(msgpcb, fsm, msg226); + } + + return ERR_OK; +} + +static err_t ftpd_dataconnected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg; + + fsd->msgfs->datapcb = pcb; + fsd->connected = 1; + + /* Tell TCP that we wish to be informed of incoming data by a call + to the http_recv() function. */ + tcp_recv(pcb, ftpd_datarecv); + + /* Tell TCP that we wish be to informed of data that has been + successfully sent by a call to the ftpd_sent() function. */ + tcp_sent(pcb, ftpd_datasent); + + tcp_err(pcb, ftpd_dataerr); + + switch (fsd->msgfs->state) { + case FTPD_LIST: + send_next_directory(fsd, pcb, 0); + break; + case FTPD_NLST: + send_next_directory(fsd, pcb, 1); + break; + case FTPD_RETR: + send_file(fsd, pcb); + break; + default: + break; + } + + return ERR_OK; +} + +static err_t ftpd_dataaccept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg; + + fsd->msgfs->datapcb = pcb; + fsd->connected = 1; + + /* Tell TCP that we wish to be informed of incoming data by a call + to the http_recv() function. */ + tcp_recv(pcb, ftpd_datarecv); + + /* Tell TCP that we wish be to informed of data that has been + successfully sent by a call to the ftpd_sent() function. */ + tcp_sent(pcb, ftpd_datasent); + + tcp_err(pcb, ftpd_dataerr); + + switch (fsd->msgfs->state) { + case FTPD_LIST: + send_next_directory(fsd, pcb, 0); + break; + case FTPD_NLST: + send_next_directory(fsd, pcb, 1); + break; + case FTPD_RETR: + send_file(fsd, pcb); + break; + default: + break; + } + + return ERR_OK; +} + +static int open_dataconnection(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (fsm->passive) + return 0; + + /* Allocate memory for the structure that holds the state of the connection. */ + fsm->datafs = (struct ftpd_datastate*)malloc(sizeof(struct ftpd_datastate)); + + if (fsm->datafs == NULL) { + send_msg(pcb, fsm, msg451); + return 1; + } + memset(fsm->datafs, 0, sizeof(struct ftpd_datastate)); + fsm->datafs->msgfs = fsm; + fsm->datafs->msgpcb = pcb; + sfifo_init(&fsm->datafs->fifo, 2000); + + fsm->datapcb = tcp_new(); + tcp_bind(fsm->datapcb, &pcb->local_ip, 20); + /* Tell TCP that this is the structure we wish to be passed for our + callbacks. */ + tcp_arg(fsm->datapcb, fsm->datafs); + tcp_connect(fsm->datapcb, &fsm->dataip, fsm->dataport, ftpd_dataconnected); + + return 0; +} + +static void cmd_user(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + send_msg(pcb, fsm, msg331); + fsm->state = FTPD_PASS; + /* + send_msg(pcb, fs, msgLoginFailed); + fs->state = FTPD_QUIT; + */ +} + +static void cmd_pass(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + send_msg(pcb, fsm, msg230); + fsm->state = FTPD_IDLE; + /* + send_msg(pcb, fs, msgLoginFailed); + fs->state = FTPD_QUIT; + */ +} + +static void cmd_port(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + int nr; + unsigned pHi, pLo; + unsigned ip[4]; + + nr = sscanf(arg, "%u,%u,%u,%u,%u,%u", &(ip[0]), &(ip[1]), &(ip[2]), &(ip[3]), &pHi, &pLo); + if (nr != 6) { + send_msg(pcb, fsm, msg501); + } else { + IP4_ADDR(&fsm->dataip, (u8_t) ip[0], (u8_t) ip[1], (u8_t) ip[2], (u8_t) ip[3]); + fsm->dataport = ((u16_t) pHi << 8) | (u16_t) pLo; + send_msg(pcb, fsm, msg200); + } +} + +static void cmd_quit(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + send_msg(pcb, fsm, msg221); + fsm->state = FTPD_QUIT; +} + +static void cmd_cwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (!vfs_chdir(fsm->vfs, arg)) { + send_msg(pcb, fsm, msg250); + } else { + send_msg(pcb, fsm, msg550); + } +} + +static void cmd_cdup(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (!vfs_chdir(fsm->vfs, "..")) { + send_msg(pcb, fsm, msg250); + } else { + send_msg(pcb, fsm, msg550); + } +} + +static void cmd_pwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + char *path; + + path = vfs_getcwd( fsm->vfs, NULL, 0 ); + if( path ) + { + send_msg(pcb, fsm, msg257PWD, path); + free(path); + } +} + +static void cmd_list_common(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, int shortlist) +{ + vfs_dir_t *vfs_dir; + char *cwd; + +#if 0 + cwd = vfs_getcwd(fsm->vfs, NULL, 0); + if ((!cwd)) { + send_msg(pcb, fsm, msg451); + return; + } +#endif + vfs_dir = vfs_opendir(fsm->vfs, cwd); + free(cwd); + if (!vfs_dir) { + send_msg(pcb, fsm, msg451); + return; + } + + if( open_dataconnection(pcb, fsm) != 0) + { + vfs_closedir(vfs_dir); + return; + } + + fsm->datafs->vfs_dir = vfs_dir; + fsm->datafs->vfs_dirent = NULL; + if (shortlist != 0) + { + fsm->state = FTPD_NLST; + } + else + { + fsm->state = FTPD_LIST; + } + send_msg(pcb, fsm, msg150); +} + + +static void cmd_nlst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + cmd_list_common(arg, pcb, fsm, 1); +} + +static void cmd_list(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + cmd_list_common(arg, pcb, fsm, 0); +} + +static void cmd_retr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + vfs_file_t *vfs_file; + vfs_stat_t st; + +#if 0 + vfs_stat(fsm->vfs, arg, &st); + if (!VFS_ISREG(st.st_mode)) + { + send_msg(pcb, fsm, msg550); + return; + } +#endif + vfs_file = vfs_open(fsm->vfs, arg, "rb"); + if (!vfs_file) { + send_msg(pcb, fsm, msg550); + return; + } + + send_msg(pcb, fsm, msg150recv, arg, st.st_size); + + if (open_dataconnection(pcb, fsm) != 0) { + vfs_close(vfs_file); + return; + } + + fsm->datafs->vfs_file = vfs_file; + fsm->state = FTPD_RETR; +} + +static void cmd_stor(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + vfs_file_t *vfs_file; + + vfs_file = vfs_open(fsm->vfs, arg, "wb"); + if (!vfs_file) { + send_msg(pcb, fsm, msg550); + return; + } + + send_msg(pcb, fsm, msg150stor, arg); + + if (open_dataconnection(pcb, fsm) != 0) { + vfs_close(vfs_file); + return; + } + + fsm->datafs->vfs_file = vfs_file; + fsm->state = FTPD_STOR; +} + +static void cmd_noop(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + send_msg(pcb, fsm, msg200); +} + +static void cmd_syst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + send_msg(pcb, fsm, msg214SYST, "UNIX"); +} + +static void cmd_pasv(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + static u16_t port = 4096; + static u16_t start_port = 4096; + struct tcp_pcb *temppcb; + + /* Allocate memory for the structure that holds the state of the connection. */ + fsm->datafs = (struct ftpd_datastate*)malloc(sizeof(struct ftpd_datastate)); + + if (fsm->datafs == NULL) { + send_msg(pcb, fsm, msg451); + return; + } + memset(fsm->datafs, 0, sizeof(struct ftpd_datastate)); + + fsm->datapcb = tcp_new(); + if (!fsm->datapcb) { + free(fsm->datafs); + send_msg(pcb, fsm, msg451); + return; + } + + sfifo_init(&fsm->datafs->fifo, 2000); + + start_port = port; + + while (1) { + err_t err; + + if(++port > 0x7fff) + port = 4096; + + fsm->dataport = port; + err = tcp_bind(fsm->datapcb, &pcb->local_ip, fsm->dataport); + if (err == ERR_OK) + break; + if (start_port == port) + err = ERR_CLSD; + if (err == ERR_USE) + continue; + if (err != ERR_OK) { + ftpd_dataclose(fsm->datapcb, fsm->datafs); + fsm->datapcb = NULL; + fsm->datafs = NULL; + return; + } + } + + temppcb = tcp_listen(fsm->datapcb); + if (!temppcb) { + ftpd_dataclose(fsm->datapcb, fsm->datafs); + fsm->datapcb = NULL; + fsm->datafs = NULL; + return; + } + fsm->datapcb = temppcb; + + fsm->passive = 1; + fsm->datafs->connected = 0; + fsm->datafs->msgfs = fsm; + fsm->datafs->msgpcb = pcb; + + /* Tell TCP that this is the structure we wish to be passed for our + callbacks. */ + tcp_arg(fsm->datapcb, fsm->datafs); + + tcp_accept(fsm->datapcb, ftpd_dataaccept); + send_msg(pcb, fsm, msg227, ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), (fsm->dataport >> 8) & 0xff, (fsm->dataport) & 0xff); +} + +static void cmd_abrt(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (fsm->datafs != NULL) { + tcp_arg(fsm->datapcb, NULL); + tcp_sent(fsm->datapcb, NULL); + tcp_recv(fsm->datapcb, NULL); + tcp_arg(fsm->datapcb, NULL); + tcp_abort(pcb); + sfifo_close(&fsm->datafs->fifo); + free(fsm->datafs); + fsm->datafs = NULL; + } + fsm->state = FTPD_IDLE; +} + +static void cmd_type(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + dbg_printf("Got TYPE -%s-\n", arg); + //printit( "Got TYPE -" ); + //printit( (char*)arg ); // ASCII text + + if( *arg == 'A' ) + { + send_msg(pcb, fsm, "200 Type set to A." ); + } + else + { + send_msg(pcb, fsm, msg502); + } +} + +static void cmd_mode(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + dbg_printf("Got MODE -%s-\n", arg); + //printit( "Got MODE -" ); + //printit( (char*)arg ); + send_msg(pcb, fsm, msg502); +} + +static void cmd_rnfr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (arg == NULL) { + send_msg(pcb, fsm, msg501); + return; + } + if (*arg == '\0') { + send_msg(pcb, fsm, msg501); + return; + } + if (fsm->renamefrom) + free(fsm->renamefrom); + fsm->renamefrom = (char*)malloc(strlen(arg) + 1); + if (fsm->renamefrom == NULL) { + send_msg(pcb, fsm, msg451); + return; + } + strcpy(fsm->renamefrom, arg); + fsm->state = FTPD_RNFR; + send_msg(pcb, fsm, msg350); +} + +static void cmd_rnto(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (fsm->state != FTPD_RNFR) { + send_msg(pcb, fsm, msg503); + return; + } + fsm->state = FTPD_IDLE; + if (arg == NULL) { + send_msg(pcb, fsm, msg501); + return; + } + if (*arg == '\0') { + send_msg(pcb, fsm, msg501); + return; + } + if (vfs_rename(fsm->vfs, fsm->renamefrom, arg)) { + send_msg(pcb, fsm, msg450); + } else { + send_msg(pcb, fsm, msg250); + } +} + +static void cmd_mkd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + if (arg == NULL) { + send_msg(pcb, fsm, msg501); + return; + } + if (*arg == '\0') { + send_msg(pcb, fsm, msg501); + return; + } + if (vfs_mkdir(fsm->vfs, arg, VFS_IRWXU | VFS_IRWXG | VFS_IRWXO) != 0) { + send_msg(pcb, fsm, msg550); + } else { + send_msg(pcb, fsm, msg257, arg); + } +} + +static void cmd_nill(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + printit( "cmd_nill" ); +} + + +static void cmd_rmd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + vfs_stat_t st; + + if (arg == NULL) { + send_msg(pcb, fsm, msg501); + return; + } + if (*arg == '\0') { + send_msg(pcb, fsm, msg501); + return; + } + if (vfs_stat(fsm->vfs, arg, &st) != 0) { + send_msg(pcb, fsm, msg550); + return; + } + if (!VFS_ISDIR(st.st_mode)) { + send_msg(pcb, fsm, msg550); + return; + } + if (vfs_rmdir(fsm->vfs, arg) != 0) { + send_msg(pcb, fsm, msg550); + } else { + send_msg(pcb, fsm, msg250); + } +} + +static void cmd_dele(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + vfs_stat_t st; + + if (arg == NULL) { + send_msg(pcb, fsm, msg501); + return; + } + if (*arg == '\0') { + send_msg(pcb, fsm, msg501); + return; + } +#if 0 + if (vfs_stat(fsm->vfs, arg, &st) != 0) + { + send_msg(pcb, fsm, msg550); + return; + } + if (!VFS_ISREG(st.st_mode)) + { + send_msg(pcb, fsm, msg550); + return; + } +#endif + if (vfs_remove(fsm->vfs, arg) != 0) + { + send_msg(pcb, fsm, msg550); + } + else + { + send_msg(pcb, fsm, msg250); + } +} + + +struct ftpd_command { + char *cmd; + void (*func) (const char *arg, struct tcp_pcb * pcb, struct ftpd_msgstate * fsm); +}; + +static struct ftpd_command ftpd_commands[] = { + "USER", cmd_user, + "PASS", cmd_pass, + "PORT", cmd_port, + "QUIT", cmd_quit, + "CWD", cmd_cwd, + "CDUP", cmd_cdup, + "PWD", cmd_pwd, + "XPWD", cmd_pwd, + "NLST", cmd_nlst, + "LIST", cmd_list, + "RETR", cmd_retr, + "STOR", cmd_stor, + "NOOP", cmd_noop, + "SYST", cmd_syst, + "ABOR", cmd_abrt, + "TYPE", cmd_type, + "MODE", cmd_mode, + "RNFR", cmd_rnfr, + "RNTO", cmd_rnto, + "MKD", cmd_mkd, + "XMKD", cmd_mkd, + "RMD", cmd_rmd, + "XRMD", cmd_rmd, + "DELE", cmd_dele, + //"PASV", cmd_pasv, + NULL +}; + +static void send_msgdata(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + err_t err; + u16_t len; + + if (sfifo_used(&fsm->fifo) > 0) { + int i; + + /* We cannot send more data than space available in the send + buffer. */ + if (tcp_sndbuf(pcb) < sfifo_used(&fsm->fifo)) { + len = tcp_sndbuf(pcb); + } else { + len = (u16_t) sfifo_used(&fsm->fifo); + } + + i = fsm->fifo.readpos; + if ((i + len) > fsm->fifo.size) { + err = tcp_write(pcb, fsm->fifo.buffer + i, (u16_t)(fsm->fifo.size - i), 1); + if (err != ERR_OK) { + dbg_printf("send_msgdata: error writing!\n"); + return; + } + len -= fsm->fifo.size - i; + fsm->fifo.readpos = 0; + i = 0; + } + + err = tcp_write(pcb, fsm->fifo.buffer + i, len, 1); + if (err != ERR_OK) { + dbg_printf("send_msgdata: error writing!\n"); + return; + } + fsm->fifo.readpos += len; + } +} + +static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg, ...) +{ + va_list arg; + char buffer[1024]; + int len; + + va_start(arg, msg); + vsprintf(buffer, msg, arg); + va_end(arg); + strcat(buffer, "\r\n"); + len = strlen(buffer); + if (sfifo_space(&fsm->fifo) < len) + return; + sfifo_write(&fsm->fifo, buffer, len); + dbg_printf("response: %s", buffer); + //printit( buffer ); + send_msgdata(pcb, fsm); +} + +static void ftpd_msgerr(void *arg, err_t err) +{ + struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg; + +// printit( "ftpd_msgerr" ); + dbg_printf("ftpd_msgerr: %s (%i)\n", lwip_strerr(err), err); + if (fsm == NULL) + return; + if (fsm->datafs) + ftpd_dataclose(fsm->datapcb, fsm->datafs); + sfifo_close(&fsm->fifo); + vfs_close( (vfs_file_t*)fsm->vfs); + fsm->vfs = NULL; + if (fsm->renamefrom) + free(fsm->renamefrom); + fsm->renamefrom = NULL; + free(fsm); +} + +static void ftpd_msgclose(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) +{ + //printit( "ftpd_msgclose" ); + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); + if (fsm->datafs) + ftpd_dataclose(fsm->datapcb, fsm->datafs); + sfifo_close(&fsm->fifo); + vfs_close( (vfs_file_t*)fsm->vfs); + fsm->vfs = NULL; + if (fsm->renamefrom) + free(fsm->renamefrom); + fsm->renamefrom = NULL; + free(fsm); + tcp_arg(pcb, NULL); + tcp_close(pcb); +} + +static err_t ftpd_msgsent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg; + +// printit( "ftpd_msgsent" ); + if (pcb->state > ESTABLISHED) + return ERR_OK; + + if ((sfifo_used(&fsm->fifo) == 0) && (fsm->state == FTPD_QUIT)) + ftpd_msgclose(pcb, fsm); + + send_msgdata(pcb, fsm); + + return ERR_OK; +} + + +void bcopy (char *src, char *dest, int len) +{ + if (dest < src) + while (len--) + *dest++ = *src++; + else + { + char *lasts = src + (len-1); + char *lastd = dest + (len-1); + while (len--) + *(char *)lastd-- = *(char *)lasts--; + } +} + +static err_t ftpd_msgrecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + char *text; + struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg; + +// printit( "ftpd_msgrecv" ); + //printit( arg ); + if (err == ERR_OK && p != NULL) { + + /* Inform TCP that we have taken the data. */ + tcp_recved(pcb, p->tot_len); + + text = (char*)malloc(p->tot_len + 1); + if (text) { + char cmd[5]; + struct pbuf *q; + char *pt = text; + struct ftpd_command *ftpd_cmd; + + for (q = p; q != NULL; q = q->next) + { + bcopy( (char*)q->payload, pt, q->len); + pt += q->len; + } + *pt = '\0'; + + pt = &text[strlen(text) - 1]; + while (((*pt == '\r') || (*pt == '\n')) && pt >= text) + *pt-- = '\0'; + + dbg_printf("query: %s\n", text); + //printit( "query: " ); + //printit( text ); + + strncpy(cmd, text, 4); + for (pt = cmd; isalpha(*pt) && pt < &cmd[4]; pt++) + *pt = toupper(*pt); + *pt = '\0'; + + for (ftpd_cmd = ftpd_commands; ftpd_cmd->cmd != NULL; ftpd_cmd++) { + if (!strcmp(ftpd_cmd->cmd, cmd)) + break; + } + + if (strlen(text) < (strlen(cmd) + 1)) + pt = ""; + else + pt = &text[strlen(cmd) + 1]; + + if (ftpd_cmd->func) + ftpd_cmd->func(pt, pcb, fsm); + else + send_msg(pcb, fsm, msg502); + + free(text); + } + pbuf_free(p); + } + + return ERR_OK; +} + +static err_t ftpd_msgpoll(void *arg, struct tcp_pcb *pcb) +{ + struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg; + + //printit( "ftpd_msgpoll" ); + if (fsm == NULL) + return ERR_OK; + + if (fsm->datafs) { + if (fsm->datafs->connected) { + switch (fsm->state) { + case FTPD_LIST: + send_next_directory(fsm->datafs, fsm->datapcb, 0); + break; + case FTPD_NLST: + send_next_directory(fsm->datafs, fsm->datapcb, 1); + break; + case FTPD_RETR: + send_file(fsm->datafs, fsm->datapcb); + break; + default: + break; + } + } + } + + return ERR_OK; +} + +static err_t ftpd_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct ftpd_msgstate *fsm; + + +//printit( "FTP call" ); + /* Allocate memory for the structure that holds the state of the + connection. */ + fsm = (struct ftpd_msgstate*)malloc(sizeof(struct ftpd_msgstate)); + + if (fsm == NULL) { + dbg_printf("ftpd_msgaccept: Out of memory\n"); + return ERR_MEM; + } + memset(fsm, 0, sizeof(struct ftpd_msgstate)); + + /* Initialize the structure. */ + sfifo_init(&fsm->fifo, 2000); + fsm->state = FTPD_IDLE; + fsm->vfs = vfs_openfs(); +#if 0 + if (!fsm->vfs) + { + free(fsm); + return ERR_CLSD; + } +#endif + /* Tell TCP that this is the structure we wish to be passed for our + callbacks. */ + tcp_arg( pcb, fsm ); + + /* Tell TCP that we wish to be informed of incoming data by a call + to the http_recv() function. */ + tcp_recv( pcb, ftpd_msgrecv ); + + /* Tell TCP that we wish be to informed of data that has been + successfully sent by a call to the ftpd_sent() function. */ + tcp_sent( pcb, ftpd_msgsent ); + + tcp_err( pcb, ftpd_msgerr ); + + tcp_poll(pcb, ftpd_msgpoll, 1); + + send_msg(pcb, fsm, msg220); + + return ERR_OK; +} + + +void ftpd_init(void) +{ + struct tcp_pcb *pcb; + +//.. vfs_load_plugin(vfs_default_fs); + + pcb = tcp_new(); + tcp_bind( pcb, IP_ADDR_ANY, 21 ); + pcb = tcp_listen( pcb ); + tcp_accept( pcb, ftpd_msgaccept ); +} + + +
diff -r 000000000000 -r c9ac16a7dfb4 NetFtp/ftpd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetFtp/ftpd.h Tue Nov 30 00:45:55 2010 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002 Florian Schulze. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the authors nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * ftpd.h - This file is part of the FTP daemon for lwIP + * + */ + +#ifndef __FTPD_H__ +#define __FTPD_H__ + +//..void ftpd_init(void); + +#endif /* __FTPD_H__ */
diff -r 000000000000 -r c9ac16a7dfb4 NetFtp/vfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetFtp/vfs.c Tue Nov 30 00:45:55 2010 +0000 @@ -0,0 +1,146 @@ + +#include "mbed.h" // DRB +#include "SDFileSystem.h" // DRB +#include "vfs.h" +} + +extern void printit( char *p_buf ); + + +int *vfs_openfs( void ) +{ +// printit( "FTP vfs_openfs" ); + return NULL; +} + + +vfs_file_t *vfs_open( int *fd, const char *fname, const char *mode ) +{ +#if 0 + char what[ 40 ]; + +// printit( "FTP vfs_open" ); + printit( (char*)fname ); + sprintf( what, "/sd/%s", fname ); +// printit( what ); + return (vfs_file_t *)fopen( what, mode ); +#else + return (vfs_file_t *)fopen( fname, mode ); +#endif +} + + +ssize_t vfs_read( void *buf,int what, int BufferSize, vfs_file_t *fp ) +{ +#if 0 + char txt[ 40 ]; + + sprintf( txt, "FTP vfs_read,%u", BufferSize ); + printit( txt ); + memset( buf, 0xAA, BufferSize ); +#endif + return fread( buf, 1, BufferSize, (FILE*)fp); +} + + +int vfs_write( void *buf,int what, int BufferSize, vfs_file_t *fp ) +{ + return fwrite( buf, 1, BufferSize, (FILE*)fp); +} + + +int vfs_eof( vfs_file_t *fp ) +{ + //printit( "vfs_eof" ); + return feof( (FILE*)fp ); +// return 0; // not eof +} + + +int vfs_close( vfs_file_t *fp ) +{ + //printit( "vfs_close" ); + if( NULL != fp ) + { + fclose( (FILE*)fp ); + } + else + { + //printit( "vfs_close--opps!!!" ); + } + return 0; +} + + +int vfs_stat( int *fd, const char *fname, vfs_stat_t *st ) +{ + printit( "" ); + printit( (char*)fname ); + st->st_mode = 1; // ok + st->st_size = 123; // file size + return 1; +} + + +/* + * Find pathname of process's current directory. + * + * Use vfs vnode-to-name reverse cache; if that fails, fall back + * to reading directory contents. + */ +char *vfs_getcwd( int *fd, void *x, int y ) +{ + printit( "vfs_getcwd" ); + return (char*)malloc( 123 ); +} + + +vfs_dir_t *vfs_opendir( int *fd, char *cwd ) +{ + printit( "FTP vfs_opendir" ); + return 0; +} + + +vfs_dirent_t *vfs_readdir( vfs_dir_t *fd ) +{ + printit( "FTP vfs_readdir" ); + return 0; +} + + +int vfs_closedir( vfs_dir_t *fd ) +{ + return 0; +} + + +int vfs_mkdir( int *fd, const char *arg, int mode ) +{ + return 0; +} + + +int vfs_rmdir( int *fd, const char *arg ) +{ + return 0; +} + + +int vfs_rename( int *fd, char *oldname, const char *newname ) +{ + return rename( oldname, newname ); +} + + +int vfs_remove( int *fd, const char *arg ) +{ + return remove( arg ); +} + + +int vfs_chdir( int *fd, const char *arg ) +{ + return 0; +} +
diff -r 000000000000 -r c9ac16a7dfb4 NetFtp/vfs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetFtp/vfs.h Tue Nov 30 00:45:55 2010 +0000 @@ -0,0 +1,263 @@ +/** + * @file ap_vfs.h + * @brief Virtual File System interface + * + * @defgroup APACHE_CORE_VFS Virtual File System interface + * @ingroup APACHE_CORE + * @{ + */ + +#ifndef APACHE_VFS_H +#define APACHE_VFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +//..#include "apr.h" +//..#include "apr_file_io.h" + +//..#include "httpd.h" + +#define AP_USE_VFS 1 +#if !AP_USE_VFS + +/* VFS Interface disabled */ + +#define vfs_file_t apr_file_t +#define vfs_dir_t apr_dir_t + +#define ap_vfs_stat(r, finfo, fname, wanted, pool) \ + apr_stat(finfo, fname, wanted, pool) +#define ap_vfs_file_open(r, new, fname, flag, perm, pool) \ + apr_file_open(new, fname, flag, perm, pool) +#define ap_vfs_file_read(thefile, buf, nbytes) \ + apr_file_read(thefile, buf, nbytes) +#define ap_vfs_file_write(thefile, buf, nbytes) \ + apr_file_write(thefile, buf, nbytes) +#define ap_vfs_file_seek(thefile, where, offset) \ + apr_file_seek(thefile, where, offset) +#define ap_vfs_file_eof(thefile) \ + apr_file_eof(thefile) +#define ap_vfs_file_close(thefile) \ + apr_file_close(thefile) +#define ap_vfs_file_remove(r, path, pool) \ + apr_file_remove(path, pool) +#define ap_vfs_file_rename(r, from_path, to_path, p) \ + apr_file_rename(from_path, to_path, p) +#define ap_vfs_file_perms_set(r, fname, perms) \ + apr_file_perms_set(fname, perms) +#define ap_vfs_dir_open(r, new, dirname, pool) \ + apr_dir_open(new, dirname, pool) +#define ap_vfs_dir_read(finfo, wanted, thedir) \ + apr_dir_read(finfo, wanted, thedir) +#define ap_vfs_dir_close(thedir) \ + apr_dir_close(thedir) +#define ap_vfs_dir_make(r, path, perm, pool) \ + apr_dir_make(path, perm, pool) +#define ap_vfs_dir_remove(r, path, pool) \ + apr_dir_remove(path, pool) + +#else + +/* VFS Public Interface */ + +#define AP_DECLARE(x) x +typedef int apr_status_t; // DRB + +//..typedef struct vfs_file_t vfs_file_t; +typedef struct vfs_dir_t vfs_dir_t; +typedef struct vfs_mount vfs_mount; + +#if 0 // DRB +AP_DECLARE(apr_status_t) ap_vfs_stat(const request_rec *r, + apr_finfo_t *finfo, + const char *fname, + apr_int32_t wanted, + apr_pool_t *pool); + +AP_DECLARE(apr_status_t) ap_vfs_file_open(const request_rec *r, + vfs_file_t **new, + const char *fname, + apr_int32_t flag, + apr_fileperms_t perm, + apr_pool_t *pool); + +AP_DECLARE(apr_status_t) ap_vfs_file_read(vfs_file_t *thefile, + void *buf, + apr_size_t *nbytes); + +AP_DECLARE(apr_status_t) ap_vfs_file_write(vfs_file_t *thefile, + const void *buf, + apr_size_t *nbytes); + +AP_DECLARE(apr_status_t) ap_vfs_file_seek(vfs_file_t *thefile, + apr_seek_where_t where, + apr_off_t *offset); + +AP_DECLARE(apr_status_t) ap_vfs_file_eof(vfs_file_t *file); + +AP_DECLARE(apr_status_t) ap_vfs_file_close(vfs_file_t *file); + +AP_DECLARE(apr_status_t) ap_vfs_file_remove(const request_rec *r, + const char *path, + apr_pool_t *pool); + +AP_DECLARE(apr_status_t) ap_vfs_file_rename(const request_rec *r, + const char *from_path, + const char *to_path, + apr_pool_t *p); + +AP_DECLARE(apr_status_t) ap_vfs_file_perms_set(const request_rec *r, + const char *fname, + apr_fileperms_t perms); + +AP_DECLARE(apr_status_t) ap_vfs_dir_open(const request_rec *r, + vfs_dir_t **new, + const char *dirname, + apr_pool_t *pool); + +AP_DECLARE(apr_status_t) ap_vfs_dir_read(apr_finfo_t *finfo, + apr_int32_t wanted, + vfs_dir_t *thedir); + +AP_DECLARE(apr_status_t) ap_vfs_dir_close(vfs_dir_t *thedir); + +AP_DECLARE(apr_status_t) ap_vfs_dir_make(const request_rec *r, + const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +AP_DECLARE(apr_status_t) ap_vfs_dir_remove(const request_rec *r, + const char *path, + apr_pool_t *pool); + +/* VFS Provider interface */ + +struct vfs_mount { + vfs_mount *next; + apr_uint32_t flags; + const char *mountpoint; + void *userdata; + + /* VFS implementation hooks */ + apr_status_t (*stat) (const vfs_mount *mnt, const request_rec *r, + apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool); + apr_status_t (*file_open) (const vfs_mount *mnt, const request_rec *r, + vfs_file_t **new, const char *fname, + apr_int32_t flag, apr_fileperms_t perm, + apr_pool_t *pool); + apr_status_t (*file_read) (const vfs_mount *mnt, vfs_file_t *thefile, + void *buf, apr_size_t *nbytes); + apr_status_t (*file_write) (const vfs_mount *mnt, vfs_file_t *thefile, + const void *buf, apr_size_t *nbytes); + apr_status_t (*file_seek) (const vfs_mount *mnt, vfs_file_t *thefile, + apr_seek_where_t where, apr_off_t *offset); + apr_status_t (*file_eof) (const vfs_mount *mnt, vfs_file_t *file); + apr_status_t (*file_close) (const vfs_mount *mnt, vfs_file_t *file); + apr_status_t (*file_remove) (const vfs_mount *mnt, const request_rec *r, + const char *path, apr_pool_t *pool); + apr_status_t (*file_rename) (const vfs_mount *mnt, const request_rec *r, + const char *from_path, const char *to_path, + apr_pool_t *p); + apr_status_t (*file_perms_set)(const vfs_mount *mnt, const request_rec *r, + const char *fname, apr_fileperms_t perms); + apr_status_t (*dir_open) (const vfs_mount *mnt, const request_rec *r, + vfs_dir_t **new, const char *dirname, + apr_pool_t *pool); + apr_status_t (*dir_read) (const vfs_mount *mnt, apr_finfo_t *finfo, + apr_int32_t wanted, vfs_dir_t *thedir); + apr_status_t (*dir_close) (const vfs_mount *mnt, vfs_dir_t *thedir); + apr_status_t (*dir_make) (const vfs_mount *mnt, const request_rec *r, + const char *path, apr_fileperms_t perm, + apr_pool_t *pool); + apr_status_t (*dir_remove) (const vfs_mount *mnt, const request_rec *r, + const char *path, apr_pool_t *pool); +}; + +/* VFS file type */ + +struct vfs_file_t { + vfs_mount *mnt; + void *userdata; +}; + +/* VFS directory type */ + +struct vfs_dir_t { + vfs_mount *mnt; + void *userdata; +}; + +/* linked list of vfs_mount structures */ + +extern vfs_mount *ap_vfs_mount_head; +#else + +#define VFS_IRWXU 1 +#define VFS_IRWXG 2 +#define VFS_IRWXO 4 +#define ssize_t int +#define loff_t int +#define filldir_t int +#define VFS_ISDIR(x) ( x & 1) // ((x) && (x) type == VFS_DIR) //! Macro to know if a given entry represents a directory +#define VFS_ISREG( x ) ( x & 2) + +#define vfs_t int +typedef struct +{ + int st_size; + time_t st_mtime; + int st_mode; +} vfs_stat_t; + +typedef struct +{ + char *name; +} vfs_dirent_t; + + +/* VFS file type */ + +struct vfs_file_t { + vfs_mount *mnt; + void *userdata; +}; + +/* VFS directory type */ + +struct vfs_dir_t { + vfs_mount *mnt; + void *userdata; +}; + +int *vfs_openfs( void ); +vfs_file_t *vfs_open( int *fd, const char *arg, const char *mode ); +ssize_t vfs_read( void *buf,int what, int BufferSize, vfs_file_t *fp ); +int vfs_write( void *buf,int what, int BufferSize, vfs_file_t *fp ); +int vfs_eof( vfs_file_t *fp ); +int vfs_close( vfs_file_t *fp ); +int vfs_stat( int *fd, const char *fname, vfs_stat_t *st ); +char *vfs_getcwd( int *fd, void *x, int y ); +vfs_dir_t *vfs_opendir( int *fd, char *cwd ); +vfs_dirent_t *vfs_readdir( vfs_dir_t *fd ); +int vfs_closedir( vfs_dir_t *fd ); +int vfs_mkdir( int *fd, const char *arg, int mode ); +int vfs_rmdir( int *fd, const char *arg ); +int vfs_rename( int *fd, char *was, const char *arg ); +int vfs_remove( int *fd, const char *arg ); +int vfs_chdir( int *fd, const char *arg ); + + +//#define vfs_eof( a ) +//#define vfs_close( a ) fclose( a ) +//#define vfs_readdir( a ) readdir( a ) +//#define vfs_stat( a, b, c ) fstat( a, b ) +//#define vfs_closedir( a ) closedir( a ) + +#endif // DRB + +#endif /* AP_USE_VFS */ + +#endif /* APACHE_VFS_H */
diff -r 000000000000 -r c9ac16a7dfb4 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Nov 30 00:45:55 2010 +0000 @@ -0,0 +1,12 @@ +#include "mbed.h" + +DigitalOut myled(LED1); + +int main() { + while(1) { + myled = 1; + wait(0.2); + myled = 0; + wait(0.2); + } +}
diff -r 000000000000 -r c9ac16a7dfb4 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Nov 30 00:45:55 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e