/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <String.h>#include "ftpfs.h" /* an active fid */typedef struct Fid Fid;struct Fid{ int fid; Node *node; /* path to remote file */ int busy; Fid *next; int open;}; Fid *fids; /* linked list of fids */char errstring[128]; /* error to return */int mfd; /* fd for 9fs */int messagesize = 4*1024*IOHDRSZ;uchar mdata[8*1024*IOHDRSZ];uchar mbuf[8*1024*IOHDRSZ];Fcall rhdr;Fcall thdr;int debug;int usenlst;int usetls;char *ext;int quiet;int kapid = -1;int dying; /* set when any process decides to die */int dokeepalive; char *rflush(Fid*), *rnop(Fid*), *rversion(Fid*), *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*), *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*), *rauth(Fid*);;void mountinit(char*);void io(void);int readpdir(Node*); char *(*fcalls[])(Fid*) = { [Tflush] rflush, [Tversion] rversion, [Tattach] rattach, [Tauth] rauth, [Twalk] rwalk, [Topen] ropen, [Tcreate] rcreate, [Tread] rread, [Twrite] rwrite, [Tclunk] rclunk, [Tremove] rremove, [Tstat] rstat, [Twstat] rwstat,}; /* these names are matched as prefixes, so VMS must precede VM */OS oslist[] = { { Plan9, "Plan 9", }, { Plan9, "Plan9", }, { Plan9, "UNIX Type: L8 Version: Plan 9", }, { Unix, "SUN", }, { Unix, "UNIX", }, { VMS, "VMS", }, { VM, "VM", }, { Tops, "TOPS", }, { MVS, "MVS", }, { NetWare, "NetWare", }, { NetWare, "NETWARE", }, { OS½, "OS/2", }, { TSO, "TSO", }, { NT, "Windows_NT", }, /* DOS like interface */ { NT, "WINDOWS_NT", }, /* Unix like interface */ { Unknown, 0 },}; char *nouid = "?uid?"; #define S2P(x) (((ulong)(x)) & 0xffffff) char *nosuchfile = "file does not exist";char *keyspec = ""; voidusage(void){ fprint(2, "ftpfs [-/dqnt] [-a passwd] [-m mountpoint] [-e ext] [-k keyspec] [-o os] [-r root] [net!]address\n"); exits("usage");} voidmain(int argc, char *argv[]){ char *mountroot = 0; char *mountpoint = "/n/ftp"; char *cpassword = 0; char *cp; int p[2]; OS *o; defos = Unix; user = strdup(getuser()); usetls = 0; ARGBEGIN { case '/': mountroot = "/"; break; case 'a': cpassword = ARGF(); break; case 'd': debug = 1; break; case 'k': keyspec = EARGF(usage()); break; case 'K': dokeepalive = 1; break; case 'm': mountpoint = ARGF(); break; case 'n': usenlst = 1; break; case 'e': ext = ARGF(); break; case 't': usetls = 1; break; case 'o': cp = ARGF(); for(o = oslist; o->os != Unknown; o++) if(strncmp(cp, o->name, strlen(o->name)) == 0){ defos = o->os; break; } break; case 'r': mountroot = ARGF(); break; case 'q': quiet = 1; break; } ARGEND if(argc != 1) usage(); /* get a pipe to mount and run 9fs on */ if(pipe(p) < 0) fatal("pipe failed: %r"); mfd = p[0]; /* initial handshakes with remote side */ hello(*argv); if(cpassword == 0) rlogin(*argv, keyspec); else clogin("anonymous", cpassword); preamble(mountroot); /* start the 9fs protocol */ switch(rfork(RFPROC|RFNAMEG|RFENVG|RFFDG|RFNOTEG|RFREND)){ case -1: fatal("fork: %r"); case 0: /* seal off standard input/output */ close(0); open("/dev/null", OREAD); close(1); open("/dev/null", OWRITE); close(p[1]); fmtinstall('F', fcallfmt); /* debugging */ fmtinstall('D', dirfmt); /* expected by %F */ fmtinstall('M', dirmodefmt); /* expected by %F */ io(); quit(); break; default: close(p[0]); if(mount(p[1], -1, mountpoint, MREPL|MCREATE, "") < 0) fatal("mount failed: %r"); } exits(0);} /* * lookup an fid. if not found, create a new one. */Fid *newfid(int fid){ Fid *f, *ff; ff = 0; for(f = fids; f; f = f->next){ if(f->fid == fid){ if(f->busy) return f; else{ ff = f; break; } } else if(!ff && !f->busy) ff = f; } if(ff == 0){ ff = mallocz(sizeof(*f), 1); ff->next = fids; fids = ff; } ff->node = nil; ff->fid = fid; return ff;} /* * a process that sends keep alive messages to * keep the server from shutting down the connection */intkaproc(void){ int pid; if(!dokeepalive) return -1; switch(pid = rfork(RFPROC|RFMEM)){ case -1: return -1; case 0: break; default: return pid; } while(!dying){ sleep(5000); nop(); } _exits(0); return -1;} voidio(void){ char *err, buf[ERRMAX]; int n; kapid = kaproc(); while(!dying){ n = read9pmsg(mfd, mdata, messagesize); if(n <= 0){ errstr(buf, sizeof buf); if(buf[0]=='\0' || strstr(buf, "hungup")) exits(""); fatal("mount read: %s\n", buf); } if(convM2S(mdata, n, &thdr) == 0) continue; if(debug) fprint(2, "<-%F\n", &thdr);/**/ if(!fcalls[thdr.type]) err = "bad fcall type"; else err = (*fcalls[thdr.type])(newfid(thdr.fid)); if(err){ rhdr.type = Rerror; rhdr.ename = err; }else{ rhdr.type = thdr.type + 1; rhdr.fid = thdr.fid; } rhdr.tag = thdr.tag; if(debug) fprint(2, "->%F\n", &rhdr);/**/ n = convS2M(&rhdr, mdata, messagesize); if(write(mfd, mdata, n) != n) fatal("mount write"); }} char*rnop(Fid *f){ USED(f); return 0;} char*rversion(Fid*){ if(thdr.msize > sizeof(mdata)) rhdr.msize = messagesize; else rhdr.msize = thdr.msize; messagesize = thdr.msize; if(strncmp(thdr.version, "9P2000", 6) != 0) return "unknown 9P version"; rhdr.version = "9P2000"; return nil;} char*rflush(Fid*){ return 0;} char*rauth(Fid*){ return "auth unimplemented";} char*rattach(Fid *f){ f->busy = 1; f->node = remroot; rhdr.qid = f->node->d->qid; return 0;} char*rwalk(Fid *f){ Node *np; Fid *nf; char **elems; int i, nelems; char *err; Node *node; /* clone fid */ nf = nil; if(thdr.newfid != thdr.fid){ nf = newfid(thdr.newfid); if(nf->busy) return "newfid in use"; nf->busy = 1; nf->node = f->node; f = nf; } err = nil; elems = thdr.wname; nelems = thdr.nwname; node = f->node; rhdr.nwqid = 0; if(nelems > 0){ /* walk fid */ for(i=0; i<nelems && i<MAXWELEM; i++){ if((node->d->qid.type & QTDIR) == 0){ err = "not a directory"; break; } if(strcmp(elems[i], ".") == 0){ Found: rhdr.wqid[i] = node->d->qid; rhdr.nwqid++; continue; } if(strcmp(elems[i], "..") == 0){ node = node->parent; goto Found; } if(strcmp(elems[i], ".flush.ftpfs") == 0){ /* hack to flush the cache */ invalidate(node); readdir(node); goto Found; } /* some top level names are special */ if((os == Tops || os == VM || os == VMS) && node == remroot){ np = newtopsdir(elems[i]); if(np){ node = np; goto Found; } else { err = nosuchfile; break; } } /* everything else */ node = extendpath(node, s_copy(elems[i])); if(ISCACHED(node->parent)){ /* the cache of the parent is good, believe it */ if(!ISVALID(node)){ err = nosuchfile; break; } if(node->parent->chdirunknown || (node->d->mode & DMSYML)) fixsymbolic(node); } else if(!ISVALID(node)){ /* this isn't a valid node, try cd'ing */ if(changedir(node) == 0){ node->d->qid.type = QTDIR; node->d->mode |= DMDIR; }else{ node->d->qid.type = QTFILE; node->d->mode &= ~DMDIR; } } goto Found; } if(i == 0 && err == 0) err = "file does not exist"; } /* clunk a newly cloned fid if the walk didn't succeed */ if(nf != nil && (err != nil || rhdr.nwqid<nelems)){ nf->busy = 0; nf->fid = 0; } /* if it all worked, point the fid to the enw node */ if(err == nil) f->node = node; return err;} char *ropen(Fid *f){ int mode; mode = thdr.mode; if(f->node->d->qid.type & QTDIR) if(mode != OREAD) return "permission denied"; if(mode & OTRUNC){ uncache(f->node); uncache(f->node->parent); filedirty(f->node); } else { /* read the remote file or directory */ if(!ISCACHED(f->node)){ filefree(f->node); if(f->node->d->qid.type & QTDIR){ invalidate(f->node); if(readdir(f->node) < 0) return nosuchfile; } else { if(readfile(f->node) < 0) return errstring; } CACHED(f->node); } } rhdr.qid = f->node->d->qid; f->open = 1; f->node->opens++; return 0;} char*rcreate(Fid *f){ char *name; if((f->node->d->qid.type&QTDIR) == 0) return "not a directory"; name = thdr.name; f->node = extendpath(f->node, s_copy(name)); uncache(f->node); if(thdr.perm & DMDIR){ if(createdir(f->node) < 0) return "permission denied"; } elseLines 1–500 of 830. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <auth.h> #include <fcall.h> #include <String.h> #include "ftpfs.h" /* an active fid */ typedef struct Fid Fid; struct Fid { int fid; Node *node; /* path to remote file */ int busy; Fid *next; int open; }; Fid *fids; /* linked list of fids */ char errstring[128]; /* error to return */ int mfd; /* fd for 9fs */ int messagesize = 4*1024*IOHDRSZ; uchar mdata[8*1024*IOHDRSZ]; uchar mbuf[8*1024*IOHDRSZ]; Fcall rhdr; Fcall thdr; int debug; int usenlst; int usetls; char *ext; int quiet; int kapid = -1; int dying; /* set when any process decides to die */ int dokeepalive; char *rflush(Fid*), *rnop(Fid*), *rversion(Fid*), *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*), *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*), *rauth(Fid*);; void mountinit(char*); void io(void); int readpdir(Node*); char *(*fcalls[])(Fid*) = { [Tflush] rflush, [Tversion] rversion, [Tattach] rattach, [Tauth] rauth, [Twalk] rwalk, [Topen] ropen, [Tcreate] rcreate, [Tread] rread, [Twrite] rwrite, [Tclunk] rclunk, [Tremove] rremove, [Tstat] rstat, [Twstat] rwstat, }; /* these names are matched as prefixes, so VMS must precede VM */ OS oslist[] = { { Plan9, "Plan 9", }, { Plan9, "Plan9", }, { Plan9, "UNIX Type: L8 Version: Plan 9", }, { Unix, "SUN", }, { Unix, "UNIX", }, { VMS, "VMS", }, { VM, "VM", }, { Tops, "TOPS", }, { MVS, "MVS", }, { NetWare, "NetWare", }, { NetWare, "NETWARE", }, { OS½, "OS/2", }, { TSO, "TSO", }, { NT, "Windows_NT", }, /* DOS like interface */ { NT, "WINDOWS_NT", }, /* Unix like interface */ { Unknown, 0 }, }; char *nouid = "?uid?"; #define S2P(x) (((ulong)(x)) & 0xffffff) char *nosuchfile = "file does not exist"; char *keyspec = ""; void usage(void) { fprint(2, "ftpfs [-/dqnt] [-a passwd] [-m mountpoint] [-e ext] [-k keyspec] [-o os] [-r root] [net!]address\n"); exits("usage"); } void main(int argc, char *argv[]) { char *mountroot = 0; char *mountpoint = "/n/ftp"; char *cpassword = 0; char *cp; int p[2]; OS *o; defos = Unix; user = strdup(getuser()); usetls = 0; ARGBEGIN { case '/': mountroot = "/"; break; case 'a': cpassword = ARGF(); break; case 'd': debug = 1; break; case 'k': keyspec = EARGF(usage()); break; case 'K': dokeepalive = 1; break; case 'm': mountpoint = ARGF(); break; case 'n': usenlst = 1; break; case 'e': ext = ARGF(); break; case 't': usetls = 1; break; case 'o': cp = ARGF(); for(o = oslist; o->os != Unknown; o++) if(strncmp(cp, o->name, strlen(o->name)) == 0){ defos = o->os; break; } break; case 'r': mountroot = ARGF(); break; case 'q': quiet = 1; break; } ARGEND if(argc != 1) usage(); /* get a pipe to mount and run 9fs on */ if(pipe(p) < 0) fatal("pipe failed: %r"); mfd = p[0]; /* initial handshakes with remote side */ hello(*argv); if(cpassword == 0) rlogin(*argv, keyspec); else clogin("anonymous", cpassword); preamble(mountroot); /* start the 9fs protocol */ switch(rfork(RFPROC|RFNAMEG|RFENVG|RFFDG|RFNOTEG|RFREND)){ case -1: fatal("fork: %r"); case 0: /* seal off standard input/output */ close(0); open("/dev/null", OREAD); close(1); open("/dev/null", OWRITE); close(p[1]); fmtinstall('F', fcallfmt); /* debugging */ fmtinstall('D', dirfmt); /* expected by %F */ fmtinstall('M', dirmodefmt); /* expected by %F */ io(); quit(); break; default: close(p[0]); if(mount(p[1], -1, mountpoint, MREPL|MCREATE, "") < 0) fatal("mount failed: %r"); } exits(0); } /* * lookup an fid. if not found, create a new one. */ Fid * newfid(int fid) { Fid *f, *ff; ff = 0; for(f = fids; f; f = f->next){ if(f->fid == fid){ if(f->busy) return f; else{ ff = f; break; } } else if(!ff && !f->busy) ff = f; } if(ff == 0){ ff = mallocz(sizeof(*f), 1); ff->next = fids; fids = ff; } ff->node = nil; ff->fid = fid; return ff; } /* * a process that sends keep alive messages to * keep the server from shutting down the connection */ int kaproc(void) { int pid; if(!dokeepalive) return -1; switch(pid = rfork(RFPROC|RFMEM)){ case -1: return -1; case 0: break; default: return pid; } while(!dying){ sleep(5000); nop(); } _exits(0); return -1; } void io(void) { char *err, buf[ERRMAX]; int n; kapid = kaproc(); while(!dying){ n = read9pmsg(mfd, mdata, messagesize); if(n <= 0){ errstr(buf, sizeof buf); if(buf[0]=='\0' || strstr(buf, "hungup")) exits(""); fatal("mount read: %s\n", buf); } if(convM2S(mdata, n, &thdr) == 0) continue; if(debug) fprint(2, "<-%F\n", &thdr);/**/ if(!fcalls[thdr.type]) err = "bad fcall type"; else err = (*fcalls[thdr.type])(newfid(thdr.fid)); if(err){ rhdr.type = Rerror; rhdr.ename = err; }else{ rhdr.type = thdr.type + 1; rhdr.fid = thdr.fid; } rhdr.tag = thdr.tag; if(debug) fprint(2, "->%F\n", &rhdr);/**/ n = convS2M(&rhdr, mdata, messagesize); if(write(mfd, mdata, n) != n) fatal("mount write"); } } char* rnop(Fid *f) { USED(f); return 0; } char* rversion(Fid*) { if(thdr.msize > sizeof(mdata)) rhdr.msize = messagesize; else rhdr.msize = thdr.msize; messagesize = thdr.msize; if(strncmp(thdr.version, "9P2000", 6) != 0) return "unknown 9P version"; rhdr.version = "9P2000"; return nil; } char* rflush(Fid*) { return 0; } char* rauth(Fid*) { return "auth unimplemented"; } char* rattach(Fid *f) { f->busy = 1; f->node = remroot; rhdr.qid = f->node->d->qid; return 0; } char* rwalk(Fid *f) { Node *np; Fid *nf; char **elems; int i, nelems; char *err; Node *node; /* clone fid */ nf = nil; if(thdr.newfid != thdr.fid){ nf = newfid(thdr.newfid); if(nf->busy) return "newfid in use"; nf->busy = 1; nf->node = f->node; f = nf; } err = nil; elems = thdr.wname; nelems = thdr.nwname; node = f->node; rhdr.nwqid = 0; if(nelems > 0){ /* walk fid */ for(i=0; i<nelems && i<MAXWELEM; i++){ if((node->d->qid.type & QTDIR) == 0){ err = "not a directory"; break; } if(strcmp(elems[i], ".") == 0){ Found: rhdr.wqid[i] = node->d->qid; rhdr.nwqid++; continue; } if(strcmp(elems[i], "..") == 0){ node = node->parent; goto Found; } if(strcmp(elems[i], ".flush.ftpfs") == 0){ /* hack to flush the cache */ invalidate(node); readdir(node); goto Found; } /* some top level names are special */ if((os == Tops || os == VM || os == VMS) && node == remroot){ np = newtopsdir(elems[i]); if(np){ node = np; goto Found; } else { err = nosuchfile; break; } } /* everything else */ node = extendpath(node, s_copy(elems[i])); if(ISCACHED(node->parent)){ /* the cache of the parent is good, believe it */ if(!ISVALID(node)){ err = nosuchfile; break; } if(node->parent->chdirunknown || (node->d->mode & DMSYML)) fixsymbolic(node); } else if(!ISVALID(node)){ /* this isn't a valid node, try cd'ing */ if(changedir(node) == 0){ node->d->qid.type = QTDIR; node->d->mode |= DMDIR; }else{ node->d->qid.type = QTFILE; node->d->mode &= ~DMDIR; } } goto Found; } if(i == 0 && err == 0) err = "file does not exist"; } /* clunk a newly cloned fid if the walk didn't succeed */ if(nf != nil && (err != nil || rhdr.nwqid<nelems)){ nf->busy = 0; nf->fid = 0; } /* if it all worked, point the fid to the enw node */ if(err == nil) f->node = node; return err; } char * ropen(Fid *f) { int mode; mode = thdr.mode; if(f->node->d->qid.type & QTDIR) if(mode != OREAD) return "permission denied"; if(mode & OTRUNC){ uncache(f->node); uncache(f->node->parent); filedirty(f->node); } else { /* read the remote file or directory */ if(!ISCACHED(f->node)){ filefree(f->node); if(f->node->d->qid.type & QTDIR){ invalidate(f->node); if(readdir(f->node) < 0) return nosuchfile; } else { if(readfile(f->node) < 0) return errstring; } CACHED(f->node); } } rhdr.qid = f->node->d->qid; f->open = 1; f->node->opens++; return 0; } char* rcreate(Fid *f) { char *name; if((f->node->d->qid.type&QTDIR) == 0) return "not a directory"; name = thdr.name; f->node = extendpath(f->node, s_copy(name)); uncache(f->node); if(thdr.perm & DMDIR){ if(createdir(f->node) < 0) return "permission denied"; } else