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;
44 fsys->_close = ext2close;
46 if(ext2sync(fsys) < 0)
67 ext2group(Ext2 *fs, u32int i, Block **pb)
76 addr = fs->groupaddr + i/fs->descperblock;
77 b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);
80 g = (Group*)(b->data+i%fs->descperblock*GroupSize);
86 ext2blockread(Fsys *fsys, u64int vbno)
92 u32int bno, boff, bitblock;
97 if(vbno >= fs->nblock)
104 if(bno < fs->firstblock)
105 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
107 if(bno < fs->firstblock)
110 bno -= fs->firstblock;
111 if((g = ext2group(fs, bno/fs->blockspergroup, &gb)) == nil){
113 fprint(2, "loading group: %r...");
118 fprint(2, "ext2 group %d: bitblock=%ud inodebitblock=%ud inodeaddr=%ud freeblocks=%ud freeinodes=%ud useddirs=%ud\n",
119 (int)(bno/fs->blockspergroup),
127 fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g->bitblock);
129 bitblock = g->bitblock;
130 bitpos = (u64int)bitblock*fs->blocksize;
133 if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){
135 fprint(2, "loading bitblock: %r...");
139 boff = bno%fs->blockspergroup;
140 if((bits[boff>>3] & (1<<(boff&7))) == 0){
142 fprint(2, "block %d not allocated in group %d: bitblock %d/%lld bits[%d] = %#x\n",
143 boff, bno/fs->blockspergroup,
153 bno += fs->firstblock;
154 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
158 ext2datablock(Ext2 *fs, u32int bno, int size)
161 return ext2blockread(fs->fsys, bno);
165 ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size)
173 if(bno < NDIRBLOCKS){
175 fprint(2, "fileblock %d -> %d...",
176 bno, ino->block[bno]);
177 return ext2datablock(fs, ino->block[bno], size);
180 ppb = fs->blocksize/4;
184 b = ext2datablock(fs, ino->block[INDBLOCK], fs->blocksize);
187 a = (u32int*)b->data;
190 return ext2datablock(fs, bno, size);
194 /* one double indirect */
196 b = ext2datablock(fs, ino->block[DINDBLOCK], fs->blocksize);
199 a = (u32int*)b->data;
203 b = ext2datablock(fs, pbno, fs->blocksize);
206 a = (u32int*)b->data;
209 return ext2datablock(fs, bno, size);
213 /* one triple indirect */
214 if(bno < ppb*ppb*ppb){
215 b = ext2datablock(fs, ino->block[TINDBLOCK], fs->blocksize);
218 a = (u32int*)b->data;
219 pbno = a[bno/(ppb*ppb)];
222 b = ext2datablock(fs, pbno, fs->blocksize);
225 a = (u32int*)b->data;
229 b = ext2datablock(fs, pbno, fs->blocksize);
232 a = (u32int*)b->data;
235 return ext2datablock(fs, bno, size);
238 fprint(2, "ext2fileblock %ud: too big\n", obno);
243 checksuper(Super *super)
245 if(super->magic != SUPERMAGIC){
246 werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);
264 if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
266 super = (Super*)b->data;
267 if(checksuper(super) < 0)
269 fs->blocksize = MINBLOCKSIZE<<super->logblocksize;
270 fs->nblock = super->nblock;
271 fs->ngroup = (super->nblock+super->blockspergroup-1)
272 / super->blockspergroup;
273 fs->inospergroup = super->inospergroup;
274 fs->blockspergroup = super->blockspergroup;
275 fs->inosperblock = fs->blocksize / InodeSize;
276 if(fs->blocksize == SBOFF)
280 fs->descperblock = fs->blocksize / GroupSize;
281 fs->firstblock = super->firstdatablock;
284 fsys->blocksize = fs->blocksize;
285 fsys->nblock = fs->nblock;
286 fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n",
287 fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup);
290 for(i=0; i<fs->ngroup; i++)
291 if((g = ext2group(fs, i, &b)) != nil){
292 fprint(2, "grp %d: bitblock=%d\n", i, g->bitblock);
304 mkhandle(Nfs3Handle *h, u64int ino)
316 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
320 handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
330 return Nfs3ErrBadHandle;
331 inum = byte2u32(h->h);
334 i = (inum-1) / fs->inospergroup;
336 return Nfs3ErrBadHandle;
337 ioff = (inum-1) % fs->inospergroup;
338 if((g = ext2group(fs, i, &gb)) == nil)
340 addr = g->inodeaddr + ioff/fs->inosperblock;
342 if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)
344 *ino = ((Inode*)b->data)[ioff%fs->inosperblock];
350 ext2root(Fsys *fsys, Nfs3Handle *h)
353 mkhandle(h, ROOTINODE);
363 if((ino->mode&IFMT)==IFREG)
364 size |= (u64int)ino->diracl << 32;
369 ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
374 switch(ino->mode&IFMT){
376 attr->type = Nfs3FileFifo;
379 attr->type = Nfs3FileChar;
382 attr->type = Nfs3FileDir;
385 attr->type = Nfs3FileBlock;
388 attr->type = Nfs3FileReg;
391 attr->type = Nfs3FileSymlink;
394 attr->type = Nfs3FileSocket;
398 return Nfs3ErrBadHandle;
401 attr->mode = ino->mode&07777;
402 attr->nlink = ino->nlink;
403 attr->uid = ino->uid;
404 attr->gid = ino->gid;
405 attr->size = inosize(ino);
406 attr->used = (u64int)ino->nblock*fs->blocksize;
407 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
408 rdev = ino->block[0];
409 attr->major = (rdev>>8)&0xFF;
410 attr->minor = rdev & 0xFFFF00FF;
417 attr->atime.sec = ino->atime;
418 attr->atime.nsec = 0;
419 attr->mtime.sec = ino->mtime;
420 attr->mtime.nsec = 0;
421 attr->ctime.sec = ino->ctime;
422 attr->ctime.nsec = 0;
427 ingroup(SunAuthUnix *au, uint gid)
431 for(i=0; i<au->ng; i++)
438 inoperm(Inode *ino, SunAuthUnix *au, int need)
445 have = ino->mode&0777;
446 if(ino->uid == au->uid)
448 else if(ino->gid == au->gid || ingroup(au, ino->gid))
451 if((have&need) != need)
452 return Nfs3ErrNotOwner; /* really EPERM */
457 ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
465 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
468 USED(au); /* anyone can getattr */
469 return ino2attr(fs, &ino, inum, attr);
473 ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
482 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
485 have = ino.mode&0777;
486 if(ino.uid == au->uid)
488 else if(ino.gid == au->gid || ingroup(au, ino.gid))
492 if((want&Nfs3AccessRead) && (have&AREAD))
493 *got |= Nfs3AccessRead;
494 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
495 *got |= Nfs3AccessLookup;
496 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
497 *got |= Nfs3AccessExecute;
499 return ino2attr(fs, &ino, inum, attr);
503 ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
516 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
519 if((ino.mode&IFMT) != IFDIR)
520 return Nfs3ErrNotDir;
522 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
526 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
527 if(debug) fprint(2, "%d blocks in dir...", nblock);
528 for(i=0; i<nblock; i++){
530 want = ino.size % fs->blocksize;
532 want = fs->blocksize;
533 b = ext2fileblock(fs, &ino, i, want);
535 if(debug) fprint(2, "empty block...");
544 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
550 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
555 if(4+2+2+de->namlen > de->reclen){
557 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
560 if(de->namlen == len && memcmp(de->name, name, len) == 0){
561 mkhandle(nh, de->ino);
572 ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
577 uchar *data, *dp, *dep, *p, *ep, *ndp;
587 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
590 if((ino.mode&IFMT) != IFDIR)
591 return Nfs3ErrNotDir;
593 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
596 if(cookie >= ino.size){
608 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
609 i = cookie/fs->blocksize;
610 off = cookie%fs->blocksize;
612 for(; i<nblock && !done; i++){
614 want = ino.size % fs->blocksize;
616 want = fs->blocksize;
617 b = ext2fileblock(fs, &ino, i, want);
622 memset(&e, 0, sizeof e);
626 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
631 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
635 if(debug) fprint(2, "zero inode\n");
638 if(4+2+2+de->namlen > de->reclen){
639 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);
642 if(debug) print("%.*s/%d ", de->namlen, de->name, (int)de->ino);
643 if((uchar*)de - b->data < off)
647 e.namelen = de->namlen;
648 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
649 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
667 ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
668 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
673 int skip1, tot, want, fragcount;
679 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
682 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
685 size = inosize(&ino);
692 if(offset+count > size)
695 data = malloc(count);
698 memset(data, 0, count);
700 skip1 = offset%fs->blocksize;
705 * have to read multiple blocks if we get asked for a big read.
706 * Linux NFS client assumes that if you ask for 8k and only get 4k
707 * back, the remaining 4k is zeros.
709 for(tot=0; tot<want; tot+=fragcount){
710 b = ext2fileblock(fs, &ino, (offset+tot)/fs->blocksize, fs->blocksize);
711 fragcount = fs->blocksize;
714 if(tot+fragcount > want)
715 fragcount = want - tot;
717 memmove(data, b->data+skip1, fragcount-skip1);
719 memmove(data+tot-skip1, b->data, fragcount);
724 *peof = (offset+count == size);
731 ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
740 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
742 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
750 /* BUG: assumes symlink fits in one block */
751 b = ext2fileblock(fs, &ino, 0, len);
754 if(memchr(b->data, 0, len) != nil){
758 *link = malloc(len+1);
763 memmove(*link, b->data, len);
769 if(len > sizeof ino.block)
772 *link = malloc(len+1);
775 memmove(*link, ino.block, ino.size);