📄 ftpd.c
字号:
/* * chdir */intcwdcmd(char *dir){ char *rp; char buf[Maxpath]; /* shell cd semantics */ if(dir == 0 || *dir == 0){ if(isnone) rp = "/"; else { snprint(buf, sizeof buf, "/usr/%s", user); rp = buf; } if(accessok(rp) == 0) rp = nil; } else rp = abspath(dir); if(rp == nil) return reply("550 Permission denied"); if(chdir(rp) < 0) return reply("550 Cwd failed: %r"); strcpy(curdir, rp); return reply("250 directory changed to %s", curdir);}/* * chdir .. */intcdupcmd(char *dp){ USED(dp); return cwdcmd("..");}intquitcmd(char *arg){ USED(arg); reply("200 Bye"); if(pid) postnote(PNPROC, pid, "kill"); return -1;}inttypecmd(char *arg){ int c; char *x; x = arg; if(arg == 0) return reply("501 Type command needs arguments"); while(c = *arg++){ switch(tolower(c)){ case 'a': type = Tascii; break; case 'i': case 'l': type = Timage; break; case '8': case ' ': case 'n': case 't': case 'c': break; default: return reply("501 Unimplemented type %s", x); } } return reply("200 Type %s", type==Tascii ? "Ascii" : "Image");}intmodecmd(char *arg){ if(arg == 0) return reply("501 Mode command needs arguments"); while(*arg){ switch(tolower(*arg)){ case 's': mode = Mstream; break; default: return reply("501 Unimplemented mode %c", *arg); } arg++; } return reply("200 Stream mode");}intstructcmd(char *arg){ if(arg == 0) return reply("501 Struct command needs arguments"); for(; *arg; arg++){ switch(tolower(*arg)){ case 'f': structure = Sfile; break; default: return reply("501 Unimplemented structure %c", *arg); } } return reply("200 File structure");}intportcmd(char *arg){ char *field[7]; int n; if(arg == 0) return reply("501 Port command needs arguments"); n = getfields(arg, field, 7, 0, ", "); if(n != 6) return reply("501 Incorrect port specification"); snprint(data, sizeof data, "tcp!%.3s.%.3s.%.3s.%.3s!%d", field[0], field[1], field[2], field[3], atoi(field[4])*256 + atoi(field[5])); return reply("200 Data port is %s", data);}intmountnet(void){ int rv; rv = 0; if(bind("#/", "/", MAFTER) < 0){ logit("can't bind #/ to /: %r"); return reply("500 can't bind #/ to /: %r"); } if(bind(nci->spec, "/net", MBEFORE) < 0){ logit("can't bind %s to /net: %r", nci->spec); rv = reply("500 can't bind %s to /net: %r", nci->spec); unmount("#/", "/"); } return rv;}voidunmountnet(void){ unmount(0, "/net"); unmount("#/", "/");}intpasvcmd(char *arg){ NetConnInfo *nnci; Passive *p; USED(arg); p = &passive; if(p->inuse){ close(p->afd); p->inuse = 0; } if(mountnet() < 0) return 0; p->afd = announce("tcp!*!0", passive.adir); if(p->afd < 0){ unmountnet(); return reply("500 No free ports"); } nnci = getnetconninfo(p->adir, -1); unmountnet(); /* parse the local address */ if(debug) logit("local sys is %s", nci->lsys); parseip(p->ipaddr, nci->lsys); if(ipcmp(p->ipaddr, v4prefix) == 0 || ipcmp(p->ipaddr, IPnoaddr) == 0) parseip(p->ipaddr, nci->lsys); p->port = atoi(nnci->lserv); freenetconninfo(nnci); p->inuse = 1; return reply("227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)", p->ipaddr[IPv4off+0], p->ipaddr[IPv4off+1], p->ipaddr[IPv4off+2], p->ipaddr[IPv4off+3], p->port>>8, p->port&0xff);}enum{ Narg=32,};int Cflag, rflag, tflag, Rflag;int maxnamelen;int col;char*mode2asc(int m){ static char asc[12]; char *p; strcpy(asc, "----------"); if(DMDIR & m) asc[0] = 'd'; if(DMAPPEND & m) asc[0] = 'a'; else if(DMEXCL & m) asc[3] = 'l'; for(p = asc+1; p < asc + 10; p += 3, m<<=3){ if(m & 0400) p[0] = 'r'; if(m & 0200) p[1] = 'w'; if(m & 0100) p[2] = 'x'; } return asc;}voidlistfile(Biobufhdr *b, char *name, int lflag, char *dname){ char ts[32]; int n, links, pad; long now; char *x; Dir *d; x = abspath(name); if(x == nil) return; d = dirstat(x); if(d == nil) return; if(isnone){ if(strncmp(x, "/incoming/", sizeof("/incoming/")-1) != 0) d->mode &= ~0222; d->uid = "none"; d->gid = "none"; } strcpy(ts, ctime(d->mtime)); ts[16] = 0; now = time(0); if(now - d->mtime > 6*30*24*60*60) memmove(ts+11, ts+23, 5); if(lflag){ /* Unix style long listing */ if(DMDIR&d->mode){ links = 2; d->length = 512; } else links = 1; Bprint(b, "%s %3d %-8s %-8s %7lld %s ", mode2asc(d->mode), links, d->uid, d->gid, d->length, ts+4); } if(Cflag && maxnamelen < 40){ n = strlen(name); pad = ((col+maxnamelen)/(maxnamelen+1))*(maxnamelen+1); if(pad+maxnamelen+1 < 60){ Bprint(b, "%*s", pad-col+n, name); col = pad+n; } else{ Bprint(b, "\r\n%s", name); col = n; } } else{ if(dname) Bprint(b, "%s/", dname); Bprint(b, "%s\r\n", name); } free(d);}intdircomp(void *va, void *vb){ int rv; Dir *a, *b; a = va; b = vb; if(tflag) rv = b->mtime - a->mtime; else rv = strcmp(a->name, b->name); return (rflag?-1:1)*rv;}voidlistdir(char *name, Biobufhdr *b, int lflag, int *printname, Globlist *gl){ Dir *p; int fd, n, i, l; char *dname; uvlong total; col = 0; fd = open(name, OREAD); if(fd < 0){ Bprint(b, "can't read %s: %r\r\n", name); return; } dname = 0; if(*printname){ if(Rflag || lflag) Bprint(b, "\r\n%s:\r\n", name); else dname = name; } n = dirreadall(fd, &p); close(fd); if(Cflag){ for(i = 0; i < n; i++){ l = strlen(p[i].name); if(l > maxnamelen) maxnamelen = l; } } /* Unix style total line */ if(lflag){ total = 0; for(i = 0; i < n; i++){ if(p[i].qid.type & QTDIR) total += 512; else total += p[i].length; } Bprint(b, "total %ulld\r\n", total/512); } qsort(p, n, sizeof(Dir), dircomp); for(i = 0; i < n; i++){ if(Rflag && (p[i].qid.type & QTDIR)){ *printname = 1; globadd(gl, name, p[i].name); } listfile(b, p[i].name, lflag, dname); } free(p);}voidlist(char *arg, int lflag){ Dir *d; Globlist *gl; Glob *g; int dfd, printname; int i, n, argc; char *alist[Narg]; char **argv; Biobufhdr bh; uchar buf[512]; char *p, *s; if(arg == 0) arg = ""; if(debug) logit("ls %s (. = %s)", arg, curdir); /* process arguments, understand /bin/ls -l option */ argv = alist; argv[0] = "/bin/ls"; argc = getfields(arg, argv+1, Narg-2, 1, " \t") + 1; argv[argc] = 0; rflag = 0; tflag = 0; Rflag = 0; Cflag = 0; col = 0; ARGBEGIN{ case 'l': lflag++; break; case 'R': Rflag++; break; case 'C': Cflag++; break; case 'r': rflag++; break; case 't': tflag++; break; }ARGEND; if(Cflag) lflag = 0; dfd = dialdata(); if(dfd < 0){ reply("425 Error opening data connection:%r"); return; } reply("150 Opened data connection (%s)", data); Binits(&bh, dfd, OWRITE, buf, sizeof(buf)); if(argc == 0){ argc = 1; argv = alist; argv[0] = "."; } for(i = 0; i < argc; i++){ chdir(curdir); gl = glob(argv[i]); if(gl == nil) continue; printname = gl->first != nil && gl->first->next != nil; maxnamelen = 8; if(Cflag) for(g = gl->first; g; g = g->next) if(g->glob && (n = strlen(s_to_c(g->glob))) > maxnamelen) maxnamelen = n; while(s = globiter(gl)){ if(debug) logit("glob %s", s); p = abspath(s); if(p == nil){ free(s); continue; } d = dirstat(p); if(d == nil){ free(s); continue; } if(d->qid.type & QTDIR) listdir(s, &bh, lflag, &printname, gl); else listfile(&bh, s, lflag, 0); free(s); free(d); } globlistfree(gl); } if(Cflag) Bprint(&bh, "\r\n"); Bflush(&bh); close(dfd); reply("226 Transfer complete (list %s)", arg);}intnamelistcmd(char *arg){ return asproc(list, arg, 0);}intlistcmd(char *arg){ return asproc(list, arg, 1);}/* * return the size of the file */intsizecmd(char *arg){ Dir *d; int rv; if(arg == 0) return reply("501 Size command requires pathname"); arg = abspath(arg); d = dirstat(arg); if(d == nil) return reply("501 %r accessing %s", arg); rv = reply("213 %lld", d->length); free(d); return rv;}/* * return the modify time of the file */intmdtmcmd(char *arg){ Dir *d; Tm *t; int rv; if(arg == 0) return reply("501 Mdtm command requires pathname"); if(arg == 0) return reply("550 Permission denied"); d = dirstat(arg); if(d == nil) return reply("501 %r accessing %s", arg); t = gmtime(d->mtime); rv = reply("213 %4.4d%2.2d%2.2d%2.2d%2.2d%2.2d", t->year+1900, t->mon+1, t->mday, t->hour, t->min, t->sec); free(d); return rv;}/* * set an offset to start reading a file from * only lasts for one command */intrestartcmd(char *arg){ if(arg == 0) return reply("501 Restart command requires offset"); offset = atoll(arg); if(offset < 0){ offset = 0; return reply("501 Bad offset"); } return reply("350 Restarting at %lld. Send STORE or RETRIEVE", offset);}/* * send a file to the user */intcrlfwrite(int fd, char *p, int n){ char *ep, *np; char buf[2*Nbuf]; for(np = buf, ep = p + n; p < ep; p++){ if(*p == '\n') *np++ = '\r'; *np++ = *p; } if(write(fd, buf, np - buf) == np - buf) return n; else return -1;}voidretrievedir(char *arg){ int n; char *p; String *file; if(type != Timage){ reply("550 This file requires type binary/image"); return; } file = s_copy(arg); p = strrchr(s_to_c(file), '/'); if(p != s_to_c(file)){ *p++ = 0; chdir(s_to_c(file)); } else { chdir("/"); p = s_to_c(file)+1; } n = transfer("/bin/tar", "c", p, 0, 1); if(n < 0) logit("get %s failed", arg); else logit("get %s OK %d", arg, n); s_free(file);}voidretrieve(char *arg, int arg2){ int dfd, fd, n, i, bytes; Dir *d; char buf[Nbuf]; char *p, *ep; USED(arg2); p = strchr(arg, '\r'); if(p){ logit("cr in file name", arg); *p = 0; } fd = open(arg, OREAD); if(fd == -1){ n = strlen(arg); if(n > 4 && strcmp(arg+n-4, ".tar") == 0){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -