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("hjfs: 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 -- getdent");
58 if(qidcmp(d, l) != 0){
59 dprint("hjfs: 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 -- getdent");
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);
97 for(l = 0, i = fs->fstart; i < e; i++){
98 b = getbuf(d, i, TREF, 0);
103 for(j = 0; j < REFPERBLK; j++, l++)
110 else if(nbsend(fs->freelist, &l) <= 0)
117 werrstr("disk full");
126 putfree(Fs *fs, uvlong r)
130 rc = chref(fs, r, -1);
134 nbsend(fs->freelist, &r);
145 if(getfree(fs, &r) < 0)
146 sysfatal("ream: getfree: %r");
147 c = getbuf(fs->d, r, TDENTRY, 1);
150 sysfatal("ream: getbuf: %r");
151 memset(c->de, 0, sizeof(c->de));
153 strcpy(d->name, "/");
154 d->mode = DALLOC | 0775;
163 strcpy(d->name, "/");
164 d->mode = DALLOC | 0775;
174 c = getbuf(fs->d, SUPERBLK, TSUPERBLOCK, 1);
187 ch = chanattach(fs, 0);
191 chancreat(ch, "adm", DMDIR | 0775, OREAD);
193 ch = chanattach(fs, 0);
197 if(chanwalk(ch, "adm") <= 0)
199 if(chanwalk(ch, "users") > 0){
200 if(chanopen(ch, OWRITE|OTRUNC) <= 0)
202 }else if(chancreat(ch, "users", 0664, OWRITE) <= 0)
204 if(userssave(fs, ch) < 0){
214 dprint("writeusers: %r\n");
222 ch = chanattach(fs, 0);
226 if(chanwalk(ch, "adm") <= 0)
228 if(chanwalk(ch, "users") <= 0)
230 if(chanopen(ch, OREAD) < 0)
232 if(usersload(fs, ch) < 0)
239 dprint("hjfs: readusers: %r\nhjfs: using default user db\n");
247 uvlong i, firsti, lasti;
251 dprint("hjfs: reaming %s\n", d->name);
252 b = getbuf(d, SUPERBLK, TSUPERBLOCK, 1);
255 sysfatal("ream: getbuf: %r");
256 memset(&b->sb, 0, sizeof(b->sb));
257 b->sb.magic = SUPERMAGIC;
258 b->sb.size = d->size;
259 b->sb.fstart = SUPERBLK + 1;
260 fs->fstart = b->sb.fstart;
261 b->sb.fend = b->sb.fstart + HOWMANY(b->sb.size * 3, RBLOCK);
262 b->sb.qidpath = DUMPROOTQID + 1;
263 firsti = b->sb.fstart + SUPERBLK / REFPERBLK;
264 lasti = b->sb.fstart + b->sb.fend / REFPERBLK;
265 for(i = b->sb.fstart; i < b->sb.fend; i++){
266 c = getbuf(d, i, TREF, 1);
269 memset(c->refs, 0, sizeof(b->data));
270 if(i >= firsti && i <= lasti){
274 j = SUPERBLK % REFPERBLK;
276 je = b->sb.fend % REFPERBLK;
280 if(i == b->sb.fend - 1){
281 j = b->sb.size % REFPERBLK;
283 for(; j < REFPERBLK; j++)
293 dprint("hjfs: ream successful\n");
297 initfs(Dev *d, int doream, int flags)
303 fs = emalloc(sizeof(*fs));
307 b = getbuf(d, SUPERBLK, TSUPERBLOCK, 0);
308 if(b == nil || b->sb.magic != SUPERMAGIC)
310 fs->root = b->sb.root;
311 fs->fstart = b->sb.fstart;
312 fs->freelist = chancreate(sizeof(uvlong), FREELISTLEN);
318 fs->rootloc = getloc(fs, f, nil);
320 f.path = DUMPROOTQID;
321 fs->dumprootloc = getloc(fs, f, nil);
327 dprint("hjfs: fs is %s\n", d->name);
340 if((ch->flags & CHFNOLOCK) == 0)
347 if((ch->flags & CHFNOLOCK) == 0)
352 newqid(Fs *fs, uvlong *q)
356 b = getbuf(fs->d, SUPERBLK, TSUPERBLOCK, 0);
359 *q = b->sb.qidpath++;
366 getloc(Fs *fs, FLoc f, Loc *next)
371 if(next != nil && next->child != nil){
374 if(l->blk == f.blk && l->deind == f.deind){
376 qunlock(&fs->loctree);
380 }while(l != next->child);
382 l = emalloc(sizeof(*l));
386 if(fs->rootloc != nil){
387 l->gnext = fs->rootloc;
388 l->gprev = l->gnext->gprev;
392 l->gnext = l->gprev = l;
393 l->cprev = l->cnext = l;
395 if(next->child == nil)
398 l->cnext = next->child;
399 l->cprev = next->child->cprev;
404 qunlock(&fs->loctree);
409 haveloc(Fs *fs, uvlong blk, int deind, Loc *next)
416 if(l->blk == blk && l->deind == deind){
417 qunlock(&fs->loctree);
421 } while(l != next->child);
422 qunlock(&fs->loctree);
427 cloneloc(Fs *fs, Loc *l)
432 for(m = l; m != nil; m = m->next)
434 qunlock(&fs->loctree);
439 putloc(Fs *fs, Loc *l, int loop)
445 if(!loop && --l->ref <= 0)
447 while(loop && l != nil && l->ref <= 1){
449 if((l->flags & LGONE) != 0){
451 * safe to unlock here, the file is gone and
452 * we'r the last reference.
454 qunlock(&fs->loctree);
455 b = getbuf(fs->d, l->blk, TDENTRY, 0);
462 l->cnext->cprev = l->cprev;
463 l->cprev->cnext = l->cnext;
464 l->gnext->gprev = l->gprev;
465 l->gprev->gnext = l->gnext;
466 if(l->next != nil && l->next->child == l){
468 l->next->child = nil;
470 l->next->child = l->cnext;
476 for(; loop && l != nil; l = l->next)
478 qunlock(&fs->loctree);
482 dumpblk(Fs *fs, FLoc *, uvlong *l)
489 b = getbuf(fs->d, *l, TDONTCARE, 0);
492 if(getfree(fs, &n) < 0){
497 c = getbuf(fs->d, n, b->type, 1);
504 memcpy(c->offs, b->offs, sizeof(b->offs));
505 for(i = 0; i < OFFPERBLK; i++)
507 chref(fs, b->offs[i], 1);
510 memcpy(c->data, b->data, sizeof(b->data));
513 memcpy(c->de, b->de, sizeof(b->de));
514 for(d = b->de; d < &b->de[DEPERBLK]; d++){
515 if((d->mode & DALLOC) == 0)
517 if((d->type & QTTMP) != 0)
519 for(i = 0; i < NDIRECT; i++)
521 chref(fs, d->db[i], 1);
522 for(i = 0; i < NINDIRECT; i++)
524 chref(fs, d->ib[i], 1);
528 werrstr("dumpblk -- unknown type %d", b->type);
543 * getblk returns the address of a block in a file
544 * given its relative address blk
545 * the address are returned in *r
546 * mode has to be one of:
547 * - GBREAD: this block will only be read
548 * - GBWRITE: this block will be written, but don't create it
549 * if it doesn't exist
550 * - GBCREATE: this block will be written, create it if necessary
551 * - GBOVERWR: like GBCREATE, but return an empty block if a dump
553 * return value is 1 if the block existed, -1 on error
554 * a return value of 0 means the block did not exist
555 * this is only an error in case of GBREAD and GBWRITE
559 getblk(Fs *fs, FLoc *L, Buf *bd, uvlong blk, uvlong *r, int mode)
570 dprint("hjfs: getblk: dirent gone\n");
579 for(i = 0; i < NINDIRECT; i++){
586 werrstr("getblk: block offset too large");
590 for(j = 0; j <= i; j++){
592 if(mode == GBREAD || mode == GBWRITE){
597 if(getfree(fs, loc) < 0){
606 b = getbuf(fs->d, k, TINDIR, 1);
609 memset(b->offs, 0, sizeof(b->offs));
612 if(mode != GBREAD && chref(fs, *loc, 0) > 1){
613 if(dumpblk(fs, L, loc) < 0){
623 b = getbuf(fs->d, k, TINDIR, 0);
628 loc = &b->offs[blk / l];
638 if((rc = chref(fs, *loc, 0)) > 1){
639 if(mode == GBOVERWR){
646 if(dumpblk(fs, L, loc) < 0){
655 dprint("hjfs: getblk: block %lld has refcount 0\n");
656 werrstr("phase error -- getblk");
663 }else if(mode == GBCREATE || mode == GBOVERWR){
679 delindir(Fs *fs, uvlong *l, int n)
686 if(chref(fs, *l, 0) > 1){
691 b = getbuf(fs->d, *l, TINDIR, 0);
693 for(k = 0; k < OFFPERBLK; k++)
695 delindir(fs, &b->offs[k], n-1);
706 zeroes(int *a, int i)
715 delindirpart(Fs *fs, FLoc *p, uvlong *l, int *a, int n)
731 if(chref(fs, *l, 0) > 1)
733 b = getbuf(fs->d, *l, TINDIR, 0);
736 delindirpart(fs, p, &b->offs[*a], a + 1, n - 1);
737 for(k = a[0] + 1; k < OFFPERBLK; k++)
739 delindir(fs, &b->offs[k], n - 1);
745 * call willmodify() before and modified()
746 * after calling this function
749 trunc(Fs *fs, FLoc *ll, Buf *bd, uvlong size)
762 blk = HOWMANY(size, RBLOCK);
763 while(blk < NDIRECT){
765 putfree(fs, d->db[blk]);
773 for(i = 0; i < NINDIRECT; i++){
780 werrstr("phase error -- truncate");
789 for(j = 0; j <= i; j++){
794 delindirpart(fs, ll, &d->ib[i], a, i + 1);
797 for(; i < NINDIRECT; i++)
798 delindir(fs, &d->ib[i], i + 1);
807 * name == nil allows any entry to match
809 * return value 1 on success, 0 on Enoent,
813 findentry(Fs *fs, FLoc *l, Buf *b, char *name, FLoc *rl, int dump)
824 for(i = 0; i < d->size; i++){
825 if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
827 c = getbuf(fs->d, r, TDENTRY, 0);
830 for(j = 0; j < DEPERBLK; j++)
831 if((c->de[j].mode & DALLOC) != 0 &&
832 (name == nil || strcmp(c->de[j].name, name) == 0)){
833 if(dump && (c->de[j].type & QTTMP) != 0)
836 rl->Qid = c->de[j].Qid;
850 modified(Chan *ch, Dentry *d)
855 ch->loc->vers = ++d->vers;
858 typedef struct Del Del;
866 deltraverse(Fs *fs, Del *p, Buf *b, Del **last)
877 b = getbuf(fs->d, p->blk, TDENTRY, 0);
888 for(i = 0; i < s; i++){
889 rc = getblk(fs, p, b, i, &r, GBREAD);
892 c = getbuf(fs->d, r, TDENTRY, 0);
895 for(j = 0; j < DEPERBLK; j++){
897 if((d->mode & (DALLOC|DGONE)) != 0){
898 if((d->type & QTDIR) == 0){
900 memset(d, 0, sizeof(*d));
903 dd = emalloc(sizeof(Del));
921 delete(Fs *fs, FLoc *l, Buf *b)
925 Del *first, *last, *p, *q;
930 if((d->type & QTDIR) == 0){
932 memset(d, 0, sizeof(*d));
936 first = last = emalloc(sizeof(Del));
938 for(p = first; p != nil; p = p->next)
939 deltraverse(fs, p, p == first ? b : nil, &last);
940 for(p = last; p != nil; q = p->prev, free(p), p = q){
944 c = getbuf(fs->d, p->blk, TDENTRY, 0);
950 memset(d, 0, sizeof(*d));
960 * newentry() looks for a free slot in the directory
961 * and returns FLoc pointing to the slot. if no free
962 * slot is available a new block is allocated. if
963 * dump == 0, then the resulting blk from the FLoc
964 * *is not* dumped, so to finally allocate the Dentry,
965 * one has to call willmodify() on res before modyfing it.
968 newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res, int dump)
978 for(i = 0; i < d->size; i++){
979 if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
981 c = getbuf(fs->d, r, TDENTRY, 0);
984 for(j = 0; j < DEPERBLK; j++){
986 if((dd->mode & DGONE) != 0)
988 if((dd->mode & DALLOC) != 0){
989 if(strcmp(dd->name, name) == 0){
996 if(si != -1 || haveloc(fs, r, j, l))
1003 if(si == -1 && i == d->size){
1004 if(getblk(fs, l, b, i, &r, GBCREATE) >= 0){
1005 c = getbuf(fs->d, r, TDENTRY, 1);
1011 memset(c->de, 0, sizeof(c->de));
1018 if(si == -1 || sj == -1){
1019 werrstr("phase error -- create");
1022 if(getblk(fs, l, b, si, &res->blk, dump != 0 ? GBWRITE : GBREAD) <= 0)
1025 res->Qid = (Qid){0, 0, 0};