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)
141 return ext2blockread(fs->fsys, bno+fs->firstblock);
145 ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size)
153 if(bno < NDIRBLOCKS){
155 fprint(2, "fileblock %d -> %d...",
156 bno, ino->block[bno]);
157 return ext2datablock(fs, ino->block[bno], size);
160 ppb = fs->blocksize/4;
164 b = ext2datablock(fs, ino->block[INDBLOCK], fs->blocksize);
167 a = (u32int*)b->data;
170 return ext2datablock(fs, bno, size);
174 /* one double indirect */
176 b = ext2datablock(fs, ino->block[DINDBLOCK], fs->blocksize);
179 a = (u32int*)b->data;
180 bno = a[(bno/ppb)%ppb];
182 b = ext2datablock(fs, bno, fs->blocksize);
185 a = (u32int*)b->data;
188 return ext2datablock(fs, bno, size);
192 /* one triple indirect */
193 if(bno < ppb*ppb*ppb){
194 b = ext2datablock(fs, ino->block[TINDBLOCK], fs->blocksize);
197 a = (u32int*)b->data;
198 bno = a[(bno/(ppb*ppb))%ppb];
200 b = ext2datablock(fs, bno, fs->blocksize);
203 a = (u32int*)b->data;
204 bno = a[(bno/ppb)%ppb];
206 b = ext2datablock(fs, bno, fs->blocksize);
209 a = (u32int*)b->data;
212 return ext2datablock(fs, bno, size);
215 fprint(2, "ext2fileblock %ud: too big\n", obno);
220 checksuper(Super *super)
222 if(super->magic != SUPERMAGIC){
223 werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);
241 if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
243 super = (Super*)b->data;
244 if(checksuper(super) < 0)
246 fs->blocksize = MINBLOCKSIZE<<super->logblocksize;
247 fs->nblock = super->nblock;
248 fs->ngroup = (super->nblock+super->blockspergroup-1)
249 / super->blockspergroup;
250 fs->inospergroup = super->inospergroup;
251 fs->blockspergroup = super->blockspergroup;
252 fs->inosperblock = fs->blocksize / InodeSize;
253 if(fs->blocksize == SBOFF)
257 fs->descperblock = fs->blocksize / GroupSize;
258 fs->firstblock = super->firstdatablock;
261 fsys->blocksize = fs->blocksize;
262 fsys->nblock = fs->nblock;
263 fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n",
264 fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup);
267 for(i=0; i<fs->ngroup; i++)
268 if((g = ext2group(fs, i, &b)) != nil){
269 fprint(2, "grp %d: bitblock=%d\n", i, g->bitblock);
281 mkhandle(Nfs3Handle *h, u64int ino)
293 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
297 handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
307 return Nfs3ErrBadHandle;
308 inum = byte2u32(h->h);
311 i = (inum-1) / fs->inospergroup;
313 return Nfs3ErrBadHandle;
314 ioff = (inum-1) % fs->inospergroup;
315 if((g = ext2group(fs, i, &gb)) == nil)
317 addr = g->inodeaddr + ioff/fs->inosperblock;
319 if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)
321 *ino = ((Inode*)b->data)[ioff%fs->inosperblock];
327 ext2root(Fsys *fsys, Nfs3Handle *h)
330 mkhandle(h, ROOTINODE);
335 ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
340 switch(ino->mode&IFMT){
342 attr->type = Nfs3FileFifo;
345 attr->type = Nfs3FileChar;
348 attr->type = Nfs3FileDir;
351 attr->type = Nfs3FileBlock;
354 attr->type = Nfs3FileReg;
357 attr->type = Nfs3FileSymlink;
360 attr->type = Nfs3FileSocket;
364 return Nfs3ErrBadHandle;
367 attr->mode = ino->mode&07777;
368 attr->nlink = ino->nlink;
369 attr->uid = ino->uid;
370 attr->gid = ino->gid;
371 attr->size = ino->size;
372 attr->used = ino->nblock*fs->blocksize;
373 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
374 rdev = ino->block[0];
375 attr->major = (rdev>>8)&0xFF;
376 attr->minor = rdev & 0xFFFF00FF;
383 attr->atime.sec = ino->atime;
384 attr->atime.nsec = 0;
385 attr->mtime.sec = ino->mtime;
386 attr->mtime.nsec = 0;
387 attr->ctime.sec = ino->ctime;
388 attr->ctime.nsec = 0;
393 ingroup(SunAuthUnix *au, uint gid)
397 for(i=0; i<au->ng; i++)
404 inoperm(Inode *ino, SunAuthUnix *au, int need)
411 have = ino->mode&0777;
412 if(ino->uid == au->uid)
414 else if(ino->gid == au->gid || ingroup(au, ino->gid))
417 if((have&need) != need)
418 return Nfs3ErrNotOwner; /* really EPERM */
423 ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
431 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
434 USED(au); /* anyone can getattr */
435 return ino2attr(fs, &ino, inum, attr);
439 ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
448 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
451 have = ino.mode&0777;
452 if(ino.uid == au->uid)
454 else if(ino.gid == au->gid || ingroup(au, ino.gid))
458 if((want&Nfs3AccessRead) && (have&AREAD))
459 *got |= Nfs3AccessRead;
460 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
461 *got |= Nfs3AccessLookup;
462 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
463 *got |= Nfs3AccessExecute;
465 return ino2attr(fs, &ino, inum, attr);
469 ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
482 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
485 if((ino.mode&IFMT) != IFDIR)
486 return Nfs3ErrNotDir;
488 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
492 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
493 if(debug) fprint(2, "%d blocks in dir...", nblock);
494 for(i=0; i<nblock; i++){
496 want = ino.size % fs->blocksize;
498 want = fs->blocksize;
499 b = ext2fileblock(fs, &ino, i, want);
501 if(debug) fprint(2, "empty block...");
510 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
516 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
521 if(4+2+2+de->namlen > de->reclen){
523 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
526 if(de->namlen == len && memcmp(de->name, name, len) == 0){
527 mkhandle(nh, de->ino);
538 ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
543 uchar *data, *dp, *dep, *p, *ep, *ndp;
553 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
556 if((ino.mode&IFMT) != IFDIR)
557 return Nfs3ErrNotDir;
559 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
562 if(cookie >= ino.size){
574 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
575 i = cookie/fs->blocksize;
576 off = cookie%fs->blocksize;
578 for(; i<nblock && !done; i++){
580 want = ino.size % fs->blocksize;
582 want = fs->blocksize;
583 b = ext2fileblock(fs, &ino, i, want);
588 memset(&e, 0, sizeof e);
592 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
597 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
601 if(debug) fprint(2, "zero inode\n");
604 if(4+2+2+de->namlen > de->reclen){
605 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);
608 if(de->name[de->namlen] != 0){
609 if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
612 if(debug) print("%s/%d ", de->name, (int)de->ino);
613 if((uchar*)de - b->data < off)
617 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
618 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
636 ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
637 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
642 int off, want, fragcount;
647 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
650 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
653 if(offset >= ino.size){
659 if(offset+count > ino.size)
660 count = ino.size-offset;
661 if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
662 count = fs->blocksize - offset%fs->blocksize;
664 data = malloc(count);
668 want = offset%fs->blocksize+count;
669 if(want%fs->blocksize)
670 want += fs->blocksize - want%fs->blocksize;
672 b = ext2fileblock(fs, &ino, offset/fs->blocksize, want);
674 /* BUG: distinguish sparse file from I/O error */
675 memset(data, 0, count);
677 off = offset%fs->blocksize;
678 fragcount = count; /* need signed variable */
679 if(off+fragcount > b->len){
680 fragcount = b->len - off;
685 memmove(data, b->data+off, fragcount);
689 *peof = (offset+count == ino.size);
696 ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
705 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
707 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
715 /* BUG: assumes symlink fits in one block */
716 b = ext2fileblock(fs, &ino, 0, len);
719 if(memchr(b->data, 0, len) != nil){
723 *link = malloc(len+1);
728 memmove(*link, b->data, len);
734 if(len > sizeof ino.block)
737 *link = malloc(len+1);
740 memmove(*link, ino.block, ino.size);