📄 ftp_srv2.c
字号:
n = fd & FILE_MASK;
if (cwd == 1) {
// var
if (n != README_FILENO)
return logmodtime;
}
return starttime;
}
// This must be a 64-byte string, exactly repeated once, to 128 bytes.
const char random_data[129] =
"The quick brown fox jumps over the lazy dog. !@#$%^&*()-=+[]{}\r\nThe quick brown fox jumps over the lazy dog. !@#$%^&*()-=+[]{}\r\n";
int my_read(int fd, char *buf, long offset, int len)
{
auto LogEntry le;
auto File f;
auto int cwd, n;
auto unsigned i, j;
cwd = DIR2NUMBER(fd);
n = fd & FILE_MASK;
if (n == README_FILENO) {
memcpy(buf, readmes[cwd] + (int)offset, len);
return len;
}
switch (cwd) {
case 0:
return sspec_readfile(n, buf, offset, len);
case 1: /* var */
switch (n) {
case FN_LOG:
if (len < 192)
return 192; // Tell server we need this much buffer
if (!offset)
// 1st request
log_seek(MY_LOG, 0);
if (log_next(MY_LOG, &le) < 0)
return 0;
log_format(&le, buf, len, 1);
n = strlen(buf);
strcpy(buf+n, "\r\n");
return n+2;
case FN_LOG_REV:
if (len < 192)
return 192; // Tell server we need this much buffer
if (!offset)
// 1st request
log_seek(MY_LOG, 1);
if (log_prev(MY_LOG, &le) < 0)
return 0;
log_format(&le, buf, len, 1);
n = strlen(buf);
strcpy(buf+n, "\r\n");
return n+2;
case FN_LOG_APPEND:
break;
}
return 0;
case 2: /* dev */
switch (n) {
case FN_KMEM:
// Read the entire address space
xmem2root(buf, offset, len);
return len;
case FN_RANDOM:
// Random data returned. We don't really generate random data.
// Instead, we return a repeated string. Since this goes forever,
// the client will need to abort the download when they have seen
// enough (e.g. press the STOP botton on a browser, or Ctl-C on a
// command-line client).
j = (unsigned)offset & 63;
for (n = 0; n < len; n += 64) {
i = (unsigned)len - n;
if (i > 64)
i = 64;
memcpy(buf + n, random_data + j, i);
}
return len;
case FN_FS2_IMAGE:
// Entire FS2 file system.
return 0;
default:
// FS2 logical extent, as a raw dump
return 0;
}
case 3: /* fs2 */
// Read a FS2 file in normal mode.
if (fopen_rd(&f, n))
return 0; // should not happen
fseek(&f, offset, SEEK_SET);
fread(&f, buf, len);
fclose(&f);
return len;
}
return 0;
}
int my_write(int fd, char *buf, long offset, int len)
{
static char log[LOG_MAX_MESSAGE+10];
static int loglen;
static int logpri;
static int discard;
auto File f;
auto int bl, c;
auto int n;
if (!offset) {
loglen = -1;
discard = 0;
}
bl = len;
// If this is called, we know file is OK for write.
if (fd > FILENUMBER(3, 0) && fd <= FILENUMBER(3, 255)) {
// Normal FS2 file write
n = fd & FILE_MASK;
if (fopen_wr(&f, n))
return -1;
fseek(&f, offset, SEEK_SET);
bl = fwrite(&f, buf, len);
fclose(&f);
return bl;
}
else if (fd == FILENUMBER(1, FN_LOG_APPEND)) {
// Append messages to the log. Each message is of the form
// [optional digit] [string] [optional CR] LF
// If the first char is a digit 0-7, this is assumed to be the priority of
// the message. The rest of the characters up to the end of line are put into
// the log. If a CR preceeds the LF, it is discarded. The total length of the
// line is limited to 115 (LOG_MAX_MESSAGE) characters; any others are discarded.
// This process is complicated by the fact that the FTP server insists that we
// process all data. We must therefore maintain some state information about where
// we were up to, since we can't log partial messages. The information is kept in
// static variables. This makes the code non-reentrant, but that doesn't matter
// because we only support one write operation at a time.
while (bl) {
if (discard) {
while (bl) {
buf++;
bl--;
if (buf[-1] == '\n') {
discard = 0;
loglen = -1;
break;
}
}
}
c = 0;
while (loglen < LOG_MAX_MESSAGE+2 && bl) {
if (loglen < 0) {
if (isdigit(*buf)) {
logpri = *buf - '0';
if (logpri > 7) logpri = 7;
buf++;
bl--;
}
else
logpri = LOG_INFO;
loglen = 0;
continue;
}
c = log[loglen++] = *buf;
buf++;
bl--;
if (c == '\n')
break;
}
if (c == '\n') {
// Got legitimate EOL
loglen--;
if (loglen && log[loglen-1] == '\r')
loglen--;
log_put(LOG_MAKEPRI(MY_FAC, logpri), 0, log, loglen);
logmodtime = SEC_TIMER;
loglen = -1;
}
else if (bl) {
discard = 1;
log_put(LOG_MAKEPRI(MY_FAC, logpri), 0, log, LOG_MAX_MESSAGE);
logmodtime = SEC_TIMER;
}
}
return len;
}
return -1;
}
int my_close(int fd)
{
printf("Closed %s transfer\n", writing ? "write" : "read");
if (writing)
writing = 0;
else
reading--;
return 0;
}
int my_cd(int cwd, char * dir, int uid)
{
int rc;
rc = filename2number(dir, cwd, 1, O_RDONLY);
printf("dir: %s, cwd: %d, new cwd: %d\n", dir, cwd, rc);
return rc;
}
int my_pwd(int cwd, char * buf)
{
strcpy(buf, "/");
strcat(buf, dirnames[cwd]);
return 0;
}
int my_dirlist(int item, char *line, int listing, int uid, int cwd)
{
// This is not quite as easy as it might be: we want to return the ".." and
// README entries first in the list, so a bit of reordering must be done.
// The ".." entry is probably superfluous, but we want to make the illusion
// complete that we are a Unix machine :-) Maybe we should do "." as well?
int attribs, fd, spec;
long length;
char name[80];
char attrstr[11];
char buf[16];
long modtm;
int lxn;
attribs = 0444;
length = 0;
switch (cwd) {
case 0: /* root */
switch (item) {
case 0:
fd = README_FILENO;
strcpy(name, README_NAME);
break;
case 1:
case 2:
case 3:
/* Directories */
fd = item + DIR_FILENO;
attribs = 01555;
strcpy(name, dirnames[item]);
length = 10;
break;
default:
// sspec names
spec = sspec_findnextfile(item-NUM_DIRS, SERVER_FTP);
if (spec < 0)
return -1;
fd = spec;
item = spec+NUM_DIRS;
strcpy(name, sspec_getname(spec));
break;
}
break;
default:
fd = NUMBER2DIR(cwd);
if (item == 0) {
strcpy(name, "..");
attribs = 01555;
length = 10;
break;
}
if (item == 1) {
strcpy(name, README_NAME);
fd |= README_FILENO;
break;
}
switch (cwd) {
case 1: /* var */
if (item-2 < NUM_VARS) {
strcpy(name, varnames[item-2]);
fd |= item-2 + FN_VAR;
if (item-2 == FN_LOG_APPEND)
attribs = 0222;
}
else
return -1;
break;
case 2: /* dev */
if (item-2 < NUM_DEVS) {
strcpy(name, devnames[item-2]);
fd |= item-2 + FN_DEV;
}
else {
lxn = item-1-NUM_DEVS;
if (lxn > _fs.num_lx)
return -1;
sprintf(name, "fs2_ext_%d", lxn);
fd |= lxn;
}
break;
case 3: /* fs2 */
while (item <= 256 && !FS_EXISTS(item-1))
item++;
if (item > 256)
return -1;
sprintf(name, "file%d", item-1);
fd |= item-1;
attribs = 0666;
break;
}
}
if (!length && fd >= 0)
length = my_getfilesize(fd);
if (fd >= 0)
modtm = my_mdtm(fd);
else
modtm = 0;
if (listing)
sprintf(line, "%s\r\n", name);
else {
strcpy(attrstr, "---");
if (attribs & 0400)
attrstr[0] = 'r';
if (attribs & 0200)
attrstr[1] = 'w';
if (attribs & 0100)
attrstr[2] = 'x';
sprintf(line, "%c%s%s%s 1 anonymous\tanonymous\t%10lu %s %s\r\n",
attribs & 01000 ? 'd' : '-',
attrstr, attrstr, attrstr, length, ftp_ls_date(modtm, buf), name);
}
return item;
}
int my_delete(char * name, int uid, int cwd)
{
auto int fd, n;
if (writing || reading)
return FTP_ERR_UNAVAIL;
fd = filename2number(name, cwd, 0, O_RDONLY);
if (fd < 0)
return FTP_ERR_NOTFOUND;
if (fd > FILENUMBER(3, 0) && fd <= FILENUMBER(3, 255)) {
n = fd & FILE_MASK;
if (fdelete(n))
return FTP_ERR_UNAVAIL;
return 0;
}
return FTP_ERR_BADMODE;
}
FTPhandlers hnd;
/********************************
* Main program *
********************************/
main()
{
int file;
int user;
int rc;
printf("Initializing file system. Please wait...\n");
rc = fs_init(0,0);
if (rc) {
printf("Could not initialize filesystem, error number %d\n", errno);
exit(2);
}
fs_print_lxs(0);
log_open(MY_LOG, 1);
log_put(MY_FACPRI, 0, "----log start-----", 18);
log_put(MY_FACPRI, 0, "FTP Server started", 18);
log_put(MY_FACPRI, 0, "------------------", 18);
starttime = logmodtime = SEC_TIMER;
writing = 0;
reading = 0;
hnd.open = my_open;
hnd.read = my_read;
hnd.write = my_write;
hnd.close = my_close;
hnd.getfilesize = my_getfilesize;
hnd.dirlist = my_dirlist;
hnd.cd = my_cd;
hnd.pwd = my_pwd;
hnd.mdtm = my_mdtm;
hnd.delete = my_delete;
// Set up the first file and user
file = sspec_addxmemfile("rabbitA.gif", rabbit1_gif, SERVER_FTP);
user = sauth_adduser("anonymous", "", SERVER_FTP);
ftp_set_anonymous(user);
sspec_setuser(file, user);
sspec_setuser(sspec_addxmemfile("test1", rabbit1_gif, SERVER_FTP), user);
sspec_setuser(sspec_addxmemfile("test2", rabbit1_gif, SERVER_FTP), user);
// Set up the second file and user
file = sspec_addxmemfile("rabbitF.gif", rabbit1_gif, SERVER_FTP);
user = sauth_adduser("foo", "bar", SERVER_FTP);
sspec_setuser(file, user);
sspec_setuser(sspec_addxmemfile("test3", rabbit1_gif, SERVER_FTP), user);
sspec_setuser(sspec_addxmemfile("test4", rabbit1_gif, SERVER_FTP), user);
sock_init();
ip_print_ifs();
ftp_init(&hnd); /* use custom handlers */
tcp_reserveport(FTP_CMDPORT); // Port 21
// Now we sit back and relax...
while(1) {
ftp_tick();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -