diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libdiskfs/ffs.c | 98 |
1 files changed, 79 insertions, 19 deletions
diff --git a/src/libdiskfs/ffs.c b/src/libdiskfs/ffs.c index 2342171f..d26d0ff3 100644 --- a/src/libdiskfs/ffs.c +++ b/src/libdiskfs/ffs.c @@ -15,6 +15,7 @@ static Block *ffsblockread(Fsys*, u64int); static int ffssync(Fsys*); static void ffsclose(Fsys*); +static u64int ffsxfileblock(Fsys *fs, Nfs3Handle *h, u64int offset); static Nfs3Status ffsroot(Fsys*, Nfs3Handle*); static Nfs3Status ffsgetattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*); static Nfs3Status ffslookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*); @@ -43,6 +44,7 @@ fsysopenffs(Disk *disk) fsys->_readfile = ffsreadfile; fsys->_readlink = ffsreadlink; fsys->_readdir = ffsreaddir; + fsys->fileblock = ffsxfileblock; if(ffssync(fsys) < 0) goto error; @@ -288,35 +290,60 @@ ffsdatablock(Ffs *fs, u32int bno, int size) return b; } -static Block* -ffsfileblock(Ffs *fs, Inode *ino, u32int bno, int size) +static u32int +ifetch(Ffs *fs, u32int bno, u32int off) { - int ppb; - Block *b; u32int *a; + Block *b; + + if(bno == ~0) + return ~0; + b = ffsdatablock(fs, bno, fs->blocksize); + if(b == nil) + return ~0; + a = (u32int*)b->data; + bno = a[off]; + blockput(b); + return bno; +} + +static u32int +ffsfileblockno(Ffs *fs, Inode *ino, u32int bno) +{ + int ppb; if(bno < NDADDR){ if(debug) fprint(2, "ffsfileblock %lud: direct %#lux\n", (ulong)bno, (ulong)ino->db[bno]); - return ffsdatablock(fs, ino->db[bno], size); + return ino->db[bno]; } bno -= NDADDR; ppb = fs->blocksize/4; - if(bno/ppb < NIADDR){ - if(debug) fprint(2, "ffsfileblock %lud: indirect %#lux\n", (ulong)(bno+NDADDR), - (ulong)ino->ib[bno/ppb]); - b = ffsdatablock(fs, ino->ib[bno/ppb], fs->blocksize); - if(b == nil) - return nil; - a = (u32int*)b->data; - bno = a[bno%ppb]; - if(debug) fprint(2, "ffsfileblock: indirect fetch %#lux size %d\n", (ulong)bno, size); - blockput(b); - return ffsdatablock(fs, bno, size); - } + if(bno < ppb) /* single indirect */ + return ifetch(fs, ino->ib[0], bno); + bno -= ppb; - fprint(2, "ffsfileblock %lud: too big\n", (ulong)bno+NDADDR); - return nil; + if(bno < ppb*ppb) + return ifetch(fs, ifetch(fs, ino->ib[1], bno/ppb), bno%ppb); + bno -= ppb*ppb; + + if(bno/ppb/ppb/ppb == 0) /* bno < ppb*ppb*ppb w/o overflow */ + return ifetch(fs, ifetch(fs, ifetch(fs, ino->ib[2], bno/ppb/ppb), (bno/ppb)%ppb), bno%ppb); + bno -= ppb*ppb*ppb; + + fprint(2, "ffsfileblock %lud: way too big\n", (ulong)bno+NDADDR); + return ~0; +} + +static Block* +ffsfileblock(Ffs *fs, Inode *ino, u32int bno, int size) +{ + u32int b; + + b = ffsfileblockno(fs, ino, bno); + if(b == ~0) + return nil; + return ffsdatablock(fs, b, size); } /* @@ -338,6 +365,8 @@ byte2u32(uchar *p) return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; } +static u64int iaddr; + static Nfs3Status handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino) { @@ -370,6 +399,8 @@ handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino) if((b = diskread(fs->disk, fs->blocksize, (cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize)) == nil) return Nfs3ErrIo; + iaddr = (cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize + + (ioff%fs->inosperblock)*sizeof(Inode); *ino = ((Inode*)b->data)[ioff%fs->inosperblock]; blockput(b); @@ -458,6 +489,9 @@ inoperm(Inode *ino, SunAuthUnix *au, int need) { int have; + if(au == nil) + return Nfs3Ok; + have = ino->mode&0777; if(ino->uid == au->uid) have >>= 6; @@ -680,6 +714,32 @@ ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cook return Nfs3Ok; } +static u64int +ffsxfileblock(Fsys *fsys, Nfs3Handle *h, u64int offset) +{ + u32int bno; + Inode ino; + Nfs3Status ok; + Ffs *fs; + + fs = fsys->priv; + if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok){ + nfs3errstr(ok); + return 0; + } + if(offset == 1) + return iaddr; + if(offset >= ino.size){ + werrstr("beyond end of file"); + return 0; + } + bno = offset/fs->blocksize; + bno = ffsfileblockno(fs, &ino, bno); + if(bno == ~0) + return 0; + return bno*(u64int)fs->fragsize; +} + static Nfs3Status ffsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int offset, uchar **pdata, u32int *pcount, u1int *peof) |