9 chref(Fs *fs, uvlong r, int stat)
16 i = fs->fstart + r / REFPERBLK;
18 c = getbuf(fs->d, i, TREF, 0);
21 if(stat < 0 && c->refs[j] < -stat)
33 qidcmp(Qid *a, Qid *b)
35 if(a->type != b->type)
37 if(a->path != b->path){
38 /* special case for dump, this is ok */
39 if(a->path==ROOTQID && b->path==DUMPROOTQID)
47 getdent(FLoc *l, Buf *b)
52 if((d->mode & (DGONE | DALLOC)) == 0){
53 dprint("getdent: file gone, d=%llux, l=%llud/%d %llux, callerpc %#p\n",
54 d->path, l->blk, l->deind, l->path, getcallerpc(&l));
55 werrstr("phase error -- directory entry for nonexistent file");
58 if(qidcmp(d, l) != 0){
59 dprint("getdent: wrong qid d=%llux != l=%llud/%d %llux, callerpc %#p\n",
60 d->path, l->blk, l->deind, l->path, getcallerpc(&l));
61 werrstr("phase error -- qid mismatch");
68 getfree(Fs *fs, uvlong *r)
76 while(nbrecv(fs->freelist, &l) > 0){
77 i = fs->fstart + l / REFPERBLK;
79 b = getbuf(d, i, TREF, 0);
90 b = getbuf(d, SUPERBLK, TSUPERBLOCK, 0);
92 werrstr("could not find superblock");
99 for(l = 0, i = fs->fstart; i < e; i++){
100 b = getbuf(d, i, TREF, 0);
105 for(j = 0; j < REFPERBLK; j++, l++)
111 }else if(nbsend(fs->freelist, &l) <= 0)
118 werrstr("disk full");
127 putfree(Fs *fs, uvlong r)
131 rc = chref(fs, r, -1);
135 nbsend(fs->freelist, &r);
146 if(getfree(fs, &r) < 0)
147 sysfatal("ream: getfree: %r");
148 c = getbuf(fs->d, r, TDENTRY, 1);
151 sysfatal("ream: getbuf: %r");
152 memset(c->de, 0, sizeof(c->de));
154 strcpy(d->name, "/");
155 d->mode = DALLOC | 0775;
164 strcpy(d->name, "/");
165 d->mode = DALLOC | 0775;
175 c = getbuf(fs->d, SUPERBLK, TSUPERBLOCK, 0);
189 ch = chanattach(fs, 0);
193 chancreat(ch, "adm", DMDIR | 0775, OREAD);
195 ch = chanattach(fs, 0);
199 if(chanwalk(ch, "adm") <= 0)
201 if(chanwalk(ch, "users") > 0){
202 if(chanopen(ch, OWRITE|OTRUNC) <= 0)
204 }else if(chancreat(ch, "users", 0664, OWRITE) <= 0)
206 if(userssave(fs, ch) < 0){
216 dprint("writeusers: %r\n");
224 ch = chanattach(fs, 0);
228 if(chanwalk(ch, "adm") <= 0)
230 if(chanwalk(ch, "users") <= 0)
232 if(chanopen(ch, OREAD) < 0)
234 if(usersload(fs, ch) < 0)
241 dprint("readusers: %r\nhjfs: using default user db\n");
249 uvlong i, firsti, lasti;
253 dprint("reaming %s\n", d->name);
254 b = getbuf(d, SUPERBLK, TSUPERBLOCK, 1);
257 sysfatal("ream: getbuf: %r");
258 memset(&b->sb, 0, sizeof(b->sb));
259 b->sb.magic = SUPERMAGIC;
260 b->sb.size = d->size;
261 b->sb.fstart = SUPERBLK + 1;
262 fs->fstart = b->sb.fstart;
263 b->sb.fend = b->sb.fstart + HOWMANY(b->sb.size * REFSIZ);
264 b->sb.qidpath = DUMPROOTQID + 1;
265 firsti = b->sb.fstart + SUPERBLK / REFPERBLK;
266 lasti = b->sb.fstart + b->sb.fend / REFPERBLK;
267 for(i = b->sb.fstart; i < b->sb.fend; i++){
268 c = getbuf(d, i, TREF, 1);
271 memset(c->refs, 0, sizeof(c->refs));
272 if(i >= firsti && i <= lasti){
276 j = SUPERBLK % REFPERBLK;
278 je = b->sb.fend % REFPERBLK;
282 if(i == b->sb.fend - 1){
283 j = b->sb.size % REFPERBLK;
285 for(; j < REFPERBLK; j++)
295 dprint("ream successful\n");
299 initfs(Dev *d, int doream, int flags)
305 fs = emalloc(sizeof(*fs));
309 b = getbuf(d, SUPERBLK, TSUPERBLOCK, 0);
310 if(b == nil || b->sb.magic != SUPERMAGIC)
312 fs->root = b->sb.root;
313 fs->fstart = b->sb.fstart;
314 fs->freelist = chancreate(sizeof(uvlong), FREELISTLEN);
320 fs->rootloc = getloc(fs, f, nil);
322 f.path = DUMPROOTQID;
323 fs->dumprootloc = getloc(fs, f, nil);
329 dprint("fs is %s\n", d->name);
342 if((ch->flags & CHFNOLOCK) == 0)
349 if((ch->flags & CHFNOLOCK) == 0)
354 newqid(Fs *fs, uvlong *q)
358 b = getbuf(fs->d, SUPERBLK, TSUPERBLOCK, 0);
361 *q = b->sb.qidpath++;
368 getloc(Fs *fs, FLoc f, Loc *next)
373 if(next != nil && next->child != nil){
376 if(l->blk == f.blk && l->deind == f.deind){
378 qunlock(&fs->loctree);
382 }while(l != next->child);
384 l = emalloc(sizeof(*l));
388 if(fs->rootloc != nil){
389 l->gnext = fs->rootloc;
390 l->gprev = l->gnext->gprev;
394 l->gnext = l->gprev = l;
395 l->cprev = l->cnext = l;
397 if(next->child == nil)
400 l->cnext = next->child;
401 l->cprev = next->child->cprev;
406 qunlock(&fs->loctree);
411 haveloc(Fs *fs, uvlong blk, int deind, Loc *next)
418 if(l->blk == blk && l->deind == deind){
419 qunlock(&fs->loctree);
423 } while(l != next->child);
424 qunlock(&fs->loctree);
429 cloneloc(Fs *fs, Loc *l)
434 for(m = l; m != nil; m = m->next)
436 qunlock(&fs->loctree);
441 putloc(Fs *fs, Loc *l, int loop)
447 if(!loop && --l->ref <= 0)
449 while(loop && l != nil && l->ref <= 1){
451 if((l->flags & LGONE) != 0){
453 * safe to unlock here, the file is gone and
454 * we're the last reference.
456 qunlock(&fs->loctree);
457 b = getbuf(fs->d, l->blk, TDENTRY, 0);
464 l->cnext->cprev = l->cprev;
465 l->cprev->cnext = l->cnext;
466 l->gnext->gprev = l->gprev;
467 l->gprev->gnext = l->gnext;
468 if(l->next != nil && l->next->child == l){
470 l->next->child = nil;
472 l->next->child = l->cnext;
478 for(; loop && l != nil; l = l->next)
480 qunlock(&fs->loctree);
484 dumpblk(Fs *fs, FLoc *, uvlong *l)
491 b = getbuf(fs->d, *l, TDONTCARE, 0);
494 if(getfree(fs, &n) < 0){
499 c = getbuf(fs->d, n, b->type, 1);
506 memcpy(c->offs, b->offs, sizeof(b->offs));
507 for(i = 0; i < OFFPERBLK; i++)
509 chref(fs, b->offs[i], 1);
512 memcpy(c->data, b->data, sizeof(b->data));
515 memcpy(c->de, b->de, sizeof(b->de));
516 for(d = b->de; d < &b->de[DEPERBLK]; d++){
517 if((d->mode & DALLOC) == 0)
519 if((d->type & QTTMP) != 0)
521 for(i = 0; i < NDIRECT; i++)
523 chref(fs, d->db[i], 1);
524 for(i = 0; i < NINDIRECT; i++)
526 chref(fs, d->ib[i], 1);
530 werrstr("dumpblk -- unknown type %d", b->type);
545 * getblk returns the address of a block in a file
546 * given its relative address blk
547 * the address are returned in *r
548 * mode has to be one of:
549 * - GBREAD: this block will only be read
550 * - GBWRITE: this block will be written, but don't create it
551 * if it doesn't exist
552 * - GBCREATE: this block will be written, create it if necessary
553 * - GBOVERWR: like GBCREATE, but return an empty block if a dump
555 * return value is 1 if the block existed, -1 on error
556 * a return value of 0 means the block did not exist
557 * this is only an error in case of GBREAD and GBWRITE
561 getblk(Fs *fs, FLoc *L, Buf *bd, uvlong blk, uvlong *r, int mode)
572 dprint("getblk: dirent gone\n");
581 for(i = 0; i < NINDIRECT; i++){
588 werrstr("getblk: block offset too large");
592 for(j = 0; j <= i; j++){
594 if(mode == GBREAD || mode == GBWRITE){
599 if(getfree(fs, loc) < 0){
608 b = getbuf(fs->d, k, TINDIR, 1);
611 memset(b->offs, 0, sizeof(b->offs));
614 if(mode != GBREAD && chref(fs, *loc, 0) > 1){
615 if(dumpblk(fs, L, loc) < 0){
625 b = getbuf(fs->d, k, TINDIR, 0);
630 loc = &b->offs[blk / l];
640 if((rc = chref(fs, *loc, 0)) > 1){
641 if(mode == GBOVERWR){
648 if(dumpblk(fs, L, loc) < 0){
657 dprint("getblk: block %lld has refcount 0\n");
658 werrstr("phase error -- getblk");
665 }else if(mode == GBCREATE || mode == GBOVERWR){
681 delindir(Fs *fs, uvlong *l, int n)
688 if(chref(fs, *l, 0) > 1){
693 b = getbuf(fs->d, *l, TINDIR, 0);
695 for(k = 0; k < OFFPERBLK; k++)
697 delindir(fs, &b->offs[k], n-1);
708 zeroes(int *a, int i)
717 delindirpart(Fs *fs, FLoc *p, uvlong *l, int *a, int n)
733 if(chref(fs, *l, 0) > 1)
735 b = getbuf(fs->d, *l, TINDIR, 0);
738 delindirpart(fs, p, &b->offs[*a], a + 1, n - 1);
739 for(k = a[0] + 1; k < OFFPERBLK; k++)
741 delindir(fs, &b->offs[k], n - 1);
747 * call willmodify() before and modified()
748 * after calling this function
751 trunc(Fs *fs, FLoc *ll, Buf *bd, uvlong size)
765 while(blk < NDIRECT){
767 putfree(fs, d->db[blk]);
775 for(i = 0; i < NINDIRECT; i++){
782 werrstr("phase error -- truncate");
791 for(j = 0; j <= i; j++){
796 delindirpart(fs, ll, &d->ib[i], a, i + 1);
799 for(; i < NINDIRECT; i++)
800 delindir(fs, &d->ib[i], i + 1);
809 * name == nil allows any entry to match
811 * return value 1 on success, 0 on Enoent,
815 findentry(Fs *fs, FLoc *l, Buf *b, char *name, FLoc *rl, int dump)
826 for(i = 0; i < d->size; i++){
827 if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
829 c = getbuf(fs->d, r, TDENTRY, 0);
832 for(j = 0; j < DEPERBLK; j++)
833 if((c->de[j].mode & DALLOC) != 0 &&
834 (name == nil || strcmp(c->de[j].name, name) == 0)){
835 if(dump && (c->de[j].type & QTTMP) != 0)
838 rl->Qid = c->de[j].Qid;
852 modified(Chan *ch, Dentry *d)
857 ch->loc->vers = ++d->vers;
860 typedef struct Del Del;
868 deltraverse(Fs *fs, Del *p, Buf *b, Del **last)
879 b = getbuf(fs->d, p->blk, TDENTRY, 0);
890 for(i = 0; i < s; i++){
891 rc = getblk(fs, p, b, i, &r, GBREAD);
894 c = getbuf(fs->d, r, TDENTRY, 0);
897 for(j = 0; j < DEPERBLK; j++){
899 if((d->mode & (DALLOC|DGONE)) != 0){
900 if((d->type & QTDIR) == 0){
902 memset(d, 0, sizeof(*d));
905 dd = emalloc(sizeof(Del));
923 delete(Fs *fs, FLoc *l, Buf *b)
927 Del *first, *last, *p, *q;
932 if((d->type & QTDIR) == 0){
934 memset(d, 0, sizeof(*d));
938 first = last = emalloc(sizeof(Del));
940 for(p = first; p != nil; p = p->next)
941 deltraverse(fs, p, p == first ? b : nil, &last);
942 for(p = last; p != nil; q = p->prev, free(p), p = q){
946 c = getbuf(fs->d, p->blk, TDENTRY, 0);
952 memset(d, 0, sizeof(*d));
962 * newentry() looks for a free slot in the directory
963 * and returns FLoc pointing to the slot. if no free
964 * slot is available a new block is allocated. if
965 * dump == 0, then the resulting blk from the FLoc
966 * *is not* dumped, so to finally allocate the Dentry,
967 * one has to call willmodify() on res before modyfing it.
970 newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res, int dump)
981 for(i = 0; i < d->size; i++){
982 if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
984 c = getbuf(fs->d, r, TDENTRY, 0);
987 for(j = 0; j < DEPERBLK; j++){
989 if((dd->mode & DGONE) != 0)
991 if((dd->mode & DALLOC) != 0){
992 if(strcmp(dd->name, name) == 0){
999 if(si != -1 || haveloc(fs, r, j, l))
1006 if(si == -1 && i == d->size){
1007 if(getblk(fs, l, b, i, &r, GBCREATE) >= 0){
1008 c = getbuf(fs->d, r, TDENTRY, 1);
1014 memset(c->de, 0, sizeof(c->de));
1020 if(si == -1 || sj == -1){
1021 werrstr("phase error -- create");
1024 if(getblk(fs, l, b, si, &res->blk, dump != 0 ? GBWRITE : GBREAD) <= 0)
1027 res->Qid = (Qid){0, 0, 0};