11 OPERM = 0x3, /* mask of all permission types in open mode */
12 Maxsize = 512*1024*1024,
17 typedef struct Fid Fid;
24 String *path; /* complete path */
26 int fd; /* set on open or create */
27 Qid qid; /* set on open or create */
28 int attach; /* this is an attach fd */
30 ulong diroff; /* directory offset */
31 Dir *dir; /* directory entries */
32 int ndir; /* number of directory entries */
38 uchar mdata[IOHDRSZ+Maxfdata];
39 uchar rdata[Maxfdata]; /* buffer for data in reply */
40 uchar statbuf[STATMAX];
43 int messagesize = sizeof mdata;
50 void *erealloc(void*, ulong);
54 void fidqid(Fid*, Qid*);
55 char* short2long(char*);
56 char* long2short(char*, int);
58 void post(char*, int);
60 char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
61 *rattach(Fid*), *rwalk(Fid*),
62 *ropen(Fid*), *rcreate(Fid*),
63 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
64 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
66 char *(*fcalls[])(Fid*) = {
82 char Eperm[] = "permission denied";
83 char Enotdir[] = "not a directory";
84 char Enoauth[] = "lnfs: authentication not required";
85 char Enotexist[] = "file does not exist";
86 char Einuse[] = "file in use";
87 char Eexist[] = "file exists";
88 char Eisdir[] = "file is a directory";
89 char Enotowner[] = "not owner";
90 char Eisopen[] = "file already open for I/O";
91 char Excl[] = "exclusive use file already open";
92 char Ename[] = "illegal name";
93 char Eversion[] = "unknown 9P version";
98 fprint(2, "usage: %s [-r] [-s srvname] mountpoint\n", argv0);
103 notifyf(void *a, char *s)
106 if(strncmp(s, "interrupt", 9) == 0)
112 main(int argc, char *argv[])
138 if(d == nil || !(d->qid.type & QTDIR))
139 sysfatal("mountpoint must be an accessible directory");
143 sysfatal("pipe failed");
154 fmtinstall('F', fcallfmt);
155 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
157 sysfatal("fork: %r");
164 close(p[0]); /* don't deadlock if child fails */
165 if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)
166 sysfatal("mount failed: %r");
172 post(char *srvname, int pfd)
177 snprint(name, sizeof name, "#s/%s", srvname);
178 fd = create(name, OWRITE, 0666);
180 sysfatal("create of %s failed: %r", srvname);
181 sprint(name, "%d", pfd);
182 if(write(fd, name, strlen(name)) < 0)
183 sysfatal("writing %s: %r", srvname);
190 for(f = fids; f; f = f->next)
193 if(thdr.msize > sizeof mdata)
194 rhdr.msize = sizeof mdata;
196 rhdr.msize = thdr.msize;
197 messagesize = rhdr.msize;
198 if(strncmp(thdr.version, "9P2000", 6) != 0)
200 rhdr.version = "9P2000";
220 /* no authentication! */
223 f->user = estrdup(thdr.uname);
226 if(strcmp(user, "none") == 0)
230 f->path = s_copy(".");
231 fidqid(f, &rhdr.qid);
237 clone(Fid *f, Fid **nf)
241 *nf = newfid(thdr.newfid);
245 (*nf)->path = s_clone(f->path);
247 (*nf)->user = f->user;
267 if(rhdr.newfid != rhdr.fid){
271 f = nf; /* walk the new fid */
274 npath = s_clone(f->path);
276 for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
277 name = long2short(thdr.wname[i], 0);
278 if(strcmp(name, ".") == 0){
280 } else if(strcmp(name, "..") == 0){
281 cp = strrchr(s_to_c(npath), '/');
287 s_append(npath, "/");
288 s_append(npath, name);
290 d = dirstat(s_to_c(npath));
298 if(i==0 && err == nil)
302 /* if there was an error and we cloned, get rid of the new fid */
303 if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
308 /* update the fid after a successful walk */
309 if(rhdr.nwqid == thdr.nwname){
319 static char err[256];
321 rerrstr(err, sizeof err);
328 if(readonly && (thdr.mode & 3))
332 f->fd = open(s_to_c(f->path), thdr.mode);
335 fidqid(f, &rhdr.qid);
337 rhdr.iounit = messagesize-IOHDRSZ;
349 name = long2short(thdr.name, 1);
352 s_append(f->path, "/");
353 s_append(f->path, name);
354 f->fd = create(s_to_c(f->path), thdr.mode, thdr.perm);
357 fidqid(f, &rhdr.qid);
359 rhdr.iounit = messagesize-IOHDRSZ;
369 /* reread the directory */
370 if(thdr.offset == 0){
376 f->ndir = dirreadall(f->fd, &f->dir);
381 for(i = 0; i < f->ndir; i++)
382 f->dir[i].name = short2long(f->dir[i].name);
385 /* copy in as many directory entries as possible */
386 for(n = 0; f->diroff < f->ndir; n += i){
387 i = convD2M(&f->dir[f->diroff], rdata+n, thdr.count - n);
392 rhdr.data = (char*)rdata;
404 if(thdr.count > messagesize-IOHDRSZ)
405 thdr.count = messagesize-IOHDRSZ;
406 if(f->qid.type & QTDIR)
408 n = pread(f->fd, rdata, thdr.count, thdr.offset);
411 rhdr.data = (char*)rdata;
421 if(readonly || (f->qid.type & QTDIR))
425 if(thdr.count > messagesize-IOHDRSZ) /* shouldn't happen, anyway */
426 thdr.count = messagesize-IOHDRSZ;
427 n = pwrite(f->fd, thdr.data, thdr.count, thdr.offset);
440 f->path = s_reset(f->path);
450 f->diroff = f->ndir = 0;
457 if(remove(s_to_c(f->path)) < 0)
468 d = dirstat(s_to_c(f->path));
471 d->name = short2long(d->name);
472 n = convD2M(d, statbuf, sizeof statbuf);
489 convM2D(thdr.stat, thdr.nstat, &d, (char*)rdata);
490 d.name = long2short(d.name, 1);
491 n = dirwstat(s_to_c(f->path), &d);
503 for(f = fids; f; f = f->next)
506 else if(!ff && !f->busy)
512 f = emalloc(sizeof *f);
513 f->path = s_reset(f->path);
531 * reading from a pipe or a network device
532 * will give an error after a few eof reads.
533 * however, we cannot tell the difference
534 * between a zero-length read and an interrupt
535 * on the processes writing to us,
536 * so we wait for the error.
538 n = read9pmsg(mfd[0], mdata, messagesize);
540 sysfatal("mount read");
543 if(convM2S(mdata, n, &thdr) == 0)
547 fprint(2, "%s %d:<-%F\n", argv0, pid, &thdr);
549 if(!fcalls[thdr.type])
550 err = "bad fcall type";
552 err = (*fcalls[thdr.type])(newfid(thdr.fid));
557 rhdr.type = thdr.type + 1;
562 fprint(2, "%s %d:->%F\n", argv0, pid, &rhdr);/**/
563 n = convS2M(&rhdr, mdata, messagesize);
565 sysfatal("convS2M error on write");
566 if(write(mfd[1], mdata, n) != n)
567 sysfatal("mount write");
578 sysfatal("out of memory");
584 erealloc(void *p, ulong n)
588 sysfatal("out of memory");
601 sysfatal("out of memory");
607 fidqid(Fid *f, Qid *q)
611 d = dirstat(s_to_c(f->path));
613 *q = (Qid){0, 0, QTFILE};
621 * table of name translations
623 * the file ./.longnames contains all the known long names.
624 * the short name is the first NAMELEN-1 bytes of the base64
625 * encoding of the MD5 hash of the longname.
628 typedef struct Name Name;
632 char shortname[NAMELEN];
636 Dir *dbstat; /* last stat of the name file */
637 char *namefile = "./.longnames";
642 newname(char *longname, int writeflag)
646 uchar digest[MD5dlen];
649 /* chain in new name */
650 n = strlen(longname);
651 np = emalloc(sizeof(*np)+n+1);
652 np->longname = (char*)&np[1];
653 strcpy(np->longname, longname);
654 md5((uchar*)longname, n, digest, nil);
655 enc32(np->shortname, sizeof(np->shortname), digest, MD5dlen);
659 /* don't change namefile if we're read only */
663 /* add to namefile */
664 fd = open(namefile, OWRITE);
667 fprint(fd, "%s\n", longname);
678 for(np = names; np != nil; np = next){
686 * reread the file if the qid.path has changed.
688 * read any new entries if length has changed.
699 d = dirstat(namefile);
704 /* create file if it doesn't exist */
705 fd = create(namefile, OREAD, DMAPPEND|0666);
718 if(d->qid.path == dbstat->qid.path){
719 if(d->length <= dbstat->length){
723 offset = dbstat->length;
732 b = Bopen(namefile, OREAD);
738 while((p = Brdline(b, '\n')) != nil){
739 p[Blinelen(b)-1] = 0;
747 * look up a long name, if it doesn't exist in the
748 * file, add an entry to the file if the writeflag is
749 * non-zero. Return a pointer to the short name.
752 long2short(char *longname, int writeflag)
756 if(strlen(longname) < NAMELEN-1 && strpbrk(longname, " ")==nil)
759 for(np = names; np != nil; np = np->next)
760 if(strcmp(longname, np->longname) == 0)
761 return np->shortname;
764 np = newname(longname, !readonly);
765 return np->shortname;
769 * look up a short name, if it doesn't exist, return the
773 short2long(char *shortname)
777 for(np = names; np != nil; np = np->next)
778 if(strcmp(shortname, np->shortname) == 0)