11 static int ext2sync(Fsys*);
12 static void ext2close(Fsys*);
13 static Block* ext2blockread(Fsys*, u64int);
15 static Nfs3Status ext2root(Fsys*, Nfs3Handle*);
16 static Nfs3Status ext2getattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);
17 static Nfs3Status ext2lookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);
18 static Nfs3Status ext2readfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
19 static Nfs3Status ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);
20 static Nfs3Status ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
21 static Nfs3Status ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr);
24 fsysopenext2(Disk *disk)
29 fsys = emalloc(sizeof(Fsys));
30 fs = emalloc(sizeof(Ext2));
35 fsys->_readblock = ext2blockread;
36 fsys->_sync = ext2sync;
37 fsys->_root = ext2root;
38 fsys->_getattr = ext2getattr;
39 fsys->_access = ext2access;
40 fsys->_lookup = ext2lookup;
41 fsys->_readfile = ext2readfile;
42 fsys->_readlink = ext2readlink;
43 fsys->_readdir = ext2readdir;
45 if(ext2sync(fsys) < 0)
66 ext2group(Ext2 *fs, u32int i, Block **pb)
75 addr = fs->groupaddr + i/fs->descperblock;
76 b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);
79 g = (Group*)(b->data+i%fs->descperblock*GroupSize);
85 ext2blockread(Fsys *fsys, u64int vbno)
95 if(vbno >= fs->nblock)
102 if(bno < fs->firstblock)
103 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
105 if(bno < fs->firstblock)
108 bno -= fs->firstblock;
109 if((g = ext2group(fs, bno/fs->blockspergroup, &gb)) == nil){
111 fprint(2, "loading group: %r...");
115 // fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g->bitblock);
117 if((bitb = diskread(fs->disk, fs->blocksize, (u64int)g->bitblock*fs->blocksize)) == nil){
119 fprint(2, "loading bitblock: %r...");
124 boff = bno%fs->blockspergroup;
125 if((bits[boff>>3] & (1<<(boff&7))) == 0){
127 fprint(2, "block %d not allocated...", bno);
133 bno += fs->firstblock;
134 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
138 ext2datablock(Ext2 *fs, u32int bno, int size)
140 return ext2blockread(fs->fsys, bno+fs->firstblock);
144 ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size)
152 if(bno < NDIRBLOCKS){
154 fprint(2, "fileblock %d -> %d...",
155 bno, ino->block[bno]);
156 return ext2datablock(fs, ino->block[bno], size);
159 ppb = fs->blocksize/4;
163 b = ext2datablock(fs, ino->block[INDBLOCK], fs->blocksize);
166 a = (u32int*)b->data;
169 return ext2datablock(fs, bno, size);
173 /* one double indirect */
175 b = ext2datablock(fs, ino->block[DINDBLOCK], fs->blocksize);
178 a = (u32int*)b->data;
179 bno = a[(bno/ppb)%ppb];
181 b = ext2datablock(fs, bno, fs->blocksize);
184 a = (u32int*)b->data;
187 return ext2datablock(fs, bno, size);
191 /* one triple indirect */
192 if(bno < ppb*ppb*ppb){
193 b = ext2datablock(fs, ino->block[TINDBLOCK], fs->blocksize);
196 a = (u32int*)b->data;
197 bno = a[(bno/(ppb*ppb))%ppb];
199 b = ext2datablock(fs, bno, fs->blocksize);
202 a = (u32int*)b->data;
203 bno = a[(bno/ppb)%ppb];
205 b = ext2datablock(fs, bno, fs->blocksize);
208 a = (u32int*)b->data;
211 return ext2datablock(fs, bno, size);
214 fprint(2, "ext2fileblock %llud: too big\n", obno);
219 checksuper(Super *super)
221 if(super->magic != SUPERMAGIC){
222 werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);
240 if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
242 super = (Super*)b->data;
243 if(checksuper(super) < 0)
245 fs->blocksize = MINBLOCKSIZE<<super->logblocksize;
246 fs->nblock = super->nblock;
247 fs->ngroup = (super->nblock+super->blockspergroup-1)
248 / super->blockspergroup;
249 fs->inospergroup = super->inospergroup;
250 fs->blockspergroup = super->blockspergroup;
251 fs->inosperblock = fs->blocksize / InodeSize;
252 if(fs->blocksize == SBOFF)
256 fs->descperblock = fs->blocksize / GroupSize;
257 fs->firstblock = super->firstdatablock;
260 fsys->blocksize = fs->blocksize;
261 fsys->nblock = fs->nblock;
262 fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n",
263 fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup);
266 for(i=0; i<fs->ngroup; i++)
267 if((g = ext2group(fs, i, &b)) != nil){
268 fprint(2, "grp %d: bitblock=%d\n", i, g->bitblock);
280 mkhandle(Nfs3Handle *h, u64int ino)
292 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
296 handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
306 return Nfs3ErrBadHandle;
307 inum = byte2u32(h->h);
310 i = (inum-1) / fs->inospergroup;
312 return Nfs3ErrBadHandle;
313 ioff = (inum-1) % fs->inospergroup;
314 if((g = ext2group(fs, i, &gb)) == nil)
316 addr = g->inodeaddr + ioff/fs->inosperblock;
318 if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)
320 *ino = ((Inode*)b->data)[ioff%fs->inosperblock];
326 ext2root(Fsys *fsys, Nfs3Handle *h)
328 mkhandle(h, ROOTINODE);
333 ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
338 switch(ino->mode&IFMT){
340 attr->type = Nfs3FileFifo;
343 attr->type = Nfs3FileChar;
346 attr->type = Nfs3FileDir;
349 attr->type = Nfs3FileBlock;
352 attr->type = Nfs3FileReg;
355 attr->type = Nfs3FileSymlink;
358 attr->type = Nfs3FileSocket;
362 return Nfs3ErrBadHandle;
365 attr->mode = ino->mode&07777;
366 attr->nlink = ino->nlink;
367 attr->uid = ino->uid;
368 attr->gid = ino->gid;
369 attr->size = ino->size;
370 attr->used = ino->nblock*fs->blocksize;
371 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
372 rdev = ino->block[0];
373 attr->major = (rdev>>8)&0xFF;
374 attr->minor = rdev & 0xFFFF00FF;
381 attr->atime.sec = ino->atime;
382 attr->atime.nsec = 0;
383 attr->mtime.sec = ino->mtime;
384 attr->mtime.nsec = 0;
385 attr->ctime.sec = ino->ctime;
386 attr->ctime.nsec = 0;
391 ingroup(SunAuthUnix *au, uint gid)
395 for(i=0; i<au->ng; i++)
402 inoperm(Inode *ino, SunAuthUnix *au, int need)
409 have = ino->mode&0777;
410 if(ino->uid == au->uid)
412 else if(ino->gid == au->gid || ingroup(au, ino->gid))
415 if((have&need) != need)
416 return Nfs3ErrNotOwner; /* really EPERM */
421 ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
429 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
432 USED(au); /* anyone can getattr */
433 return ino2attr(fs, &ino, inum, attr);
437 ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
446 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
449 have = ino.mode&0777;
450 if(ino.uid == au->uid)
452 else if(ino.gid == au->gid || ingroup(au, ino.gid))
456 if((want&Nfs3AccessRead) && (have&AREAD))
457 *got |= Nfs3AccessRead;
458 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
459 *got |= Nfs3AccessLookup;
460 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
461 *got |= Nfs3AccessExecute;
463 return ino2attr(fs, &ino, inum, attr);
467 ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
480 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
483 if((ino.mode&IFMT) != IFDIR)
484 return Nfs3ErrNotDir;
486 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
490 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
491 if(debug) fprint(2, "%d blocks in dir...", nblock);
492 for(i=0; i<nblock; i++){
494 want = ino.size % fs->blocksize;
496 want = fs->blocksize;
497 b = ext2fileblock(fs, &ino, i, want);
499 if(debug) fprint(2, "empty block...");
508 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
514 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
519 if(4+2+2+de->namlen > de->reclen){
521 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
524 if(de->namlen == len && memcmp(de->name, name, len) == 0){
525 mkhandle(nh, de->ino);
536 ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
541 uchar *data, *dp, *dep, *p, *ep, *ndp;
551 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
554 if((ino.mode&IFMT) != IFDIR)
555 return Nfs3ErrNotDir;
557 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
560 if(cookie >= ino.size){
572 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
573 i = cookie/fs->blocksize;
574 off = cookie%fs->blocksize;
576 for(; i<nblock && !done; i++){
578 want = ino.size % fs->blocksize;
580 want = fs->blocksize;
581 b = ext2fileblock(fs, &ino, i, want);
586 memset(&e, 0, sizeof e);
590 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
595 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
599 if(debug) fprint(2, "zero inode\n");
602 if(4+2+2+de->namlen > de->reclen){
603 if(debug) fprint(2, "bad namlen %d reclen %d at offset %d of %d\n", de->namlen, de->reclen, (int)(p-b->data), b->len);
606 if(de->name[de->namlen] != 0){
607 if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
610 if(debug) print("%s/%d ", de->name, (int)de->ino);
611 if((uchar*)de - b->data < off)
615 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
616 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
634 ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
635 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
640 int off, want, fragcount;
645 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
648 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
651 if(offset >= ino.size){
657 if(offset+count > ino.size)
658 count = ino.size-offset;
659 if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
660 count = fs->blocksize - offset%fs->blocksize;
662 data = malloc(count);
666 want = offset%fs->blocksize+count;
667 if(want%fs->blocksize)
668 want += fs->blocksize - want%fs->blocksize;
670 b = ext2fileblock(fs, &ino, offset/fs->blocksize, want);
672 /* BUG: distinguish sparse file from I/O error */
673 memset(data, 0, count);
675 off = offset%fs->blocksize;
676 fragcount = count; /* need signed variable */
677 if(off+fragcount > b->len){
678 fragcount = b->len - off;
683 memmove(data, b->data+off, fragcount);
687 *peof = (offset+count == ino.size);
694 ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
703 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
705 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
713 /* BUG: assumes symlink fits in one block */
714 b = ext2fileblock(fs, &ino, 0, len);
717 if(memchr(b->data, 0, len) != nil){
721 *link = malloc(len+1);
726 memmove(*link, b->data, len);
732 if(len > sizeof ino.block)
735 *link = malloc(len+1);
738 memmove(*link, ino.block, ino.size);