📄 depend.c
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <bio.h>typedef struct Args Args;struct Args { int argc; char **argv;};typedef struct Dfile Dfile;typedef struct Fid Fid;typedef struct File File;typedef struct Fs Fs;typedef struct Request Request;typedef struct Symbol Symbol;typedef struct Tardir Tardir;extern int threadrforkflag = RFNAMEG;enum{ Nstat = 1024, /* plenty for this application */ MAXSIZE = 8192+IOHDRSZ,};int messagesize = MAXSIZE;voidfatal(char *fmt, ...){ va_list arg; char buf[1024]; write(2, "depend: ", 8); va_start(arg, fmt); vseprint(buf, buf+1024, fmt, arg); va_end(arg); write(2, buf, strlen(buf)); write(2, "\n", 1); threadexitsall(fmt);}enum{ Nfidhash= 64, Ndfhash= 128,};struct Symbol{ Symbol *next; /* hash list chaining */ char *sym; int fno; /* file symbol is defined in */};/* source file */struct File{ QLock; char *name; Symbol *ref; uchar *refvec; /* files resolving the references */ uint len; /* length of file */ uint tarlen; /* length of tar file */ uint mode; uint mtime; int use; int fd;};/* .depend file */struct Dfile{ Lock; int use; /* use count */ int old; /* true if this is an superceded dfile */ File *file; /* files */ int nfile; /* number of files */ int flen; /* length of file table */ Symbol **dhash; /* hash table of symbols */ int hlen; /* length of hash table */ Dfile *next; /* hash chain */ char *path; /* path name of dependency file */ Qid qid; /* qid of the dependency file */};struct Fid{ Fid *next; int fid; int ref; int attached; int open; Qid qid; char *path; Dfile *df; Symbol *dp; int fd; Dir *dir; int ndir; int dirindex;};struct Request{ Request *next; Fid *fid; Fcall f; uchar buf[1];};enum{ Tblocksize= 512, /* tar block size */ Tnamesize= 100, /* tar name size */};struct Tardir{ char name[Tnamesize]; char mode[8]; char uid[8]; char gid[8]; char size[12]; char mtime[12]; char chksum[8]; char linkflag; char linkname[Tnamesize];};struct Fs{ Lock; int fd; /* to kernel mount point */ Fid *hash[Nfidhash]; char *root; Qid rootqid;};struct Fsarg{ Fs *fs; int fd; char *root;};extern void fsrun(void*);extern Fid* fsgetfid(Fs*, int);extern void fsputfid(Fs*, Fid*);extern void fsreply(Fs*, Request*, char*);extern void fsversion(Fs*, Request*, Fid*);extern void fsauth(Fs*, Request*, Fid*);extern void fsflush(Fs*, Request*, Fid*);extern void fsattach(Fs*, Request*, Fid*);extern void fswalk(Fs*, Request*, Fid*);extern void fsopen(Fs*, Request*, Fid*);extern void fscreate(Fs*, Request*, Fid*);extern void fsread(Fs*, Request*, Fid*);extern void fswrite(Fs*, Request*, Fid*);extern void fsclunk(Fs*, Request*, Fid*);extern void fsremove(Fs*, Request*, Fid*);extern void fsstat(Fs*, Request*, Fid*);extern void fswstat(Fs*, Request*, Fid*);void (*fcall[])(Fs*, Request*, Fid*) ={ [Tflush] fsflush, [Tversion] fsversion, [Tauth] fsauth, [Tattach] fsattach, [Twalk] fswalk, [Topen] fsopen, [Tcreate] fscreate, [Tread] fsread, [Twrite] fswrite, [Tclunk] fsclunk, [Tremove] fsremove, [Tstat] fsstat, [Twstat] fswstat};char Eperm[] = "permission denied";char Eexist[] = "file does not exist";char Enotdir[] = "not a directory";char Eisopen[] = "file already open";char Enofid[] = "no such fid";char mallocerr[] = "malloc: %r";char Etoolong[] = "name too long";char *dependlog = "depend";int debug;Dfile *dfhash[Ndfhash]; /* dependency file hash */QLock dfhlock[Ndfhash];QLock iolock;Request* allocreq(int);Dfile* getdf(char*);void releasedf(Dfile*);Symbol* dfsearch(Dfile*, char*);void dfresolve(Dfile*, int);char* mkpath(char*, char*);int mktar(Dfile*, Symbol*, uchar*, uint, int);void closetar(Dfile*, Symbol*);void*emalloc(uint n){ void *p; p = malloc(n); if(p == nil) fatal(mallocerr); memset(p, 0, n); return p;}void *erealloc(void *ReallocP, int ReallocN){ if(ReallocN == 0) ReallocN = 1; if(!ReallocP) ReallocP = emalloc(ReallocN); else if(!(ReallocP = realloc(ReallocP, ReallocN))) fatal("unable to allocate %d bytes",ReallocN); return(ReallocP);}char*estrdup(char *s){ char *d, *d0; if(!s) return 0; d = d0 = emalloc(strlen(s)+1); while(*d++ = *s++) ; return d0;}/* * mount the user interface and start one request processor * per CPU */voidrealmain(void *a){ Fs *fs; int pfd[2]; int srv; char service[128]; struct Fsarg fsarg; Args *args; int argc; char **argv; args = a; argc = args->argc; argv = args->argv; fmtinstall('F', fcallfmt); ARGBEGIN{ case 'd': debug++; break; }ARGEND if(argc != 2){ fprint(2, "usage: %s [-d] svc-name directory\n", argv0); exits("usage"); } snprint(service, sizeof service, "#s/%s", argv[0]); if(argv[1][0] != '/') fatal("directory must be rooted"); if(pipe(pfd) < 0) fatal("opening pipe: %r"); /* Typically mounted before /srv exists */ srv = create(service, OWRITE, 0666); if(srv < 0) fatal("post: %r"); fprint(srv, "%d", pfd[1]); close(srv); close(pfd[1]); time(nil); /* open fd for time before losing / */ if(bind(argv[1], "/", MREPL) == 0) fatal("can't bind %s to /", argv[1]); fs = emalloc(sizeof(Fs)); fsarg.fs = fs; fsarg.fd = pfd[0]; fsarg.root = argv[1]; proccreate(fsrun, &fsarg, 16*1024); proccreate(fsrun, &fsarg, 16*1024); fsrun(&fsarg); exits(nil);}voidthreadmain(int argc, char *argv[]){ static Args args; args.argc = argc; args.argv = argv; rfork(RFNAMEG); proccreate(realmain, &args, 16*1024);}char*mkpath(char *dir, char *file){ int len; char *path; len = strlen(dir) + 1; if(file != nil) len += strlen(file) + 1; path = emalloc(len); if(file != nil) sprint(path, "%s/%s", dir, file); else sprint(path, "%s", dir); return path;}voidfsrun(void *a){ struct Fsarg *fsarg; Fs* fs; char *root; int n, t; Request *r; Fid *f; Dir *d; fsarg = a; fs = fsarg->fs; fs->fd = fsarg->fd; root = fsarg->root; d = dirstat("/"); if(d == nil) fatal("root %s inaccessible: %r", root); fs->rootqid = d->qid; free(d); for(;;){ r = allocreq(messagesize); qlock(&iolock); n = read9pmsg(fs->fd, r->buf, messagesize); qunlock(&iolock); if(n <= 0) fatal("read9pmsg error: %r"); if(convM2S(r->buf, n, &r->f) == 0){ fprint(2, "can't convert %ux %ux %ux\n", r->buf[0], r->buf[1], r->buf[2]); free(r); continue; } f = fsgetfid(fs, r->f.fid); r->fid = f; if(debug) fprint(2, "%F path %llux\n", &r->f, f->qid.path); t = r->f.type; r->f.type++; (*fcall[t])(fs, r, f); fsputfid(fs, f); }}/* * any request that can get queued for a delayed reply */Request*allocreq(int bufsize){ Request *r; r = emalloc(sizeof(Request)+bufsize); r->next = nil; return r;}Fid*fsgetfid(Fs *fs, int fid){ Fid *f, *nf; lock(fs); for(f = fs->hash[fid%Nfidhash]; f; f = f->next){ if(f->fid == fid){ f->ref++; unlock(fs); return f; } } nf = emalloc(sizeof(Fid)); nf->next = fs->hash[fid%Nfidhash]; fs->hash[fid%Nfidhash] = nf; nf->fid = fid; nf->ref = 1; nf->fd = -1; unlock(fs); return nf;}voidfsputfid(Fs *fs, Fid *f){ Fid **l, *nf; lock(fs); if(--f->ref > 0){ unlock(fs); return; } for(l = &fs->hash[f->fid%Nfidhash]; nf = *l; l = &nf->next) if(nf == f){ *l = f->next; break; } unlock(fs); free(f);}voidfsreply(Fs *fs, Request *r, char *err){ int n; uchar buf[MAXSIZE]; if(err){ r->f.type = Rerror; r->f.ename = err; } if(debug) fprint(2, "%F path %llux\n", &r->f, r->fid->qid.path); n = convS2M(&r->f, buf, messagesize); if(n == 0) fatal("bad convS2M"); if(write(fs->fd, buf, n) != n) fatal("unmounted"); free(r);}voidfsversion(Fs *fs, Request *r, Fid*){ if(r->f.msize < 256){ fsreply(fs, r, "version: bad message size"); return; } if(messagesize > r->f.msize) messagesize = r->f.msize; r->f.msize = messagesize; r->f.version = "9P2000"; fsreply(fs, r, nil);}voidfsauth(Fs *fs, Request *r, Fid*){ fsreply(fs, r, "depend: authentication not required");}voidfsflush(Fs*, Request*, Fid*){}voidfsattach(Fs *fs, Request *r, Fid *f){ f->qid = fs->rootqid; f->path = strdup("/"); f->df = getdf(mkpath(f->path, ".depend")); /* hold down the fid till the clunk */ f->attached = 1; lock(fs); f->ref++; unlock(fs); r->f.qid = f->qid; fsreply(fs, r, nil);}voidfswalk(Fs *fs, Request *r, Fid *f){ Fid *nf; char *name, *tmp; int i, nqid, nwname; char errbuf[ERRMAX], *err; Qid qid[MAXWELEM]; Dfile *lastdf; char *path, *npath; Dir *d; Symbol *dp; if(f->attached == 0){ fsreply(fs, r, Eexist); return; } if(f->fd >= 0 || f->open) fatal("walk of an open file"); nf = nil; if(r->f.newfid != r->f.fid){ nf = fsgetfid(fs, r->f.newfid); nf->attached = 1; nf->open = f->open; nf->path = strdup(f->path); nf->qid = f->qid; nf->dp = f->dp; nf->fd = f->fd; nf->df = f->df; if(nf->df){ lock(nf->df); nf->df->use++; unlock(nf->df); } if(r->f.nwname == 0){ r->f.nwqid = 0; fsreply(fs, r, nil); return; } f = nf; } err = nil; path = strdup(f->path); if(path == nil) fatal(mallocerr); nqid = 0; nwname = r->f.nwname; lastdf = f->df; if(nwname > 0){ for(; nqid<nwname; nqid++){ name = r->f.wname[nqid]; if(strcmp(name, ".") == 0){ Noop: if(nqid == 0) qid[nqid] = f->qid; else qid[nqid] = qid[nqid-1]; continue; } if(strcmp(name, "..") == 0){ name = strrchr(path, '/'); if(name){ if(name == path) /* at root */ goto Noop; *name = '\0'; } d = dirstat(path); if(d == nil){ *name = '/'; errstr(errbuf, sizeof errbuf); err = errbuf; break; } Directory: qid[nqid] = d->qid; free(d); releasedf(lastdf); lastdf = getdf(mkpath(path, ".depend")); continue; } npath = mkpath(path, name); free(path); path = npath; d = dirstat(path); if(d !=nil && (d->qid.type & QTDIR)) goto Directory; free(d); qid[nqid].type = QTFILE; qid[nqid].path = 0; qid[nqid].vers = 0; dp = dfsearch(lastdf, name); if(dp == nil){ tmp = strdup(name); if(tmp == nil) fatal("mallocerr"); i = strlen(tmp); if(i > 4 && strcmp(&tmp[i-4], ".tar") == 0){ tmp[i-4] = 0; dp = dfsearch(lastdf, tmp); } free(tmp); } if(dp == nil){ err = Eexist; break; } qid[nqid].path = (uvlong)dp; qid[nqid].vers = 0; } if(nqid == 0 && err == nil) err = "file does not exist"; } /* for error or partial success, put the cloned fid back*/ if(nf!=nil && (err != nil || nqid < nwname)){ releasedf(nf->df); nf->df = nil; fsputfid(fs, nf); } if(err == nil){ /* return (possibly short) list of qids */ for(i=0; i<nqid; i++) r->f.wqid[i] = qid[i]; r->f.nwqid = nqid; /* for full success, advance f */ if(nqid > 0 && nqid == nwname){ free(f->path); f->path = path; path = nil; f->qid = qid[nqid-1]; f->dp = (Symbol*)f->qid.path; if(f->df != lastdf){ releasedf(f->df); f->df = lastdf; lastdf = nil; } } } releasedf(lastdf); free(path); fsreply(fs, r, err);}#ifdef adfvoidfsclone(Fs *fs, Request *r, Fid *f){ Fid *nf; if(f->attached == 0){ fsreply(fs, r, Eexist); return; } nf = fsgetfid(fs, r->f.newfid); nf->attached = 1; nf->open = f->open; nf->path = strdup(f->path); nf->qid = f->qid; nf->dp = f->dp; nf->fd = f->fd; nf->df = f->df; if(nf->df){ lock(nf->df); nf->df->use++; unlock(nf->df); } fsreply(fs, r, nil);}voidfswalk(Fs *fs, Request *r, Fid *f){ char *name; int i; Dir d; char errbuf[ERRLEN]; char *path; Symbol *dp; if(f->attached == 0){ fsreply(fs, r, Enofid); return; } if(f->fd >= 0 || f->open) fatal("walk of an open file"); name = r->f.name; if(strcmp(name, ".") == 0){ fsreply(fs, r, nil); return; } if(strcmp(name, "..") == 0){ name = strrchr(f->path, '/'); if(name){ if(name == f->path){ fsreply(fs, r, nil); return; } *name = 0; } if(dirstat(f->path, &d) < 0){ *name = '/'; errstr(errbuf); fsreply(fs, r, errbuf); return; } r->f.qid = f->qid = d.qid; releasedf(f->df); f->df = getdf(mkpath(f->path, ".depend")); fsreply(fs, r, nil); return; } path = mkpath(f->path, name); if(dirstat(path, &d) < 0 || (d.qid.path & CHDIR) == 0){ dp = dfsearch(f->df, name); if(dp == nil){ i = strlen(name); if(i > 4 && strcmp(&name[i-4], ".tar") == 0){ name[i-4] = 0; dp = dfsearch(f->df, name); } } if(dp == nil){ fsreply(fs, r, Eexist); free(path); return; } f->dp = dp; d.qid.path = (uint)dp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -