📄 depend.c
字号:
d.qid.vers = 0; } free(f->path); f->path = path; if(d.qid.path & CHDIR){ releasedf(f->df); f->df = getdf(mkpath(f->path, ".depend")); } r->f.qid = f->qid = d.qid; fsreply(fs, r, nil);}#endifvoidfsopen(Fs *fs, Request *r, Fid *f){ int mode; char errbuf[ERRMAX]; if(f->attached == 0){ fsreply(fs, r, Enofid); return; } if(f->open){ fsreply(fs, r, Eisopen); return; } mode = r->f.mode & 3; if(mode != OREAD){ fsreply(fs, r, Eperm); return; } if(f->qid.type & QTDIR){ f->fd = open(f->path, OREAD); if(f->fd < 0){ errstr(errbuf, sizeof errbuf); fsreply(fs, r, errbuf); return; } } f->open = 1; r->f.qid = f->qid; fsreply(fs, r, nil);}voidfscreate(Fs *fs, Request *r, Fid*){ fsreply(fs, r, Eperm);}voidfsread(Fs *fs, Request *r, Fid *f){ int i, n, len,skip; Dir d; Symbol *dp; char buf[512]; if(f->attached == 0){ fsreply(fs, r, Enofid); return; } if((int)r->f.count < 0){ fsreply(fs, r, "bad read count"); return; } if(f->qid.type & QTDIR){ n = 0; if(f->dir == nil){ f->ndir = dirreadall(f->fd, &f->dir); f->dirindex = 0; } if(f->dir == nil) goto Return; if(r->f.offset == 0) /* seeking to zero is permitted */ f->dirindex = 0; for(; f->dirindex < f->ndir; f->dirindex++){ if((f->dir[f->dirindex].qid.type & QTDIR) == 0) continue; len = convD2M(&f->dir[f->dirindex], r->buf+n, r->f.count-n); if(len <= BIT16SZ) goto Return; n += len; } skip = f->dirindex - f->ndir; /* # depend records already read */ if(f->df){ for(i = 0; i < f->df->hlen; i++) for(dp = f->df->dhash[i]; dp; dp = dp->next){ if(skip-- > 0) continue; snprint(buf, sizeof buf, "%s.tar", dp->sym); d.name = buf; d.uid = "none"; d.gid = "none"; d.muid = "none"; d.qid.type = QTFILE; d.qid.path = (uvlong)dp; d.qid.vers = 0; d.length = f->df->file[dp->fno].tarlen; d.mode = 0444; d.mtime = time(nil); d.atime = time(nil); len = convD2M(&d, r->buf + n, r->f.count - n); if(len <= BIT16SZ) goto Return; n += len; f->dirindex++; } } } else n = mktar(f->df, f->dp, r->buf, r->f.offset, r->f.count); Return: r->f.data = (char*)r->buf; r->f.count = n; fsreply(fs, r, nil);}voidfswrite(Fs *fs, Request *r, Fid*){ fsreply(fs, r, Eperm);}voidfsclunk(Fs *fs, Request *r, Fid *f){ if(f->attached == 0){ fsreply(fs, r, Enofid); return; } if(f->fd >= 0){ close(f->fd); f->fd = -1; } if((f->qid.type & QTDIR) == 0) closetar(f->df, f->dp); releasedf(f->df); f->df = nil; free(f->dir); f->dir = nil; fsreply(fs, r, nil); fsputfid(fs, f);}voidfsremove(Fs *fs, Request *r, Fid*){ fsreply(fs, r, Eperm);}voidfsstat(Fs *fs, Request *r, Fid *f){ char err[ERRMAX]; Dir d; Symbol *dp; int n; uchar statbuf[Nstat]; if(f->qid.type & QTDIR) n = stat(f->path, statbuf, sizeof statbuf); else { dp = f->dp; d.name = dp->sym; d.uid = "none"; d.gid = "none"; d.muid = "none"; d.qid.type = QTFILE; d.qid.path = (uvlong)dp; d.qid.vers = 0; d.length = f->df->file[dp->fno].tarlen; d.mode = 0444; d.mtime = time(nil); d.atime = time(nil); n = convD2M(&d, statbuf, sizeof statbuf); } if(n <= BIT16SZ){ errstr(err, sizeof err); fsreply(fs, r, err); } else { r->f.stat = statbuf; r->f.nstat = n; fsreply(fs, r, nil); }}voidfswstat(Fs *fs, Request *r, Fid*){ fsreply(fs, r, Eperm);}/* * string hash */uintshash(char *str, int len){ uint hash; char *val; hash = 0; for(val = str; *val; val++) hash = (hash*13) + *val-'a'; return hash % len;}/* * free info about a dependency file */voidfreedf(Dfile *df){ int i; Symbol *dp, *next; lock(df); df->old = 1; if(df->use){ unlock(df); return; } unlock(df); /* we're no longer referenced */ for(i = 0; i < df->nfile; i++) free(df->file[i].name); free(df->file[i].refvec); free(df->file); df->file = nil; for(i = 0; i < df->hlen; i++) for(dp = df->dhash[i]; dp != nil; dp = next){ next = dp->next; free(dp); } free(df->path); free(df); free(df->dhash); df->dhash = nil;}/* * crack a dependency file */voidnewsym(char *name, int fno, Symbol **l){ Symbol *dp; dp = emalloc(sizeof(Symbol)); dp->sym = strdup(name); if(dp->sym == nil) fatal("mallocerr"); dp->next = *l; dp->fno = fno; *l = dp;}intawk(Biobuf *b, char **field, int n){ char *line; int i; while(line = Brdline(b, '\n')){ line[Blinelen(b)-1] = 0; while(*line == ' ' || *line == '\t') *line++ = 0; for(i = 0; i < n; i++){ if(*line == 0 || *line == '#') break; field[i] = line; while(*line && *line != ' ' && *line != '\t') line++; while(*line == ' ' || *line == '\t') *line++ = 0; } if(i) return i; } return 0;}voidcrackdf(Dfile *df, Biobuf *b, uint len, char *dpath){ char *name; char *field[3]; char path[512]; int n, inc, ok, npath; Symbol **l, *dp, *next; File *f, *ef; Dir *d; inc = 32; df->flen = inc; df->file = emalloc(df->flen*sizeof(File)); df->nfile = 0; df->hlen = 1 + len/8; df->dhash = emalloc(df->hlen*sizeof(Symbol*)); l = nil; while((n = awk(b, field, 3)) > 0){ if(n != 2) continue; name = field[1]; switch(*field[0]){ case 'F': if(df->flen == df->nfile){ df->flen += inc; df->file = realloc(df->file, df->flen*sizeof(File)); if(df->file == nil) fatal(mallocerr); memset(&df->file[df->nfile], 0, inc*sizeof(File)); } f = &df->file[df->nfile++]; f->name = strdup(name); l = &f->ref; /* fall through and define as a symbol */ case 'D': if(l == nil) continue; newsym(name, df->nfile-1, &(df->dhash[shash(name, df->hlen)])); break; case 'R': if(l == nil) continue; newsym(name, 0, l); break; } } ef = &df->file[df->nfile]; /* stat the files to get sizes */ npath = strlen(dpath); if(npath+1+1 >= sizeof path) fatal(Etoolong); memmove(path, dpath, npath+1); /* include NUL */ name = strrchr(path, '/') + 1; for(f = df->file; f < ef; f++){ n = strlen(f->name); if(npath+1+n+3+1 > sizeof path) fatal(Etoolong); memmove(name, f->name, n+1); /* include NUL */ ok = access(path, AEXIST); if(ok < 0){ strcpy(name+n, ".Z"); ok = access(path, AEXIST); if(ok < 0){ strcpy(name+n, ".gz"); ok = access(path, AEXIST); } } if(ok >= 0){ free(f->name); f->name = strdup(name); if(f->name == nil) fatal(mallocerr); } d = dirstat(path); if(d){ f->len = d->length; f->mode = d->mode; f->mtime = d->mtime; free(d); }else{ f->len = 0; f->mode = 0; f->mtime = 0; } f->fd = -1; } /* resolve all file references */ for(f = df->file; f < ef; f++) dfresolve(df, f-df->file); /* free the referenced symbols, don't need them anymore */ for(f = df->file; f < ef; f++){ f->tarlen += 2*Tblocksize; /* tars trailing 0 blocks */ for(dp = f->ref; dp != nil; dp = next){ next = dp->next; free(dp); } f->ref = nil; }}/* * get a cracked dependency file */Dfile*getdf(char *path){ Dfile *df, **l; QLock *lk; Dir *d; int i, fd; Biobuf *b; i = shash(path, Ndfhash); l = &dfhash[i]; lk = &dfhlock[i]; qlock(lk); for(df = *l; df; df = *l){ if(strcmp(path, df->path) == 0) break; l = &df->next; } d = dirstat(path); if(df){ if(d!=nil && d->qid.type == df->qid.type && d->qid.vers == df->qid.vers && d->qid.vers == df->qid.vers){ free(path); lock(df); df->use++; unlock(df); goto Return; } *l = df->next; freedf(df); } fd = open(path, OREAD); if(d == nil || fd < 0){ close(fd); goto Return; } df = emalloc(sizeof(*df)); b = emalloc(sizeof(Biobuf)); Binit(b, fd, OREAD); df->qid = d->qid; df->path = path; crackdf(df, b, d->length, path); Bterm(b); free(b); df->next = *l; *l = df; df->use = 1; Return: qunlock(lk); free(d); return df;}/* * stop using a dependency file. Free it if it is no longer linked in. */voidreleasedf(Dfile *df){ Dfile **l, *d; QLock *lk; int i; if(df == nil) return; /* remove from hash chain */ i = shash(df->path, Ndfhash); l = &dfhash[i]; lk = &dfhlock[i]; qlock(lk); lock(df); df->use--; if(df->old == 0 || df->use > 0){ unlock(df); qunlock(lk); return; } for(d = *l; d; d = *l){ if(d == df){ *l = d->next; break; } l = &d->next; } unlock(df); qunlock(lk); /* now we know it is unreferenced, remove it */ freedf(df);}/* * search a dependency file for a symbol */Symbol*dfsearch(Dfile *df, char *name){ Symbol *dp; if(df == nil) return nil; for(dp = df->dhash[shash(name, df->hlen)]; dp; dp = dp->next) if(strcmp(dp->sym, name) == 0) return dp; return nil;}/* * resolve a single file into a vector of referenced files and the sum of their * lengths *//* set a bit in the referenced file vector */intset(uchar *vec, int fno){ if(vec[fno/8] & (1<<(fno&7))) return 1; vec[fno/8] |= 1<<(fno&7); return 0;}/* merge two referenced file vectors */voidmerge(uchar *vec, uchar *ovec, int nfile){ nfile = (nfile+7)/8; while(nfile-- > 0) *vec++ |= *ovec++;}uintres(Dfile *df, uchar *vec, int fno){ File *f; Symbol *rp, *dp; int len; f = &df->file[fno]; if(set(vec, fno)) return 0; /* already set */ if(f->refvec != nil){ merge(vec, f->refvec, df->nfile); /* we've descended here before */ return f->tarlen; } len = 0; for(rp = f->ref; rp; rp = rp->next){ dp = dfsearch(df, rp->sym); if(dp == nil) continue; len += res(df, vec, dp->fno); } return len + Tblocksize + ((f->len + Tblocksize - 1)/Tblocksize)*Tblocksize;}voiddfresolve(Dfile *df, int fno){ uchar *vec; File *f; f = &df->file[fno]; vec = emalloc((df->nfile+7)/8); f->tarlen = res(df, vec, fno); f->refvec = vec;}/* * make the tar directory block for a file */uchar*mktardir(File *f){ uchar *ep; Tardir *tp; uint sum; uchar *p, *cp; p = emalloc(Tblocksize); tp = (Tardir*)p; strcpy(tp->name, f->name); sprint(tp->mode, "%6o ", f->mode & 0777); sprint(tp->uid, "%6o ", 0); sprint(tp->gid, "%6o ", 0); sprint(tp->size, "%11o ", f->len); sprint(tp->mtime, "%11o ", f->mtime); /* calculate checksum */ memset(tp->chksum, ' ', sizeof(tp->chksum)); sum = 0; ep = p + Tblocksize; for (cp = p; cp < ep; cp++) sum += *cp; sprint(tp->chksum, "%6o", sum); return p;}/* * manage open files */intgetfile(Dfile *df, File *f){ int n; char path[512], *name; qlock(f); f->use++; if(f->fd < 0){ name = strrchr(df->path, '/') + 1; n = snprint(path, sizeof path, "%.*s/%s", (int)(name-df->path), df->path, f->name); if(n >= sizeof path - UTFmax){ syslog(0, dependlog, "path name too long: %.20s.../%.20s...", df->path, f->name); return -1; } f->fd = open(path, OREAD); if(f->fd < 0) syslog(0, dependlog, "can't open %s: %r", path); } return f->fd;}voidreleasefile(File *f){ --f->use; qunlock(f);}voidclosefile(File *f){ qlock(f); if(f->use == 0){ close(f->fd); f->fd = -1; } qunlock(f);}/* * return a block of a tar file */intmktar(Dfile *df, Symbol *dp, uchar *area, uint offset, int len){ int fd, i, j, n, off; uchar *p, *buf; uchar *vec; File *f; f = &df->file[dp->fno]; vec = f->refvec; p = area; /* find file */ for(i = 0; i < df->nfile && len > 0; i++){ if((vec[i/8] & (1<<(i&7))) == 0) continue; f = &df->file[i]; n = Tblocksize + ((f->len + Tblocksize - 1)/Tblocksize)*Tblocksize; if(offset >= n){ offset -= n; continue; } if(offset < Tblocksize){ buf = mktardir(f); if(offset + len > Tblocksize) j = Tblocksize - offset; else j = len;//if(debug)fprint(2, "reading %d bytes dir of %s\n", j, f->name); memmove(p, buf+offset, j); p += j; len -= j; offset += j; free(buf); } if(len <= 0) break; off = offset - Tblocksize; if(off >= 0 && off < f->len){ if(off + len > f->len) j = f->len - off; else j = len; fd = getfile(df, f); if(fd >= 0){//if(debug)fprint(2, "reading %d bytes from offset %d of %s\n", j, off, f->name); if(pread(fd, p, j, off) != j) syslog(0, dependlog, "%r reading %d bytes from offset %d of %s", j, off, f->name); } releasefile(f); p += j; len -= j; offset += j; } if(len <= 0) break; if(offset < n){ if(offset + len > n) j = n - offset; else j = len;//if(debug)fprint(2, "filling %d bytes after %s\n", j, f->name); memset(p, 0, j); p += j; len -= j; } offset = 0; } /* null blocks at end of tar file */ if(offset < 2*Tblocksize && len > 0){ if(offset + len > 2*Tblocksize) j = 2*Tblocksize - offset; else j = len;//if(debug)fprint(2, "filling %d bytes at end\n", j); memset(p, 0, j); p += j; } return p - area;}/* * close the files making up a tar file */voidclosetar(Dfile *df, Symbol *dp){ int i; uchar *vec; File *f; f = &df->file[dp->fno]; vec = f->refvec; /* find file */ for(i = 0; i < df->nfile; i++){ if((vec[i/8] & (1<<(i&7))) == 0) continue; closefile(&df->file[i]); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -