/* * Walks elems starting at f. * Ok if nelems is 0. */ static Path* walkpath(Memblk *f, char *elems[], int nelems) { int i; Memblk *nf; Path *p; p = newpath(f); if(catcherror()){ putpath(p); error(nil); } isfile(f); for(i = 0; i < nelems; i++){ if((f->d.mode&DMDIR) == 0) error("not a directory"); rwlock(f, Rd); if(catcherror()){ rwunlock(f, Rd); error("walk: %r"); } nf = dfwalk(f, elems[i], Rd); rwunlock(f, Rd); addelem(&p, nf); mbput(nf); f = nf; USED(&f); /* in case of error() */ noerror(); } noerror(); return p; }
static void fsrm(int, char *argv[]) { Memblk *f, *pf; Path *p; p = walkto(argv[1], nil); if(catcherror()){ putpath(p); error(nil); } if(p->nf < 2) error("short path for rm"); dfmelt(&p, p->nf-1); f = p->f[p->nf-1]; pf = p->f[p->nf-2]; rwlock(f, Wr); if(catcherror()){ rwunlock(f, Wr); rwunlock(pf, Wr); error(nil); } dfremove(pf, f); p->f[p->nf-1] = nil; noerror(); noerror(); rwunlock(pf, Wr); putpath(p); }
/* * Walk to a child and return it referenced. * If iswr, d must not be frozen and the child is returned melted. */ Memblk* dfwalk(Memblk *d, char *name, int iswr) { Memblk *f; Blksl sl; daddrt *de; uvlong off; int i; if(strcmp(name, "..") == 0) fatal("dfwalk: '..'"); isdir(d); if(iswr) ismelted(d); off = 0; f = nil; for(;;){ sl = dfslice(d, Dblkdatasz, off, Rd); if(sl.len == 0){ assert(sl.b == nil); break; } if(sl.b == nil) continue; if(catcherror()){ dprint("dfwalk d%#ullx '%s': %r\n", d->addr, name); mbput(sl.b); error(nil); } for(i = 0; i < sl.len/Daddrsz; i++){ de = sl.data; de += i; if(*de == 0) continue; f = dbget(DBfile, *de); if(strcmp(f->mf->name, name) != 0){ mbput(f); continue; } /* found */ noerror(); mbput(sl.b); if(!iswr || !f->frozen) goto done; fatal("dfwalk: frozen"); } noerror(); mbput(sl.b); off += sl.len; } error("file not found"); done: dprint("dfwalk d%#ullx '%s' -> d%#ullx\n", d->addr, name, f->addr); return f; }
static void fsget(int, char *argv[]) { Memblk *f; Mfile *m; char buf[4096], *nm; uvlong off; long nr; int fd; Path *p; fd = create(argv[1], OWRITE, 0664); if(fd < 0) error("create: %r\n"); nm = fsname(argv[2]); if(catcherror()){ free(nm); close(fd); error(nil); } p = walkto(nm, nil); f = p->f[p->nf-1]; rwlock(f, Rd); if(catcherror()){ rwunlock(f, Rd); putpath(p); error(nil); } m = f->mf; print("get %-30s\t%M\t%5ulld\t%s %ulld refs\n", m->name, (ulong)f->d.mode, f->d.length, m->uid, dbgetref(f->addr)); if((f->d.mode&DMDIR) == 0){ off = 0; for(;;){ if(fsmemfree() < Mminfree) fslru(); nr = dfpread(f, buf, sizeof buf, off); if(nr <= 0) break; if(write(fd, buf, nr) != nr){ fprint(2, "%s: error: %r\n", argv[0]); break; } off += nr; } } close(fd); noerror(); noerror(); rwunlock(f, Rd); putpath(p); free(nm); }
int main() { unsigned char outbuf[MAX_ATTRSETSIZE]; const char *decoded = "accept"; const char *secret = "foo"; krb5_error_code retval; krb5_context ctx; const char *tmp; krb5_data in; size_t len; noerror(krb5_init_context(&ctx)); /* Make sure User-Name is 1. */ insist(krad_attr_name2num("User-Name") == 1); /* Make sure 2 is User-Password. */ tmp = krad_attr_num2name(2); insist(tmp != NULL); insist(strcmp(tmp, "User-Password") == 0); /* Test decoding. */ in = make_data((void *)encoded, sizeof(encoded)); noerror(kr_attr_decode(ctx, secret, auth, krad_attr_name2num("User-Password"), &in, outbuf, &len)); insist(len == strlen(decoded)); insist(memcmp(outbuf, decoded, len) == 0); /* Test encoding. */ in = string2data((char *)decoded); retval = kr_attr_encode(ctx, secret, auth, krad_attr_name2num("User-Password"), &in, outbuf, &len); insist(retval == 0); insist(len == sizeof(encoded)); insist(memcmp(outbuf, encoded, len) == 0); /* Test constraint. */ in.length = 100; insist(kr_attr_valid(krad_attr_name2num("User-Password"), &in) == 0); in.length = 200; insist(kr_attr_valid(krad_attr_name2num("User-Password"), &in) != 0); krb5_free_context(ctx); return 0; }
static int ptrmap(daddrt addr, int nind, Blkf f, int isdisk) { int i; Memblk *b; long tot; if(addr == 0) return 0; if(isdisk) b = dbget(DBdata+nind, addr); else{ b = mbget(DBdata+nind, addr, Dontmk); if(b == nil) return 0; /* on disk */ } if(catcherror()){ mbput(b); error(nil); } tot = 0; if(f == nil || f(b) == 0){ tot++; if(nind > 0){ for(i = 0; i < Dptrperblk; i++) tot += ptrmap(b->d.ptr[i], nind-1, f, isdisk); } } noerror(); mbput(b); return tot; }
/* for dfblk only */ static Memblk* getmelted(uint isdir, uint type, daddrt *addrp, int *chg) { Memblk *b, *nb; *chg = 0; if(*addrp == 0){ b = dballoc(type); *addrp = b->addr; *chg = 1; return b; } b = dbget(type, *addrp); nb = nil; if(!b->frozen) return b; if(catcherror()){ mbput(b); mbput(nb); error(nil); } nb = dbdup(b); assert(type == b->type); if(isdir && type == DBdata) dupdentries(nb->d.data, Dblkdatasz/Daddrsz); USED(&nb); /* for error() */ *addrp = nb->addr; *chg = 1; dbput(b, b->type, b->addr); noerror(); mbput(b); return nb; }
/* * Remove [bno:bend) file data blocks. * The file must be r/wlocked and melted. */ void dfdropblks(Memblk *f, ulong bno, ulong bend) { Memblk *b; isrwlocked(f, Wr); ismelted(f); dprint("dfdropblks: could remove d%#ullx[%uld:%uld]\n", f->addr, bno, bend); /* * Instead of releasing the references on the data blocks, * considering that the file might grow again, we keep them. * Consider recompiling again and again and... * * The length has been adjusted and data won't be returned * before overwritten. * * We only have to zero the data, because the file might * grow using holes and the holes must read as zero, and also * for safety. */ for(; bno < bend; bno++){ if(catcherror()) continue; b = dfblk(f, bno, Dontmk); noerror(); memset(b->d.data, 0, Dblkdatasz); changed(b); mbput(b); } }
static Path* walkto(char *a, char **lastp) { char *els[Nels], *path; int nels; Path *p; path = fsname(a); nels = gettokens(path, els, Nels, "/"); if(nels < 1){ free(path); error("invalid path"); } if(catcherror()){ free(path); error("walkpath: %r"); } if(lastp != nil){ p = walkpath(fs->root, els, nels-1); *lastp = a + strlen(a) - strlen(els[nels-1]); }else p = walkpath(fs->root, els, nels); free(path); noerror(); if(verb) print("walked to %H\n", p->f[p->nf-1]); return p; }
void threadmain(int argc, char *argv[]) { char *dev; char *args[Nels]; int i, j, nargs; dev = "disk"; ARGBEGIN{ case 'v': verb++; break; case 'f': dev = EARGF(usage()); break; default: if(ARGC() >= 'A' && ARGC() <= 'Z'){ dbg['d'] = 1; dbg[ARGC()] = 1; }else usage(); }ARGEND; if(argc == 0) usage(); fatalaborts = 1; fmtinstall('H', mbfmt); fmtinstall('M', dirmodefmt); errinit(Errstack); if(catcherror()){ fprint(2, "cmd failed: %r\n"); threadexitsall("failed"); } fsopen(dev); for(i = 0; i < argc; i++){ if(verb>1) fsdump(0, Mem); print("%% %s\n", argv[i]); nargs = gettokens(argv[i], args, Nels, "!"); for(j = 0; j < nelem(cmds); j++){ if(strcmp(cmds[j].name, argv[i]) != 0) continue; if(cmds[j].nargs != 0 && cmds[j].nargs != nargs) fprint(2, "usage: %s\n", cmds[j].usage); else cmds[j].f(nargs, args); break; } if(j == nelem(cmds)){ fprint(2, "no such command\n"); for(j = 0; j < nelem(cmds); j++) fprint(2, "\t%s\n", cmds[j].usage); break; } } if(verb>1) fsdump(0, Mem); noerror(); threadexitsall(nil); }
long dfcountrefs(Memblk *f) { Memblk *b; int i; long nfails; nfails = 0; isfile(f); if((f->addr&Fakeaddr) == 0 && f->addr >= fs->limit){ fprint(2, "fscheck: '%s' d%#010ullx: out of range\n", f->mf->name, f->addr); return 1; } if((f->addr&Fakeaddr) == 0) if(countref(f->addr) != 0) /* already visited */ return 0; /* skip children */ rwlock(f, Rd); if(catcherror()){ fprint(2, "fscheck: '%s' d%#010ullx: data: %r\n", f->mf->name, f->addr); rwunlock(f, Rd); return 1; } for(i = 0; i < nelem(f->d.dptr); i++) ptrmap(f->d.dptr[i], 0, bcountrefs, Disk); for(i = 0; i < nelem(f->d.iptr); i++) ptrmap(f->d.iptr[i], i+1, bcountrefs, Disk); if(f->d.mode&DMDIR) for(i = 0; i < f->d.length/Daddrsz; i++){ b = dfchild(f, i); if(catcherror()){ fprint(2, "fscheck: '%s' d%#010ullx:" " child[%d]: %r\n", f->mf->name, f->addr, i); nfails++; }else{ nfails += dfcountrefs(b); noerror(); } mbput(b); } noerror(); rwunlock(f, Rd); return nfails; }
/* * May be called with null parent, for root and ctl files. * The first call with a null parent is root, all others are ctl * files linked at root. */ Memblk* dfcreate(Memblk *parent, char *name, int uid, ulong mode) { Memblk *nf; Mfile *m; int isctl; if(fsfull()) error("file system full"); isctl = parent == nil; if(parent == nil) parent = fs->root; if(parent != nil){ dprint("dfcreate '%s' %M at\n%H\n", name, mode, parent); isdir(parent); isrwlocked(parent, Wr); ismelted(parent); }else dprint("dfcreate '%s' %M", name, mode); if(isctl) nf = dballoc(DBctl); else nf = dballoc(DBfile); if(catcherror()){ mbput(nf); if(parent != nil) rwunlock(parent, Wr); error(nil); } m = nf->mf; nf->d.id = nsec(); nf->d.mode = mode; nf->d.mtime = nf->d.id; nf->d.atime = nf->d.id; nf->d.length = 0; m->uid = usrname(uid); nf->d.uid = uid; m->gid = m->uid; nf->d.gid = nf->d.uid; m->muid = m->uid; nf->d.muid = nf->d.uid; m->name = name; nf->d.asize = pmeta(nf->d.embed, Embedsz, nf); changed(nf); if(parent != nil){ m->gid = parent->mf->gid; nf->d.gid = parent->d.gid; dflink(parent, nf); } noerror(); dprint("dfcreate-> %H\n within %H\n", nf, parent); return nf; }
static void fscat(int, char *argv[]) { Memblk *f; Mfile *m; char buf[4096], *nm; uvlong off; long nr; Path *p; nm = fsname(argv[2]); if(catcherror()){ free(nm); error(nil); } p = walkto(nm, nil); f = p->f[p->nf-1]; rwlock(f, Rd); if(catcherror()){ rwunlock(f, Rd); putpath(p); error(nil); } m = f->mf; print("cat %-30s\t%M\t%5ulld\t%s %ulld refs\n", m->name, (ulong)f->d.mode, f->d.length, m->uid, dbgetref(f->addr)); if((f->d.mode&DMDIR) == 0){ off = 0; for(;;){ if(fsmemfree() < Mminfree) fslru(); nr = dfpread(f, buf, sizeof buf, off); if(nr <= 0) break; write(1, buf, nr); off += nr; } } noerror(); noerror(); rwunlock(f, Rd); putpath(p); free(nm); }
void dfremove(Memblk *p, Memblk *f) { vlong n; /* funny as it seems, we may need extra blocks to melt */ if(fsfull()) error("file system full"); isrwlocked(f, Wr); isrwlocked(p, Wr); ismelted(p); if((f->d.mode&DMDIR) != 0 && f->d.ndents > 0) error("directory not empty"); incref(p); if(catcherror()){ mbput(p); error(nil); } dfunlink(p, f); /* shouldn't fail now. it's unlinked */ if(p->d.ndents == 0 && p->d.length > 0){ /* all gone, make it public */ p->d.length = 0; changed(p); } noerror(); rwunlock(f, Wr); if(!catcherror()){ n = dfput(f); dprint("dfput d%#ullx: %lld blks\n", f->addr, n); noerror(); } mbput(f); mbput(p); }
static void fsrm(int, char *argv[]) { Memblk *f, *pf; Path *p; char *nm; nm = fsname(argv[1]); if(catcherror()){ free(nm); error(nil); } p = walkto(nm, nil); if(catcherror()){ putpath(p); error(nil); } if(p->nf < 2) error("short path for rm"); meltedpath(&p, p->nf-1, 1); f = p->f[p->nf-1]; pf = p->f[p->nf-2]; rwlock(f, Wr); if(catcherror()){ rwunlock(f, Wr); rwunlock(pf, Wr); error(nil); } dfremove(pf, f); p->f[p->nf-1] = nil; noerror(); noerror(); noerror(); rwunlock(pf, Wr); putpath(p); free(nm); }
int dffreeze(Memblk *f) { int i; Memblk *b; long tot; isfile(f); if(f->frozen && f != fs->active && f != fs->archive) return 0; rwlock(f, Wr); if(catcherror()){ rwunlock(f, Wr); error(nil); } f->frozen = 1; tot = 1; for(i = 0; i < nelem(f->d.dptr); i++) tot += ptrmap(f->d.dptr[i], 0, bfreeze, Mem); for(i = 0; i < nelem(f->d.iptr); i++) tot += ptrmap(f->d.iptr[i], i+1, bfreeze, Mem); if((f->d.mode&DMDIR) != 0){ for(i = 0; i < f->d.length/Daddrsz; i++){ b = mfchild(f, i); if(b == nil) continue; if(!catcherror()){ tot += dffreeze(b); noerror(); } mbput(b); } } noerror(); rwunlock(f, Wr); return tot; }
/* * Drop one disk reference for f and reclaim its storage if it's gone. * The given memory reference is not released. * For directories, all files contained have their disk references adjusted, * and they are also reclaimed if no further references exist. * * NB: Time ago, directories were not in compact form (they had holes * due to removals) and this had a bug while reclaiming that could lead * to double frees of disk blocks. * The bug was fixed, but since then, directories have changed again to * have holes. If the a double free happens again, this is the place where * to look, besides dbdup and dfchdentry. */ int dfput(Memblk *f) { int i; Memblk *b; long tot; isfile(f); dKprint("dfput %H\n", f); /* * Remove children if it's the last disk ref before we drop data blocks. * No new disk refs may be added, so there's no race here. */ tot = 0; if(dbgetref(f->addr) == 1 && (f->d.mode&DMDIR) != 0){ rwlock(f, Wr); if(catcherror()){ rwunlock(f, Wr); error(nil); } for(i = 0; i < f->d.ndents; i++){ b = dfchild(f, i); if(!catcherror()){ tot += dfput(b); noerror(); } mbput(b); } noerror(); rwunlock(f, Wr); } if(dbput(f, f->type, f->addr) == 0) tot++; return tot; }
/* * Report that a file has been modified. * Modification times propagate up to the root of the file tree. * But frozen files are never changed. */ void dfchanged(Path *p, int muid) { Memblk *f; u64int t, u; int i; t = nsec(); u = muid; for(i = 0; i < p->nf; i++){ f = p->f[i]; rwlock(f, Wr); if(f->frozen == 0) if(!catcherror()){ f->d.mtime = t; f->d.atime = t; f->d.muid = muid; changed(f); noerror(); } rwunlock(f, Wr); } }
/* * CAUTION: debug: no locks. */ int dfdump(Memblk *f, int isdisk) { int i; Memblk *b; Memblk *(*child)(Memblk*, int); long tot; extern int mbtab; isfile(f); tot = 1; /* visit the blocks to fetch them if needed. */ for(i = 0; i < nelem(f->d.dptr); i++) tot += ptrmap(f->d.dptr[i], 0, nil, isdisk); for(i = 0; i < nelem(f->d.iptr); i++) tot += ptrmap(f->d.iptr[i], i+1, nil, isdisk); fprint(2, "%H\n", f); if((f->d.mode&DMDIR) != 0){ mbtab++; child = dfchild; if(!isdisk) child = mfchild; for(i = 0; i < f->d.ndents; i++){ b = child(f, i); if(b == nil) continue; if(!catcherror()){ tot += dfdump(b, isdisk); noerror(); } mbput(b); } mbtab--; } return tot; }
/* * Find a dir entry for addr (perhaps 0 == avail) and change it to * naddr. If iswr, the entry is allocated if needed and the blocks * melted on demand. * Return the offset for the entry in the file or Noaddr * Does not adjust disk refs. */ uvlong dfchdentry(Memblk *d, u64int addr, u64int naddr, int mkit) { Blksl sl; daddrt *de; uvlong off; int i; assert(d->d.length/Daddrsz >= d->d.ndents); dAprint("dfchdentry d%#ullx -> d%#ullx\nin %H\n", addr, naddr, d); isrwlocked(d, mkit?Wr:Rd); isdir(d); if(addr == naddr) fatal("dfchdentry: it did happen. now, why?"); off = 0; for(;;){ sl = dfslice(d, Dblkdatasz, off, mkit); if(sl.len == 0){ assert(sl.b == nil); break; } if(sl.b == nil){ if(addr == 0 && !mkit) return off; continue; } if(catcherror()){ mbput(sl.b); error(nil); } de = sl.data; for(i = 0; i < sl.len/Daddrsz; i++){ if(de[i] == addr){ off += i*Daddrsz; if(naddr != addr){ de[i] = naddr; changed(sl.b); if(addr == 0 && naddr != 0){ if(d->d.length < off+Daddrsz) d->d.length = off+Daddrsz; d->d.ndents++; changed(d); }else if(addr != 0 && naddr == 0){ d->d.ndents--; changed(d); } } noerror(); mbput(sl.b); assert(d->d.length/Daddrsz >= d->d.ndents); return off; } } off += sl.len; noerror(); mbput(sl.b); } if(mkit) fatal("dfchdentry: bug"); return Noaddr; }
/* * This is unrealistic in that it keeps the file locked * during the entire put. This means that we can only give * fslru() a chance before each put, and not before each * write, because everything is going to be in use and dirty if * we run out of memory. */ static void fsput(int, char *argv[]) { int fd; char *fn; Memblk *m, *f; Dir *d; char buf[4096]; uvlong off; long nw, nr; Path *p; char *nm; fd = open(argv[1], OREAD); if(fd < 0) error("open: %r\n"); d = dirfstat(fd); if(d == nil){ error("dirfstat: %r\n"); } nm = fsname(argv[2]); if(catcherror()){ free(nm); close(fd); free(d); error(nil); } p = walkto(nm, &fn); if(catcherror()){ putpath(p); error(nil); } meltedpath(&p, p->nf, 1); m = p->f[p->nf-1]; if(catcherror()){ rwunlock(m, Wr); error(nil); } f = dfcreate(m, fn, usrid(d->uid), d->mode&(DMDIR|0777)); noerror(); addelem(&p, f); decref(f); /* kept now in p */ rwlock(f, Wr); rwunlock(m, Wr); if(catcherror()){ rwunlock(f, Wr); error(nil); } if((d->mode&DMDIR) == 0){ off = 0; for(;;){ if(fsmemfree() < Mminfree) fslru(); nr = read(fd, buf, sizeof buf); if(nr <= 0) break; nw = dfpwrite(f, buf, nr, &off); dprint("wrote %ld of %ld bytes\n", nw, nr); off += nr; } } noerror(); noerror(); noerror(); if(verb) print("created %H\nat %H\n", f, m); rwunlock(f, Wr); free(nm); putpath(p); close(fd); free(d); }
void Indexer::import() { int total = 0; QStringList filePaths; ProgressionInfo informations; informations.style = searching; informations.phrase = QString(tr("Recherche de morceaux en cours...")); emit updateBar(informations); iterator = new QDirIterator(chemin, filtre, QDir::NoFilter, QDirIterator::Subdirectories); while(iterator->hasNext()) { if(loopRunning == false) { return; } filePaths.append(iterator->next()); total++; ProgressionInfo informations; informations.phrase = QString(tr("%1 morceaux trouvés")).arg(total); informations.style = searching; emit updateBar(informations); } if(loopRunning == false) { return; } if(filePaths.count() == 0) { emit fatalError(tr("Aucun fichier trouvé dans le dossier spécifié")); } QString noerror(tr("0 medias importés")), alreadyexists(tr("0 existent déjà")), error(tr("aucune erreur")); int o = 0; //nombre d'erreurs int a = 0; for(int i = 0;i<filePaths.count();i++) { if(loopRunning == false || filePaths.count() == 0 || i == filePaths.count()) { return; } NutshMetaData data(filePaths.value(i)); errorcode = saver->inserer(data); switch(errorcode) { case NoError: qDebug() << "NoError"; noerror = QString(tr("%1 medias importés")).arg(i-a-o); break; case SqlError: qDebug() << "SqlError"; o = o+1; error = QString(tr("%1 erreurs")).arg(o); break; case CantDecodeTag: qDebug() << "CantDecodeTag"; o = o+1; error = QString(tr("%1 erreurs")).arg(o); break; case AlreadyExists: qDebug() << "AlreadyExists"; a = a+1; alreadyexists = QString(tr("%1 doublons")).arg(a); break; } ProgressionInfo informations; informations.progression = i+1; informations.maximum = total; informations.phrase = QString("%1, %2").arg(noerror).arg(alreadyexists); informations.style = progression; emit updateBar(informations); } emit loopEnded(); }
/* * Get a file data block, perhaps allocating it on demand * if mkit. The file must be r/wlocked and melted if mkit. * * Adds disk refs for dir entries copied during melts and * considers that /archive is always melted. * * Read-ahead is not considered here. The file only records * the last accessed block number, to help the caller do RA. * */ static Memblk* dfblk(Memblk *f, ulong bno, int mkit) { ulong prev, nblks; int i, idx, nindir, type, isdir, chg; Memblk *b, *pb; daddrt *addrp; if(mkit) ismelted(f); isdir = (f->d.mode&DMDIR); if(bno != f->mf->lastbno){ f->mf->sequential = (!mkit && bno == f->mf->lastbno + 1); f->mf->lastbno = bno; } /* * bno: block # relative to the the block we are looking at. * prev: # of blocks before the current one. */ prev = 0; chg = 0; /* * Direct block? */ if(bno < nelem(f->d.dptr)){ if(mkit) b = getmelted(isdir, DBdata, &f->d.dptr[bno], &chg); else b = dbget(DBdata, f->d.dptr[bno]); if(chg) changed(f); return b; } bno -= nelem(f->d.dptr); prev += nelem(f->d.dptr); /* * Indirect block * nblks: # of data blocks addressed by the block we look at. */ nblks = Dptrperblk; for(i = 0; i < nelem(f->d.iptr); i++){ if(bno < nblks) break; bno -= nblks; prev += nblks; nblks *= Dptrperblk; } if(i == nelem(f->d.iptr)) error("offset exceeds file capacity"); ainc(&fs->nindirs[i]); type = DBptr0+i; dFprint("dfblk: indirect %s nblks %uld (ppb %ud) bno %uld\n", tname(type), nblks, Dptrperblk, bno); addrp = &f->d.iptr[i]; if(mkit) b = getmelted(isdir, type, addrp, &chg); else b = dbget(type, *addrp); if(chg) changed(f); pb = b; if(catcherror()){ mbput(pb); error(nil); } /* at the loop header: * pb: parent of b * b: DBptr block we are looking at. * addrp: ptr to b within fb. * nblks: # of data blocks addressed by b */ for(nindir = i+1; nindir >= 0; nindir--){ chg = 0; dFprint("indir %s d%#ullx nblks %uld ptrperblk %d bno %uld\n\n", tname(DBdata+nindir), *addrp, nblks, Dptrperblk, bno); idx = 0; if(nindir > 0){ nblks /= Dptrperblk; idx = bno/nblks; } if(*addrp == 0 && !mkit){ /* hole */ fprint(2, "HOLE\n"); b = nil; }else{ assert(type >= DBdata); if(mkit) b = getmelted(isdir, type, addrp, &chg); else b = dbget(type, *addrp); if(chg) changed(pb); addrp = &b->d.ptr[idx]; } mbput(pb); pb = b; USED(&b); /* force to memory in case of error */ USED(&pb); /* force to memory in case of error */ bno -= idx * nblks; prev += idx * nblks; type--; } noerror(); return b; }
/* * Caller walked down p, and now requires the nth element to be * melted, and wlocked for writing. (nth count starts at 1); * * Return the path with the version of f that we must use, * locked for writing and melted. * References kept in the path are traded for the ones returned. */ Path* dfmelt(Path **pp, int nth) { int i; Memblk *f, **fp, *nf; Path *p; ownpath(pp); p = *pp; assert(nth >= 1 && p->nf >= nth && p->nf >= 2); assert(p->f[0] == fs->root); fp = &p->f[nth-1]; /* * 1. Optimistic: Try to get a loaded melted version for f. */ followmelted(fp, Wr); f = *fp; if(!f->frozen) return p; ainc(&fs->nmelts); rwunlock(f, Wr); /* * 2. Realistic: * walk down the path, melting every frozen thing until we * reach f. Keep wlocks so melted files are not frozen while we walk. * /active is special, because it's only frozen temporarily while * creating a frozen version of the tree. Instead of melting it, * we should just wait for it. * p[0] is / * p[1] is /active */ for(;;){ followmelted(&p->f[1], Wr); if(p->f[1]->frozen == 0) break; rwunlock(p->f[1], Wr); yield(); } /* * At loop header, parent is p->f[i-1], melted and wlocked. * At the end of the loop, p->f[i] is melted and wlocked. */ for(i = 2; i < nth; i++){ followmelted(&p->f[i], Wr); if(!p->f[i]->frozen){ rwunlock(p->f[i-1], Wr); continue; } if(catcherror()){ rwunlock(p->f[i-1], Wr); rwunlock(p->f[i], Wr); error(nil); } nf = dbdup(p->f[i]); rwlock(nf, Wr); if(catcherror()){ rwunlock(nf, Wr); mbput(nf); error(nil); } dfchdentry(p->f[i-1], p->f[i]->addr, nf->addr, Mkit); noerror(); noerror(); /* committed */ rwunlock(p->f[i-1], Wr); /* parent */ rwunlock(p->f[i], Wr); /* old frozen version */ f = p->f[i]; p->f[i] = nf; assert(f->ref > 1); mbput(f); /* ref from path */ if(!catcherror()){ dbput(f, f->type, f->addr); /* p->f[i] ref from disk */ noerror(); } } return p; }