mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-24 11:41:58 +00:00
File system access library.
This commit is contained in:
parent
be7cbb4ef2
commit
0c98da8bf8
16 changed files with 2967 additions and 0 deletions
94
include/diskfs.h
Normal file
94
include/diskfs.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* Copyright (c) Russ Cox, MIT; see src/libdiskfs/COPYRIGHT */
|
||||
|
||||
AUTOLIB(diskfs)
|
||||
|
||||
typedef struct Block Block;
|
||||
typedef struct Disk Disk;
|
||||
typedef struct Fsys Fsys;
|
||||
|
||||
#ifndef _NFS3H_ /* in case sunrpc.h, nfs3.h are not included */
|
||||
typedef struct SunAuthUnix SunAuthUnix;
|
||||
typedef struct Nfs3Attr Nfs3Attr;
|
||||
typedef struct Nfs3Entry Nfs3Entry;
|
||||
typedef struct Nfs3Handle Nfs3Handle;
|
||||
typedef int Nfs3Status;
|
||||
#endif
|
||||
struct VtCache;
|
||||
|
||||
struct Disk
|
||||
{
|
||||
Block *(*_read)(Disk *disk, u32int count, u64int offset);
|
||||
int (*_sync)(Disk*);
|
||||
void (*_close)(Disk*);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
Disk *disk;
|
||||
u32int len;
|
||||
uchar *data;
|
||||
void (*_close)(Block*);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct Fsys
|
||||
{
|
||||
u32int blocksize;
|
||||
u32int nblock;
|
||||
char *type;
|
||||
|
||||
Disk *disk;
|
||||
Block *(*_readblock)(Fsys *fsys, u64int blockno);
|
||||
int (*_sync)(Fsys *fsys);
|
||||
void (*_close)(Fsys *fsys);
|
||||
|
||||
Nfs3Status (*_root)(Fsys*, Nfs3Handle*);
|
||||
Nfs3Status (*_access)(Fsys*, SunAuthUnix*, Nfs3Handle*, u32int, u32int*, Nfs3Attr*);
|
||||
Nfs3Status (*_lookup)(Fsys*, SunAuthUnix*, Nfs3Handle*, char*, Nfs3Handle*);
|
||||
Nfs3Status (*_getattr)(Fsys*, SunAuthUnix*, Nfs3Handle*, Nfs3Attr*);
|
||||
Nfs3Status (*_readdir)(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, u32int count, u64int cookie, uchar**, u32int*, uchar*);
|
||||
Nfs3Status (*_readfile)(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, u32int count, u64int offset, uchar**, u32int*, uchar*);
|
||||
Nfs3Status (*_readlink)(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, char **link);
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct Handle
|
||||
{
|
||||
uchar h[64];
|
||||
int len;
|
||||
};
|
||||
|
||||
void blockdump(Block *b, char *desc);
|
||||
void blockput(Block *b);
|
||||
|
||||
Disk* diskcache(Disk*, uint, uint);
|
||||
Disk* diskopenventi(struct VtCache*, uchar*);
|
||||
Disk* diskopenfile(char *file);
|
||||
|
||||
Disk* diskopen(char *file);
|
||||
void diskclose(Disk *disk);
|
||||
Block* diskread(Disk *disk, u32int, u64int offset);
|
||||
int disksync(Disk *disk);
|
||||
|
||||
Fsys* fsysopenffs(Disk*);
|
||||
Fsys* fsysopenkfs(Disk*);
|
||||
Fsys* fsysopenext2(Disk*);
|
||||
Fsys* fsysopenfat(Disk*);
|
||||
|
||||
Fsys* fsysopen(Disk *disk);
|
||||
Block* fsysreadblock(Fsys *fsys, u64int blockno);
|
||||
int fsyssync(Fsys *fsys);
|
||||
void fsysclose(Fsys *fsys);
|
||||
|
||||
Nfs3Status fsysroot(Fsys *fsys, Nfs3Handle *h);
|
||||
Nfs3Status fsyslookup(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, char *name, Nfs3Handle *nh);
|
||||
Nfs3Status fsysgetattr(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, Nfs3Attr *attr);
|
||||
Nfs3Status fsysreaddir(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, u32int count, u64int cookie, uchar **e, u32int *ne, uchar*);
|
||||
Nfs3Status fsysreadfile(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, uchar*);
|
||||
Nfs3Status fsysreadlink(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, char **plink);
|
||||
Nfs3Status fsysaccess(Fsys *fsys, SunAuthUnix*, Nfs3Handle*, u32int, u32int*, Nfs3Attr*);
|
||||
void* emalloc(ulong size); /* provided by caller */
|
||||
|
||||
extern int allowall;
|
27
src/libdiskfs/COPYRIGHT
Normal file
27
src/libdiskfs/COPYRIGHT
Normal file
|
@ -0,0 +1,27 @@
|
|||
This software was developed as part of a project at MIT:
|
||||
$PLAN9/src/libdiskfs/*
|
||||
$PLAN9/include/diskfs.h
|
||||
$PLAN9/src/cmd/vbackup/*
|
||||
|
||||
Copyright (c) 2005 Russ Cox,
|
||||
Massachusetts Institute of Technology
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
51
src/libdiskfs/block.c
Normal file
51
src/libdiskfs/block.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
void
|
||||
blockdump(Block *bb, char *desc)
|
||||
{
|
||||
uchar *p, *ep;
|
||||
int i;
|
||||
Biobuf b;
|
||||
|
||||
Binit(&b, 2, OWRITE);
|
||||
|
||||
Bprint(&b, "%s\n", desc);
|
||||
|
||||
p = bb->data;
|
||||
ep = bb->data + bb->len;
|
||||
|
||||
while(p < ep){
|
||||
for(i=0; i<16; i++){
|
||||
if(p+i < ep)
|
||||
Bprint(&b, "%.2ux ", p[i]);
|
||||
else
|
||||
Bprint(&b, " ");
|
||||
if(i==7)
|
||||
Bprint(&b, "- ");
|
||||
}
|
||||
Bprint(&b, " ");
|
||||
for(i=0; i<16; i++){
|
||||
if(p+i < ep)
|
||||
Bprint(&b, "%c", p[i] >= 0x20 && p[i] <= 0x7F ? p[i] : '.');
|
||||
else
|
||||
Bprint(&b, " ");
|
||||
}
|
||||
p += 16;
|
||||
Bprint(&b, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
blockput(Block *b)
|
||||
{
|
||||
if(b == nil)
|
||||
return;
|
||||
if(!b->_close){
|
||||
fprint(2, "no blockPut\n");
|
||||
abort();
|
||||
}
|
||||
(*b->_close)(b);
|
||||
}
|
311
src/libdiskfs/cache.c
Normal file
311
src/libdiskfs/cache.c
Normal file
|
@ -0,0 +1,311 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
/*
|
||||
* Disk cache. Caches by offset, so higher levels have
|
||||
* to deal with alignment issues (if we get asked for the
|
||||
* blocks at offsets 0 and 1, we'll do two reads.
|
||||
*/
|
||||
|
||||
typedef struct DiskCache DiskCache;
|
||||
typedef struct DiskCacheBlock DiskCacheBlock;
|
||||
|
||||
struct DiskCache
|
||||
{
|
||||
Disk disk;
|
||||
Disk *subdisk;
|
||||
DiskCacheBlock **h;
|
||||
DiskCacheBlock *lruhead;
|
||||
DiskCacheBlock *lrutail;
|
||||
int nhash;
|
||||
int blocksize;
|
||||
Lock lk;
|
||||
};
|
||||
|
||||
struct DiskCacheBlock
|
||||
{
|
||||
Block block;
|
||||
Block *subblock;
|
||||
Lock lk;
|
||||
int ref;
|
||||
DiskCache *dc;
|
||||
DiskCacheBlock *next;
|
||||
DiskCacheBlock *lrunext;
|
||||
DiskCacheBlock *lruprev;
|
||||
u64int offset;
|
||||
};
|
||||
|
||||
static void
|
||||
addtohash(DiskCache *d, DiskCacheBlock *b, u64int offset)
|
||||
{
|
||||
int h;
|
||||
|
||||
if(b->offset != ~(u64int)0){
|
||||
fprint(2, "bad offset in addtohash\n");
|
||||
return;
|
||||
}
|
||||
b->offset = offset;
|
||||
h = offset % d->nhash;
|
||||
b->next = d->h[h];
|
||||
d->h[h] = b;
|
||||
}
|
||||
|
||||
static void
|
||||
delfromhash(DiskCache *d, DiskCacheBlock *b)
|
||||
{
|
||||
int h;
|
||||
DiskCacheBlock **l;
|
||||
|
||||
if(b->offset == ~(u64int)0)
|
||||
return;
|
||||
|
||||
h = b->offset % d->nhash;
|
||||
for(l=&d->h[h]; *l; l=&(*l)->next)
|
||||
if(*l == b){
|
||||
*l = b->next;
|
||||
b->offset = ~(u64int)0;
|
||||
return;
|
||||
}
|
||||
fprint(2, "delfromhash: didn't find in hash table\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
putmru(DiskCache *d, DiskCacheBlock *b)
|
||||
{
|
||||
b->lruprev = nil;
|
||||
b->lrunext = d->lruhead;
|
||||
d->lruhead = b;
|
||||
if(b->lrunext == nil)
|
||||
d->lrutail = b;
|
||||
else
|
||||
b->lrunext->lruprev = b;
|
||||
}
|
||||
|
||||
static void
|
||||
putlru(DiskCache *d, DiskCacheBlock *b)
|
||||
{
|
||||
b->lruprev = d->lrutail;
|
||||
b->lrunext = nil;
|
||||
d->lrutail = b;
|
||||
if(b->lruprev == nil)
|
||||
d->lruhead = b;
|
||||
else
|
||||
b->lruprev->lrunext = b;
|
||||
}
|
||||
|
||||
static void
|
||||
delfromlru(DiskCache *d, DiskCacheBlock *b)
|
||||
{
|
||||
if(b->lruprev)
|
||||
b->lruprev->lrunext = b->lrunext;
|
||||
else
|
||||
d->lruhead = b->lrunext;
|
||||
if(b->lrunext)
|
||||
b->lrunext->lruprev = b->lruprev;
|
||||
else
|
||||
d->lrutail = b->lruprev;
|
||||
}
|
||||
|
||||
static DiskCacheBlock*
|
||||
getlru(DiskCache *d)
|
||||
{
|
||||
DiskCacheBlock *b;
|
||||
|
||||
b = d->lrutail;
|
||||
if(b){
|
||||
delfromlru(d, b);
|
||||
delfromhash(d, b);
|
||||
blockput(b->subblock);
|
||||
b->subblock = nil;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
static DiskCacheBlock*
|
||||
findblock(DiskCache *d, u64int offset)
|
||||
{
|
||||
int h;
|
||||
DiskCacheBlock *b;
|
||||
|
||||
h = offset % d->nhash;
|
||||
for(b=d->h[h]; b; b=b->next)
|
||||
if(b->offset == offset)
|
||||
return b;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static DiskCacheBlock*
|
||||
diskcachereadbig(DiskCache *d, u64int offset)
|
||||
{
|
||||
Block *b;
|
||||
DiskCacheBlock *dcb;
|
||||
|
||||
lock(&d->lk);
|
||||
dcb = findblock(d, offset);
|
||||
if(dcb){
|
||||
//fprint(2, "found %llud in cache %p\n", (uvlong)offset, dcb);
|
||||
if(dcb->ref++ == 0)
|
||||
delfromlru(d, dcb);
|
||||
unlock(&d->lk);
|
||||
return dcb;
|
||||
}
|
||||
|
||||
dcb = getlru(d);
|
||||
unlock(&d->lk);
|
||||
if(dcb == nil){
|
||||
fprint(2, "diskcacheread: all blocks in use\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
b = diskread(d->subdisk, d->blocksize, offset);
|
||||
lock(&d->lk);
|
||||
if(b == nil){
|
||||
putlru(d, dcb);
|
||||
dcb = nil;
|
||||
}else{
|
||||
//fprint(2, "read %llud from disk %p\n", (uvlong)offset, dcb);
|
||||
dcb->subblock = b;
|
||||
dcb->ref++;
|
||||
addtohash(d, dcb, offset);
|
||||
}
|
||||
unlock(&d->lk);
|
||||
return dcb;
|
||||
}
|
||||
|
||||
static void
|
||||
diskcacheblockclose(Block *bb)
|
||||
{
|
||||
DiskCacheBlock *b = bb->priv;
|
||||
|
||||
lock(&b->dc->lk);
|
||||
if(--b->ref == 0)
|
||||
putmru(b->dc, b);
|
||||
unlock(&b->dc->lk);
|
||||
free(bb);
|
||||
}
|
||||
|
||||
static Block*
|
||||
diskcacheread(Disk *dd, u32int len, u64int offset)
|
||||
{
|
||||
int frag, dlen;
|
||||
DiskCache *d = (DiskCache*)dd;
|
||||
DiskCacheBlock *dcb;
|
||||
Block *b;
|
||||
|
||||
if(offset/d->blocksize != (offset+len-1)/d->blocksize){
|
||||
fprint(2, "diskBigRead: request for block crossing big block boundary\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
b = mallocz(sizeof(Block), 1);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
|
||||
frag = offset%d->blocksize;
|
||||
|
||||
dcb = diskcachereadbig(d, offset-frag);
|
||||
if(dcb == nil){
|
||||
free(b);
|
||||
return nil;
|
||||
}
|
||||
b->priv = dcb;
|
||||
b->_close = diskcacheblockclose;
|
||||
b->data = dcb->subblock->data+frag;
|
||||
|
||||
dlen = dcb->subblock->len;
|
||||
if(frag+len >= dlen){
|
||||
if(frag >= dlen){
|
||||
blockput(b);
|
||||
return nil;
|
||||
}
|
||||
len = dlen-frag;
|
||||
}
|
||||
b->len = len;
|
||||
//fprint(2, "offset %llud at pointer %p %lux\n", (uvlong)offset, b->data, *(ulong*)(b->data+4));
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's okay to remove these from the hash table.
|
||||
* Either the block is in use by someone or it is on
|
||||
* the lru list. If it's in use it will get put on the lru
|
||||
* list once the refs go away.
|
||||
*/
|
||||
static int
|
||||
diskcachesync(Disk *dd)
|
||||
{
|
||||
DiskCache *d = (DiskCache*)dd;
|
||||
DiskCacheBlock *b, *nextb;
|
||||
int i;
|
||||
|
||||
lock(&d->lk);
|
||||
for(i=0; i<d->nhash; i++){
|
||||
for(b=d->h[i]; b; b=nextb){
|
||||
nextb = b->next;
|
||||
b->next = nil;
|
||||
b->offset = ~(u64int)0;
|
||||
}
|
||||
d->h[i] = nil;
|
||||
}
|
||||
unlock(&d->lk);
|
||||
return disksync(d->subdisk);
|
||||
}
|
||||
|
||||
static void
|
||||
diskcacheclose(Disk *dd)
|
||||
{
|
||||
DiskCacheBlock *b;
|
||||
DiskCache *d = (DiskCache*)dd;
|
||||
|
||||
diskclose(d->subdisk);
|
||||
for(b=d->lruhead; b; b=b->lrunext)
|
||||
blockput(b->subblock);
|
||||
free(d);
|
||||
}
|
||||
|
||||
/* needn't be fast */
|
||||
static int
|
||||
isprime(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=2; i*i<=n; i++)
|
||||
if(n%i == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Disk*
|
||||
diskcache(Disk *subdisk, uint blocksize, uint ncache)
|
||||
{
|
||||
int nhash, i;
|
||||
DiskCache *d;
|
||||
DiskCacheBlock *b;
|
||||
|
||||
nhash = ncache;
|
||||
while(nhash > 1 && !isprime(nhash))
|
||||
nhash--;
|
||||
d = mallocz(sizeof(DiskCache)+ncache*sizeof(DiskCacheBlock)+nhash*sizeof(DiskCacheBlock*), 1);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
|
||||
b = (DiskCacheBlock*)&d[1];
|
||||
d->h = (DiskCacheBlock**)&b[ncache];
|
||||
d->nhash = nhash;
|
||||
d->blocksize = blocksize;
|
||||
d->subdisk = subdisk;
|
||||
d->disk._read = diskcacheread;
|
||||
d->disk._sync = diskcachesync;
|
||||
d->disk._close = diskcacheclose;
|
||||
|
||||
for(i=0; i<ncache; i++){
|
||||
b[i].block._close = diskcacheblockclose;
|
||||
b[i].offset = ~(u64int)0;
|
||||
b[i].dc = d;
|
||||
putlru(d, &b[i]);
|
||||
}
|
||||
|
||||
return &d->disk;
|
||||
}
|
39
src/libdiskfs/disk.c
Normal file
39
src/libdiskfs/disk.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
Block*
|
||||
diskread(Disk *disk, u32int count, u64int offset)
|
||||
{
|
||||
if(disk == nil)
|
||||
return nil;
|
||||
|
||||
if(!disk->_read){
|
||||
werrstr("no disk read dispatch function");
|
||||
return nil;
|
||||
}
|
||||
return (*disk->_read)(disk, count, offset);
|
||||
}
|
||||
|
||||
int
|
||||
disksync(Disk *disk)
|
||||
{
|
||||
if(disk == nil)
|
||||
return 0;
|
||||
if(!disk->_sync)
|
||||
return 0;
|
||||
return (*disk->_sync)(disk);
|
||||
}
|
||||
|
||||
void
|
||||
diskclose(Disk *disk)
|
||||
{
|
||||
if(disk == nil)
|
||||
return;
|
||||
if(!disk->_close){
|
||||
fprint(2, "no diskClose\n");
|
||||
abort();
|
||||
}
|
||||
(*disk->_close)(disk);
|
||||
}
|
742
src/libdiskfs/ext2.c
Normal file
742
src/libdiskfs/ext2.c
Normal file
|
@ -0,0 +1,742 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <sunrpc.h>
|
||||
#include <nfs3.h>
|
||||
#include <diskfs.h>
|
||||
#include "ext2.h"
|
||||
|
||||
#define debug 1
|
||||
|
||||
static int ext2sync(Fsys*);
|
||||
static void ext2close(Fsys*);
|
||||
static Block* ext2blockread(Fsys*, u64int);
|
||||
|
||||
static Nfs3Status ext2root(Fsys*, Nfs3Handle*);
|
||||
static Nfs3Status ext2getattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);
|
||||
static Nfs3Status ext2lookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);
|
||||
static Nfs3Status ext2readfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
|
||||
static Nfs3Status ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);
|
||||
static Nfs3Status ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
|
||||
static Nfs3Status ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr);
|
||||
|
||||
Fsys*
|
||||
fsysopenext2(Disk *disk)
|
||||
{
|
||||
Ext2 *fs;
|
||||
Fsys *fsys;
|
||||
|
||||
fsys = emalloc(sizeof(Fsys));
|
||||
fs = emalloc(sizeof(Ext2));
|
||||
fs->disk = disk;
|
||||
fsys->priv = fs;
|
||||
fs->fsys = fsys;
|
||||
fsys->type = "ext2";
|
||||
fsys->_readblock = ext2blockread;
|
||||
fsys->_sync = ext2sync;
|
||||
fsys->_root = ext2root;
|
||||
fsys->_getattr = ext2getattr;
|
||||
fsys->_access = ext2access;
|
||||
fsys->_lookup = ext2lookup;
|
||||
fsys->_readfile = ext2readfile;
|
||||
fsys->_readlink = ext2readlink;
|
||||
fsys->_readdir = ext2readdir;
|
||||
|
||||
if(ext2sync(fsys) < 0)
|
||||
goto error;
|
||||
|
||||
return fsys;
|
||||
|
||||
error:
|
||||
ext2close(fsys);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
ext2close(Fsys *fsys)
|
||||
{
|
||||
Ext2 *fs;
|
||||
|
||||
fs = fsys->priv;
|
||||
free(fs);
|
||||
free(fsys);
|
||||
}
|
||||
|
||||
static Group*
|
||||
ext2group(Ext2 *fs, u32int i, Block **pb)
|
||||
{
|
||||
Block *b;
|
||||
u64int addr;
|
||||
Group *g;
|
||||
|
||||
if(i >= fs->ngroup)
|
||||
return nil;
|
||||
|
||||
addr = fs->groupaddr + i/fs->descperblock;
|
||||
b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
g = (Group*)(b->data+i%fs->descperblock*GroupSize);
|
||||
*pb = b;
|
||||
return g;
|
||||
}
|
||||
|
||||
static Block*
|
||||
ext2blockread(Fsys *fsys, u64int vbno)
|
||||
{
|
||||
Block *bitb;
|
||||
Group *g;
|
||||
Block *gb;
|
||||
uchar *bits;
|
||||
u32int bno, boff;
|
||||
Ext2 *fs;
|
||||
|
||||
fs = fsys->priv;
|
||||
if(vbno >= fs->nblock)
|
||||
return nil;
|
||||
bno = vbno;
|
||||
if(bno != vbno)
|
||||
return nil;
|
||||
|
||||
/*
|
||||
if(bno < fs->firstblock)
|
||||
return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
|
||||
*/
|
||||
if(bno < fs->firstblock)
|
||||
return nil;
|
||||
|
||||
bno -= fs->firstblock;
|
||||
if((g = ext2group(fs, bno/fs->blockspergroup, &gb)) == nil){
|
||||
if(debug)
|
||||
fprint(2, "loading group: %r...");
|
||||
return nil;
|
||||
}
|
||||
// if(debug)
|
||||
// fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g->bitblock);
|
||||
|
||||
if((bitb = diskread(fs->disk, fs->blocksize, (u64int)g->bitblock*fs->blocksize)) == nil){
|
||||
if(debug)
|
||||
fprint(2, "loading bitblock: %r...");
|
||||
blockput(gb);
|
||||
return nil;
|
||||
}
|
||||
bits = bitb->data;
|
||||
boff = bno%fs->blockspergroup;
|
||||
if((bits[boff>>3] & (1<<(boff&7))) == 0){
|
||||
if(debug)
|
||||
fprint(2, "block %d not allocated...", bno);
|
||||
blockput(bitb);
|
||||
blockput(gb);
|
||||
return nil;
|
||||
}
|
||||
|
||||
bno += fs->firstblock;
|
||||
return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
|
||||
}
|
||||
|
||||
static Block*
|
||||
ext2datablock(Ext2 *fs, u32int bno, int size)
|
||||
{
|
||||
return ext2blockread(fs->fsys, bno+fs->firstblock);
|
||||
}
|
||||
|
||||
static Block*
|
||||
ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size)
|
||||
{
|
||||
int ppb;
|
||||
Block *b;
|
||||
u32int *a;
|
||||
u32int obno;
|
||||
|
||||
obno = bno;
|
||||
if(bno < NDIRBLOCKS){
|
||||
if(debug)
|
||||
fprint(2, "fileblock %d -> %d...",
|
||||
bno, ino->block[bno]);
|
||||
return ext2datablock(fs, ino->block[bno], size);
|
||||
}
|
||||
bno -= NDIRBLOCKS;
|
||||
ppb = fs->blocksize/4;
|
||||
|
||||
/* one indirect */
|
||||
if(bno < ppb){
|
||||
b = ext2datablock(fs, ino->block[INDBLOCK], fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
a = (u32int*)b->data;
|
||||
bno = a[bno%ppb];
|
||||
blockput(b);
|
||||
return ext2datablock(fs, bno, size);
|
||||
}
|
||||
bno -= ppb;
|
||||
|
||||
/* one double indirect */
|
||||
if(bno < ppb*ppb){
|
||||
b = ext2datablock(fs, ino->block[DINDBLOCK], fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
a = (u32int*)b->data;
|
||||
bno = a[(bno/ppb)%ppb];
|
||||
blockput(b);
|
||||
b = ext2datablock(fs, bno, fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
a = (u32int*)b->data;
|
||||
bno = a[bno%ppb];
|
||||
blockput(b);
|
||||
return ext2datablock(fs, bno, size);
|
||||
}
|
||||
bno -= ppb*ppb;
|
||||
|
||||
/* one triple indirect */
|
||||
if(bno < ppb*ppb*ppb){
|
||||
b = ext2datablock(fs, ino->block[TINDBLOCK], fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
a = (u32int*)b->data;
|
||||
bno = a[(bno/(ppb*ppb))%ppb];
|
||||
blockput(b);
|
||||
b = ext2datablock(fs, bno, fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
a = (u32int*)b->data;
|
||||
bno = a[(bno/ppb)%ppb];
|
||||
blockput(b);
|
||||
b = ext2datablock(fs, bno, fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
a = (u32int*)b->data;
|
||||
bno = a[bno%ppb];
|
||||
blockput(b);
|
||||
return ext2datablock(fs, bno, size);
|
||||
}
|
||||
|
||||
fprint(2, "ext2fileblock %llud: too big\n", obno);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static int
|
||||
checksuper(Super *super)
|
||||
{
|
||||
if(super->magic != SUPERMAGIC){
|
||||
werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ext2sync(Fsys *fsys)
|
||||
{
|
||||
int i;
|
||||
Group *g;
|
||||
Block *b;
|
||||
Super *super;
|
||||
Ext2 *fs;
|
||||
Disk *disk;
|
||||
|
||||
fs = fsys->priv;
|
||||
disk = fs->disk;
|
||||
if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
|
||||
goto error;
|
||||
super = (Super*)b->data;
|
||||
if(checksuper(super) < 0)
|
||||
goto error;
|
||||
fs->blocksize = MINBLOCKSIZE<<super->logblocksize;
|
||||
fs->nblock = super->nblock;
|
||||
fs->ngroup = (super->nblock+super->blockspergroup-1)
|
||||
/ super->blockspergroup;
|
||||
fs->inospergroup = super->inospergroup;
|
||||
fs->blockspergroup = super->blockspergroup;
|
||||
fs->inosperblock = fs->blocksize / InodeSize;
|
||||
if(fs->blocksize == SBOFF)
|
||||
fs->groupaddr = 2;
|
||||
else
|
||||
fs->groupaddr = 1;
|
||||
fs->descperblock = fs->blocksize / GroupSize;
|
||||
fs->firstblock = super->firstdatablock;
|
||||
blockput(b);
|
||||
|
||||
fsys->blocksize = fs->blocksize;
|
||||
fsys->nblock = fs->nblock;
|
||||
fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n",
|
||||
fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup);
|
||||
|
||||
if(0){
|
||||
for(i=0; i<fs->ngroup; i++)
|
||||
if((g = ext2group(fs, i, &b)) != nil){
|
||||
fprint(2, "grp %d: bitblock=%d\n", i, g->bitblock);
|
||||
blockput(b);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
blockput(b);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
mkhandle(Nfs3Handle *h, u64int ino)
|
||||
{
|
||||
h->h[0] = ino>>24;
|
||||
h->h[1] = ino>>16;
|
||||
h->h[2] = ino>>8;
|
||||
h->h[3] = ino;
|
||||
h->len = 4;
|
||||
}
|
||||
|
||||
static u32int
|
||||
byte2u32(uchar *p)
|
||||
{
|
||||
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
|
||||
{
|
||||
int i;
|
||||
uint ioff;
|
||||
u32int inum;
|
||||
u32int addr;
|
||||
Block *gb, *b;
|
||||
Group *g;
|
||||
|
||||
if(h->len != 4)
|
||||
return Nfs3ErrBadHandle;
|
||||
inum = byte2u32(h->h);
|
||||
if(pinum)
|
||||
*pinum = inum;
|
||||
i = (inum-1) / fs->inospergroup;
|
||||
if(i >= fs->ngroup)
|
||||
return Nfs3ErrBadHandle;
|
||||
ioff = (inum-1) % fs->inospergroup;
|
||||
if((g = ext2group(fs, i, &gb)) == nil)
|
||||
return Nfs3ErrIo;
|
||||
addr = g->inodeaddr + ioff/fs->inosperblock;
|
||||
blockput(gb);
|
||||
if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)
|
||||
return Nfs3ErrIo;
|
||||
*ino = ((Inode*)b->data)[ioff%fs->inosperblock];
|
||||
blockput(b);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2root(Fsys *fsys, Nfs3Handle *h)
|
||||
{
|
||||
mkhandle(h, ROOTINODE);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
|
||||
{
|
||||
u32int rdev;
|
||||
|
||||
attr->type = -1;
|
||||
switch(ino->mode&IFMT){
|
||||
case IFIFO:
|
||||
attr->type = Nfs3FileFifo;
|
||||
break;
|
||||
case IFCHR:
|
||||
attr->type = Nfs3FileChar;
|
||||
break;
|
||||
case IFDIR:
|
||||
attr->type = Nfs3FileDir;
|
||||
break;
|
||||
case IFBLK:
|
||||
attr->type = Nfs3FileBlock;
|
||||
break;
|
||||
case IFREG:
|
||||
attr->type = Nfs3FileReg;
|
||||
break;
|
||||
case IFLNK:
|
||||
attr->type = Nfs3FileSymlink;
|
||||
break;
|
||||
case IFSOCK:
|
||||
attr->type = Nfs3FileSocket;
|
||||
break;
|
||||
case IFWHT:
|
||||
default:
|
||||
return Nfs3ErrBadHandle;
|
||||
}
|
||||
|
||||
attr->mode = ino->mode&07777;
|
||||
attr->nlink = ino->nlink;
|
||||
attr->uid = ino->uid;
|
||||
attr->gid = ino->gid;
|
||||
attr->size = ino->size;
|
||||
attr->used = ino->nblock*fs->blocksize;
|
||||
if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
|
||||
rdev = ino->block[0];
|
||||
attr->major = (rdev>>8)&0xFF;
|
||||
attr->minor = rdev & 0xFFFF00FF;
|
||||
}else{
|
||||
attr->major = 0;
|
||||
attr->minor = 0;
|
||||
}
|
||||
attr->fsid = 0;
|
||||
attr->fileid = inum;
|
||||
attr->atime.sec = ino->atime;
|
||||
attr->atime.nsec = 0;
|
||||
attr->mtime.sec = ino->mtime;
|
||||
attr->mtime.nsec = 0;
|
||||
attr->ctime.sec = ino->ctime;
|
||||
attr->ctime.nsec = 0;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static int
|
||||
ingroup(SunAuthUnix *au, uint gid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<au->ng; i++)
|
||||
if(au->g[i] == gid)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
inoperm(Inode *ino, SunAuthUnix *au, int need)
|
||||
{
|
||||
int have;
|
||||
|
||||
if(allowall)
|
||||
return Nfs3Ok;
|
||||
|
||||
have = ino->mode&0777;
|
||||
if(ino->uid == au->uid)
|
||||
have >>= 6;
|
||||
else if(ino->gid == au->gid || ingroup(au, ino->gid))
|
||||
have >>= 3;
|
||||
|
||||
if((have&need) != need)
|
||||
return Nfs3ErrNotOwner; /* really EPERM */
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
|
||||
{
|
||||
Inode ino;
|
||||
u32int inum;
|
||||
Ext2 *fs;
|
||||
Nfs3Status ok;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
USED(au); /* anyone can getattr */
|
||||
return ino2attr(fs, &ino, inum, attr);
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
|
||||
{
|
||||
int have;
|
||||
Inode ino;
|
||||
u32int inum;
|
||||
Ext2 *fs;
|
||||
Nfs3Status ok;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
have = ino.mode&0777;
|
||||
if(ino.uid == au->uid)
|
||||
have >>= 6;
|
||||
else if(ino.gid == au->gid || ingroup(au, ino.gid))
|
||||
have >>= 3;
|
||||
|
||||
*got = 0;
|
||||
if((want&Nfs3AccessRead) && (have&AREAD))
|
||||
*got |= Nfs3AccessRead;
|
||||
if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
|
||||
*got |= Nfs3AccessLookup;
|
||||
if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
|
||||
*got |= Nfs3AccessExecute;
|
||||
|
||||
return ino2attr(fs, &ino, inum, attr);
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
|
||||
{
|
||||
u32int nblock;
|
||||
u32int i;
|
||||
uchar *p, *ep;
|
||||
Dirent *de;
|
||||
Inode ino;
|
||||
Block *b;
|
||||
Ext2 *fs;
|
||||
Nfs3Status ok;
|
||||
int len, want;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if((ino.mode&IFMT) != IFDIR)
|
||||
return Nfs3ErrNotDir;
|
||||
|
||||
if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
len = strlen(name);
|
||||
nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
|
||||
if(debug) fprint(2, "%d blocks in dir...", nblock);
|
||||
for(i=0; i<nblock; i++){
|
||||
if(i==nblock-1)
|
||||
want = ino.size % fs->blocksize;
|
||||
else
|
||||
want = fs->blocksize;
|
||||
b = ext2fileblock(fs, &ino, i, want);
|
||||
if(b == nil){
|
||||
if(debug) fprint(2, "empty block...");
|
||||
continue;
|
||||
}
|
||||
p = b->data;
|
||||
ep = p+b->len;
|
||||
while(p < ep){
|
||||
de = (Dirent*)p;
|
||||
if(de->reclen == 0){
|
||||
if(debug)
|
||||
fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
p += de->reclen;
|
||||
if(p > ep){
|
||||
if(debug)
|
||||
fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
if(de->ino == 0)
|
||||
continue;
|
||||
if(4+2+2+de->namlen > de->reclen){
|
||||
if(debug)
|
||||
fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
if(de->namlen == len && memcmp(de->name, name, len) == 0){
|
||||
mkhandle(nh, de->ino);
|
||||
blockput(b);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
}
|
||||
blockput(b);
|
||||
}
|
||||
return Nfs3ErrNoEnt;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
|
||||
{
|
||||
u32int nblock;
|
||||
u32int i;
|
||||
int off, done;
|
||||
uchar *data, *dp, *dep, *p, *ep, *ndp;
|
||||
Dirent *de;
|
||||
Inode ino;
|
||||
Block *b;
|
||||
Ext2 *fs;
|
||||
Nfs3Status ok;
|
||||
Nfs3Entry e;
|
||||
int want;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if((ino.mode&IFMT) != IFDIR)
|
||||
return Nfs3ErrNotDir;
|
||||
|
||||
if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if(cookie >= ino.size){
|
||||
*pcount = 0;
|
||||
*pdata = 0;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
dp = malloc(count);
|
||||
data = dp;
|
||||
if(dp == nil)
|
||||
return Nfs3ErrNoMem;
|
||||
dep = dp+count;
|
||||
*peof = 0;
|
||||
nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
|
||||
i = cookie/fs->blocksize;
|
||||
off = cookie%fs->blocksize;
|
||||
done = 0;
|
||||
for(; i<nblock && !done; i++){
|
||||
if(i==nblock-1)
|
||||
want = ino.size % fs->blocksize;
|
||||
else
|
||||
want = fs->blocksize;
|
||||
b = ext2fileblock(fs, &ino, i, want);
|
||||
if(b == nil)
|
||||
continue;
|
||||
p = b->data;
|
||||
ep = p+b->len;
|
||||
memset(&e, 0, sizeof e);
|
||||
while(p < ep){
|
||||
de = (Dirent*)p;
|
||||
if(de->reclen == 0){
|
||||
if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
p += de->reclen;
|
||||
if(p > ep){
|
||||
if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
if(de->ino == 0){
|
||||
if(debug) fprint(2, "zero inode\n");
|
||||
continue;
|
||||
}
|
||||
if(4+2+2+de->namlen > de->reclen){
|
||||
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);
|
||||
break;
|
||||
}
|
||||
if(de->name[de->namlen] != 0){
|
||||
if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
|
||||
continue;
|
||||
}
|
||||
if(debug) print("%s/%d ", de->name, (int)de->ino);
|
||||
if((uchar*)de - b->data < off)
|
||||
continue;
|
||||
e.fileid = de->ino;
|
||||
e.name = de->name;
|
||||
e.cookie = (u64int)i*fs->blocksize + (p - b->data);
|
||||
if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
dp = ndp;
|
||||
}
|
||||
off = 0;
|
||||
blockput(b);
|
||||
}
|
||||
if(i==nblock)
|
||||
*peof = 1;
|
||||
|
||||
*pcount = dp - data;
|
||||
*pdata = data;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
|
||||
u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
|
||||
{
|
||||
uchar *data;
|
||||
Block *b;
|
||||
Ext2 *fs;
|
||||
int off, want, fragcount;
|
||||
Inode ino;
|
||||
Nfs3Status ok;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if(offset >= ino.size){
|
||||
*pdata = 0;
|
||||
*pcount = 0;
|
||||
*peof = 1;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
if(offset+count > ino.size)
|
||||
count = ino.size-offset;
|
||||
if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
|
||||
count = fs->blocksize - offset%fs->blocksize;
|
||||
|
||||
data = malloc(count);
|
||||
if(data == nil)
|
||||
return Nfs3ErrNoMem;
|
||||
|
||||
want = offset%fs->blocksize+count;
|
||||
if(want%fs->blocksize)
|
||||
want += fs->blocksize - want%fs->blocksize;
|
||||
|
||||
b = ext2fileblock(fs, &ino, offset/fs->blocksize, want);
|
||||
if(b == nil){
|
||||
/* BUG: distinguish sparse file from I/O error */
|
||||
memset(data, 0, count);
|
||||
}else{
|
||||
off = offset%fs->blocksize;
|
||||
fragcount = count; /* need signed variable */
|
||||
if(off+fragcount > b->len){
|
||||
fragcount = b->len - off;
|
||||
if(fragcount < 0)
|
||||
fragcount = 0;
|
||||
}
|
||||
if(fragcount > 0)
|
||||
memmove(data, b->data+off, fragcount);
|
||||
count = fragcount;
|
||||
blockput(b);
|
||||
}
|
||||
*peof = (offset+count == ino.size);
|
||||
*pcount = count;
|
||||
*pdata = data;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
|
||||
{
|
||||
Ext2 *fs;
|
||||
Nfs3Status ok;
|
||||
int len;
|
||||
Inode ino;
|
||||
Block *b;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if(ino.size > 1024)
|
||||
return Nfs3ErrIo;
|
||||
len = ino.size;
|
||||
|
||||
if(ino.nblock != 0){
|
||||
/* BUG: assumes symlink fits in one block */
|
||||
b = ext2fileblock(fs, &ino, 0, len);
|
||||
if(b == nil)
|
||||
return Nfs3ErrIo;
|
||||
if(memchr(b->data, 0, len) != nil){
|
||||
blockput(b);
|
||||
return Nfs3ErrIo;
|
||||
}
|
||||
*link = malloc(len+1);
|
||||
if(*link == 0){
|
||||
blockput(b);
|
||||
return Nfs3ErrNoMem;
|
||||
}
|
||||
memmove(*link, b->data, len);
|
||||
(*link)[len] = 0;
|
||||
blockput(b);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
if(len > sizeof ino.block)
|
||||
return Nfs3ErrIo;
|
||||
|
||||
*link = malloc(len+1);
|
||||
if(*link == 0)
|
||||
return Nfs3ErrNoMem;
|
||||
memmove(*link, ino.block, ino.size);
|
||||
(*link)[len] = 0;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
167
src/libdiskfs/ext2.h
Normal file
167
src/libdiskfs/ext2.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
typedef struct Super Super;
|
||||
typedef struct Group Group;
|
||||
typedef struct Inode Inode;
|
||||
typedef struct Dirent Dirent;
|
||||
typedef struct Ext2 Ext2;
|
||||
|
||||
enum
|
||||
{
|
||||
BYTESPERSEC = 512,
|
||||
|
||||
SBOFF = 1024,
|
||||
SBSIZE = 1024,
|
||||
|
||||
SUPERMAGIC = 0xEF53,
|
||||
MINBLOCKSIZE = 1024,
|
||||
MAXBLOCKSIZE = 4096,
|
||||
ROOTINODE = 2,
|
||||
FIRSTINODE = 11,
|
||||
VALIDFS = 0x0001,
|
||||
ERRORFS = 0x0002,
|
||||
|
||||
NDIRBLOCKS = 12,
|
||||
INDBLOCK = NDIRBLOCKS,
|
||||
DINDBLOCK = INDBLOCK+1,
|
||||
TINDBLOCK = DINDBLOCK+1,
|
||||
NBLOCKS = TINDBLOCK+1,
|
||||
|
||||
NAMELEN = 255,
|
||||
|
||||
/* permissions in Inode.mode */
|
||||
IEXEC = 00100,
|
||||
IWRITE = 0200,
|
||||
IREAD = 0400,
|
||||
ISVTX = 01000,
|
||||
ISGID = 02000,
|
||||
ISUID = 04000,
|
||||
|
||||
/* type in Inode.mode */
|
||||
IFMT = 0170000,
|
||||
IFIFO = 0010000,
|
||||
IFCHR = 0020000,
|
||||
IFDIR = 0040000,
|
||||
IFBLK = 0060000,
|
||||
IFREG = 0100000,
|
||||
IFLNK = 0120000,
|
||||
IFSOCK = 0140000,
|
||||
IFWHT = 0160000,
|
||||
};
|
||||
|
||||
#define DIRLEN(namlen) (((namlen)+8+3)&~3)
|
||||
|
||||
|
||||
/*
|
||||
* Super block on-disk format.
|
||||
*/
|
||||
struct Super
|
||||
{
|
||||
u32int ninode; /* Inodes count */
|
||||
u32int nblock; /* Blocks count */
|
||||
u32int rblockcount; /* Reserved blocks count */
|
||||
u32int freeblockcount; /* Free blocks count */
|
||||
u32int freeinodecount; /* Free inodes count */
|
||||
u32int firstdatablock; /* First Data Block */
|
||||
u32int logblocksize; /* Block size */
|
||||
u32int logfragsize; /* Fragment size */
|
||||
u32int blockspergroup; /* # Blocks per group */
|
||||
u32int fragpergroup; /* # Fragments per group */
|
||||
u32int inospergroup; /* # Inodes per group */
|
||||
u32int mtime; /* Mount time */
|
||||
u32int wtime; /* Write time */
|
||||
u16int mntcount; /* Mount count */
|
||||
u16int maxmntcount; /* Maximal mount count */
|
||||
u16int magic; /* Magic signature */
|
||||
u16int state; /* File system state */
|
||||
u16int errors; /* Behaviour when detecting errors */
|
||||
u16int pad;
|
||||
u32int lastcheck; /* time of last check */
|
||||
u32int checkinterval; /* max. time between checks */
|
||||
u32int creatoros; /* OS */
|
||||
u32int revlevel; /* Revision level */
|
||||
u16int defresuid; /* Default uid for reserved blocks */
|
||||
u16int defresgid; /* Default gid for reserved blocks */
|
||||
u32int reserved[235]; /* Padding to the end of the block */
|
||||
};
|
||||
|
||||
/*
|
||||
* Blcok group on-disk format.
|
||||
*/
|
||||
struct Group
|
||||
{
|
||||
u32int bitblock; /* Blocks bitmap block */
|
||||
u32int inodebitblock; /* Inodes bitmap block */
|
||||
u32int inodeaddr; /* Inodes table block */
|
||||
u16int freeblockscount; /* Free blocks count */
|
||||
u16int freeinodescount; /* Free inodes count */
|
||||
u16int useddirscount; /* Directories count */
|
||||
u16int pad;
|
||||
u32int reserved[3];
|
||||
};
|
||||
enum
|
||||
{
|
||||
GroupSize = 32
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of an inode on the disk
|
||||
*/
|
||||
struct Inode
|
||||
{
|
||||
u16int mode; /* File mode */
|
||||
u16int uid; /* Owner Uid */
|
||||
u32int size; /* Size in bytes */
|
||||
u32int atime; /* Access time */
|
||||
u32int ctime; /* Creation time */
|
||||
u32int mtime; /* Modification time */
|
||||
u32int dtime; /* Deletion Time */
|
||||
u16int gid; /* Group Id */
|
||||
u16int nlink; /* Links count */
|
||||
u32int nblock; /* Blocks count */
|
||||
u32int flags; /* File flags */
|
||||
u32int osd1;
|
||||
u32int block[NBLOCKS];/* Pointers to blocks */
|
||||
u32int version; /* File version (for NFS) */
|
||||
u32int fileacl; /* File ACL */
|
||||
u32int diracl; /* Directory ACL */
|
||||
u32int faddr; /* Fragment address */
|
||||
uchar osd2[12];
|
||||
};
|
||||
enum
|
||||
{
|
||||
InodeSize = 128
|
||||
};
|
||||
|
||||
/*
|
||||
* Directory entry on-disk structure.
|
||||
*/
|
||||
struct Dirent
|
||||
{
|
||||
u32int ino; /* Inode number */
|
||||
u16int reclen; /* Directory entry length */
|
||||
u8int namlen; /* Name length */
|
||||
u8int pad;
|
||||
char name[NAMELEN]; /* File name */
|
||||
};
|
||||
enum
|
||||
{
|
||||
MinDirentSize = 4+2+1+1,
|
||||
};
|
||||
|
||||
/*
|
||||
* In-core fs info.
|
||||
*/
|
||||
struct Ext2
|
||||
{
|
||||
uint blocksize;
|
||||
uint nblock;
|
||||
uint ngroup;
|
||||
uint inospergroup;
|
||||
uint blockspergroup;
|
||||
uint inosperblock;
|
||||
uint groupaddr;
|
||||
uint descperblock;
|
||||
uint firstblock;
|
||||
Disk *disk;
|
||||
Fsys *fsys;
|
||||
};
|
||||
|
11
src/libdiskfs/fat.c
Normal file
11
src/libdiskfs/fat.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
Fsys*
|
||||
fsysopenfat(Disk *disk)
|
||||
{
|
||||
USED(disk);
|
||||
return nil;
|
||||
}
|
||||
|
791
src/libdiskfs/ffs.c
Normal file
791
src/libdiskfs/ffs.c
Normal file
|
@ -0,0 +1,791 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <sunrpc.h>
|
||||
#include <nfs3.h>
|
||||
#include <diskfs.h>
|
||||
#include "ffs.h"
|
||||
|
||||
#define checkcg 0
|
||||
#define debug 0
|
||||
|
||||
static int checkfsblk(Fsblk*);
|
||||
static int checkcgblk(Cgblk*);
|
||||
static Block *ffsblockread(Fsys*, u64int);
|
||||
static int ffssync(Fsys*);
|
||||
static void ffsclose(Fsys*);
|
||||
|
||||
static Nfs3Status ffsroot(Fsys*, Nfs3Handle*);
|
||||
static Nfs3Status ffsgetattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);
|
||||
static Nfs3Status ffslookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);
|
||||
static Nfs3Status ffsreadfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
|
||||
static Nfs3Status ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);
|
||||
static Nfs3Status ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
|
||||
static Nfs3Status ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr);
|
||||
|
||||
Fsys*
|
||||
fsysopenffs(Disk *disk)
|
||||
{
|
||||
Ffs *fs;
|
||||
Fsys *fsys;
|
||||
|
||||
fsys = emalloc(sizeof(Fsys));
|
||||
fs = emalloc(sizeof(Ffs));
|
||||
fs->disk = disk;
|
||||
fsys->priv = fs;
|
||||
fsys->type = "ffs";
|
||||
fsys->_readblock = ffsblockread;
|
||||
fsys->_sync = ffssync;
|
||||
fsys->_root = ffsroot;
|
||||
fsys->_getattr = ffsgetattr;
|
||||
fsys->_access = ffsaccess;
|
||||
fsys->_lookup = ffslookup;
|
||||
fsys->_readfile = ffsreadfile;
|
||||
fsys->_readlink = ffsreadlink;
|
||||
fsys->_readdir = ffsreaddir;
|
||||
|
||||
if(ffssync(fsys) < 0)
|
||||
goto error;
|
||||
|
||||
return fsys;
|
||||
|
||||
error:
|
||||
ffsclose(fsys);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static Cgblk*
|
||||
ffscylgrp(Ffs *fs, int i, Block **pb)
|
||||
{
|
||||
Block *b;
|
||||
Cgblk *cg;
|
||||
|
||||
if(i >= fs->ncg)
|
||||
return nil;
|
||||
|
||||
b = diskread(fs->disk, fs->blocksize, (u64int)fs->cg[i].cgblkno*fs->blocksize);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
cg = (Cgblk*)b->data;
|
||||
if(checkcgblk(cg) < 0){
|
||||
fprint(2, "checkcgblk %d %lud: %r\n", i, (ulong)fs->cg[i].cgblkno);
|
||||
blockput(b);
|
||||
return nil;
|
||||
}
|
||||
*pb = b;
|
||||
return cg;
|
||||
}
|
||||
|
||||
static int
|
||||
ffssync(Fsys *fsys)
|
||||
{
|
||||
int i;
|
||||
Block *b, *cgb;
|
||||
Cgblk *cgblk;
|
||||
Cylgrp *cg;
|
||||
Disk *disk;
|
||||
Ffs *fs;
|
||||
Fsblk *fsblk;
|
||||
|
||||
fs = fsys->priv;
|
||||
disk = fs->disk;
|
||||
|
||||
/*
|
||||
* Read super block.
|
||||
*/
|
||||
if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
|
||||
goto error;
|
||||
fsblk = (Fsblk*)b->data;
|
||||
if(checkfsblk(fsblk) < 0)
|
||||
goto error;
|
||||
|
||||
fs->blocksize = fsblk->blocksize;
|
||||
fs->nblock = (fsblk->nfrag+fsblk->fragsperblock-1) / fsblk->fragsperblock;
|
||||
fs->fragsize = fsblk->fragsize;
|
||||
fs->fragspergroup = fsblk->fragspergroup;
|
||||
fs->fragsperblock = fsblk->fragsperblock;
|
||||
fs->inosperblock = fsblk->inosperblock;
|
||||
fs->inospergroup = fsblk->inospergroup;
|
||||
|
||||
fs->nfrag = fsblk->nfrag;
|
||||
fs->ndfrag = fsblk->ndfrag;
|
||||
fs->blockspergroup = (u64int)fsblk->cylspergroup *
|
||||
fsblk->secspercyl * BYTESPERSEC / fsblk->blocksize;
|
||||
fs->ncg = fsblk->ncg;
|
||||
|
||||
fsys->blocksize = fs->blocksize;
|
||||
fsys->nblock = fs->nblock;
|
||||
|
||||
if(0) fprint(2, "ffs %d %d-byte blocks, %d cylinder groups\n",
|
||||
fs->nblock, fs->blocksize, fs->ncg);
|
||||
|
||||
if(fs->cg == nil)
|
||||
fs->cg = emalloc(fs->ncg*sizeof(Cylgrp));
|
||||
for(i=0; i<fs->ncg; i++){
|
||||
cg = &fs->cg[i];
|
||||
cg->bno = fs->blockspergroup*i + fsblk->cgoffset * (i & ~fsblk->cgmask);
|
||||
cg->cgblkno = cg->bno + fsblk->cfragno/fs->fragsperblock;
|
||||
cg->ibno = cg->bno + fsblk->ifragno/fs->fragsperblock;
|
||||
cg->dbno = cg->bno + fsblk->dfragno/fs->fragsperblock;
|
||||
|
||||
if(checkcg){
|
||||
if((cgb = diskread(disk, fs->blocksize, (u64int)cg->cgblkno*fs->blocksize)) == nil)
|
||||
goto error;
|
||||
|
||||
cgblk = (Cgblk*)cgb->data;
|
||||
if(checkcgblk(cgblk) < 0){
|
||||
blockput(cgb);
|
||||
goto error;
|
||||
}
|
||||
if(cgblk->nfrag % fs->fragsperblock && i != fs->ncg-1){
|
||||
werrstr("fractional number of blocks in non-last cylinder group %d", cgblk->nfrag);
|
||||
blockput(cgb);
|
||||
goto error;
|
||||
}
|
||||
// cg->nfrag = cgblk->nfrag;
|
||||
// cg->nblock = (cgblk->nfrag+fs->fragsperblock-1) / fs->fragsperblock;
|
||||
// fprint(2, "cg #%d: cgblk %lud, %d blocks, %d inodes\n", cgblk->num, (ulong)cg->cgblkno, cg->nblock, cg->nino);
|
||||
}
|
||||
}
|
||||
blockput(b);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
blockput(b);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
ffsclose(Fsys *fsys)
|
||||
{
|
||||
Ffs *fs;
|
||||
|
||||
fs = fsys->priv;
|
||||
if(fs->cg)
|
||||
free(fs->cg);
|
||||
free(fs);
|
||||
free(fsys);
|
||||
}
|
||||
|
||||
static int
|
||||
checkfsblk(Fsblk *super)
|
||||
{
|
||||
if(super->magic != FSMAGIC){
|
||||
werrstr("bad super block");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
checkcgblk(Cgblk *cg)
|
||||
{
|
||||
if(cg->magic != CGMAGIC){
|
||||
werrstr("bad cylinder group block");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read block #bno from the disk, zeroing unused data.
|
||||
* If there is no data whatsoever, it's okay to return nil.
|
||||
*/
|
||||
int nskipx;
|
||||
static Block*
|
||||
ffsblockread(Fsys *fsys, u64int bno)
|
||||
{
|
||||
u32int i, o;
|
||||
u8int *fmap;
|
||||
int frag, fsize, avail;
|
||||
Block *b;
|
||||
// Cylgrp *cg;
|
||||
Cgblk *cgblk;
|
||||
Ffs *fs;
|
||||
|
||||
fs = fsys->priv;
|
||||
i = bno / fs->blockspergroup;
|
||||
o = bno % fs->blockspergroup;
|
||||
if(i >= fs->ncg)
|
||||
return nil;
|
||||
// cg = &fs->cg[i];
|
||||
|
||||
// if(o >= cg->nblock)
|
||||
// return nil;
|
||||
|
||||
if((cgblk = ffscylgrp(fs, i, &b)) == nil)
|
||||
return nil;
|
||||
|
||||
fmap = (u8int*)cgblk+cgblk->fmapoff;
|
||||
frag = fs->fragsperblock;
|
||||
switch(frag){
|
||||
default:
|
||||
sysfatal("bad frag");
|
||||
case 8:
|
||||
avail = fmap[o];
|
||||
break;
|
||||
case 4:
|
||||
avail = (fmap[o>>1] >> ((o&1)*4)) & 0xF;
|
||||
break;
|
||||
case 2:
|
||||
avail = (fmap[o>>2] >> ((o&3)*2)) & 0x3;
|
||||
break;
|
||||
case 1:
|
||||
avail = (fmap[o>>3] >> (o&7)) & 0x1;
|
||||
break;
|
||||
}
|
||||
blockput(b);
|
||||
|
||||
if(avail == ((1<<frag)-1))
|
||||
{
|
||||
nskipx++;
|
||||
return nil;
|
||||
}
|
||||
if((b = diskread(fs->disk, fs->blocksize, bno*fs->blocksize)) == nil){
|
||||
fprint(2, "diskread failed!!!\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
fsize = fs->fragsize;
|
||||
for(i=0; i<frag; i++)
|
||||
if(avail & (1<<i))
|
||||
memset(b->data + fsize*i, 0, fsize);
|
||||
return b;
|
||||
}
|
||||
|
||||
static Block*
|
||||
ffsdatablock(Ffs *fs, u32int bno, int size)
|
||||
{
|
||||
int fsize;
|
||||
u64int diskaddr;
|
||||
Block *b;
|
||||
|
||||
if(bno == 0)
|
||||
return nil;
|
||||
|
||||
fsize = size;
|
||||
if(fsize < fs->fragsize)
|
||||
fsize = fs->fragsize;
|
||||
|
||||
if(bno >= fs->nfrag){
|
||||
fprint(2, "ffs: request for block %#lux; nfrag %#x\n", (ulong)bno, fs->nfrag);
|
||||
return nil;
|
||||
}
|
||||
diskaddr = (u64int)bno*fs->fragsize;
|
||||
b = diskread(fs->disk, fsize, diskaddr);
|
||||
if(b == nil){
|
||||
fprint(2, "ffs: disk i/o at %#llux for %#ux: %r\n", diskaddr, fsize);
|
||||
return nil;
|
||||
}
|
||||
if(b->len < fsize){
|
||||
fprint(2, "ffs: disk i/o at %#llux for %#ux got %#ux\n", diskaddr, fsize,
|
||||
b->len);
|
||||
blockput(b);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static Block*
|
||||
ffsfileblock(Ffs *fs, Inode *ino, u32int bno, int size)
|
||||
{
|
||||
int ppb;
|
||||
Block *b;
|
||||
u32int *a;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
fprint(2, "ffsfileblock %lud: too big\n", (ulong)bno+NDADDR);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* NFS handles are 4-byte inode number.
|
||||
*/
|
||||
static void
|
||||
mkhandle(Nfs3Handle *h, u64int ino)
|
||||
{
|
||||
h->h[0] = ino >> 24;
|
||||
h->h[1] = ino >> 16;
|
||||
h->h[2] = ino >> 8;
|
||||
h->h[3] = ino;
|
||||
h->len = 4;
|
||||
}
|
||||
|
||||
static u32int
|
||||
byte2u32(uchar *p)
|
||||
{
|
||||
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
|
||||
{
|
||||
int i;
|
||||
u32int ioff;
|
||||
u32int inum;
|
||||
Block *b;
|
||||
Cylgrp *cg;
|
||||
|
||||
if(h->len != 4)
|
||||
return Nfs3ErrBadHandle;
|
||||
inum = byte2u32(h->h);
|
||||
if(pinum)
|
||||
*pinum = inum;
|
||||
if(debug) print("inum %d...", (int)inum);
|
||||
|
||||
/* fetch inode from disk */
|
||||
i = inum / fs->inospergroup;
|
||||
ioff = inum % fs->inospergroup;
|
||||
if(debug)print("cg %d off %d...", i, (int)ioff);
|
||||
if(i >= fs->ncg)
|
||||
return Nfs3ErrBadHandle;
|
||||
cg = &fs->cg[i];
|
||||
/*
|
||||
if(ioff >= cg->nino)
|
||||
return Nfs3ErrBadHandle;
|
||||
*/
|
||||
|
||||
if(debug) print("cg->ibno %d...", cg->ibno);
|
||||
if((b = diskread(fs->disk, fs->blocksize,
|
||||
(cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize)) == nil)
|
||||
return Nfs3ErrIo;
|
||||
*ino = ((Inode*)b->data)[ioff%fs->inosperblock];
|
||||
blockput(b);
|
||||
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffsroot(Fsys *fsys, Nfs3Handle *h)
|
||||
{
|
||||
USED(fsys);
|
||||
mkhandle(h, 2);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ino2attr(Ffs *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
|
||||
{
|
||||
u32int rdev;
|
||||
|
||||
attr->type = -1;
|
||||
switch(ino->mode&IFMT){
|
||||
case IFIFO:
|
||||
attr->type = Nfs3FileFifo;
|
||||
break;
|
||||
case IFCHR:
|
||||
attr->type = Nfs3FileChar;
|
||||
break;
|
||||
case IFDIR:
|
||||
attr->type = Nfs3FileDir;
|
||||
break;
|
||||
case IFBLK:
|
||||
attr->type = Nfs3FileBlock;
|
||||
break;
|
||||
case IFREG:
|
||||
attr->type = Nfs3FileReg;
|
||||
break;
|
||||
case IFLNK:
|
||||
attr->type = Nfs3FileSymlink;
|
||||
break;
|
||||
case IFSOCK:
|
||||
attr->type = Nfs3FileSocket;
|
||||
break;
|
||||
case IFWHT:
|
||||
default:
|
||||
return Nfs3ErrBadHandle;
|
||||
}
|
||||
|
||||
attr->mode = ino->mode&07777;
|
||||
attr->nlink = ino->nlink;
|
||||
attr->uid = ino->uid;
|
||||
attr->gid = ino->gid;
|
||||
attr->size = ino->size;
|
||||
attr->used = ino->nblock*fs->blocksize;
|
||||
if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
|
||||
rdev = ino->db[0];
|
||||
attr->major = (rdev>>8)&0xFF;
|
||||
attr->minor = rdev & 0xFFFF00FF;
|
||||
}else{
|
||||
attr->major = 0;
|
||||
attr->minor = 0;
|
||||
}
|
||||
attr->fsid = 0;
|
||||
attr->fileid = inum;
|
||||
attr->atime.sec = ino->atime;
|
||||
attr->atime.nsec = ino->atimensec;
|
||||
attr->mtime.sec = ino->mtime;
|
||||
attr->mtime.nsec = ino->mtimensec;
|
||||
attr->ctime.sec = ino->ctime;
|
||||
attr->ctime.nsec = ino->ctimensec;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static int
|
||||
ingroup(SunAuthUnix *au, uint gid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<au->ng; i++)
|
||||
if(au->g[i] == gid)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
inoperm(Inode *ino, SunAuthUnix *au, int need)
|
||||
{
|
||||
int have;
|
||||
|
||||
have = ino->mode&0777;
|
||||
if(ino->uid == au->uid)
|
||||
have >>= 6;
|
||||
else if(ino->gid == au->gid || ingroup(au, ino->gid))
|
||||
have >>= 3;
|
||||
|
||||
if((have&need) != need)
|
||||
return Nfs3ErrNotOwner; /* really EPERM */
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffsgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
|
||||
{
|
||||
Inode ino;
|
||||
u32int inum;
|
||||
Ffs *fs;
|
||||
Nfs3Status ok;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
USED(au); /* anyone can getattr */
|
||||
|
||||
return ino2attr(fs, &ino, inum, attr);
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
|
||||
{
|
||||
int have;
|
||||
Inode ino;
|
||||
u32int inum;
|
||||
Ffs *fs;
|
||||
Nfs3Status ok;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
have = ino.mode&0777;
|
||||
if(ino.uid == au->uid)
|
||||
have >>= 6;
|
||||
else if(ino.gid == au->gid || ingroup(au, ino.gid))
|
||||
have >>= 3;
|
||||
|
||||
*got = 0;
|
||||
if((want&Nfs3AccessRead) && (have&AREAD))
|
||||
*got |= Nfs3AccessRead;
|
||||
if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
|
||||
*got |= Nfs3AccessLookup;
|
||||
if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
|
||||
*got |= Nfs3AccessExecute;
|
||||
|
||||
return ino2attr(fs, &ino, inum, attr);
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
|
||||
{
|
||||
u32int nblock;
|
||||
u32int i;
|
||||
uchar *p, *ep;
|
||||
Dirent *de;
|
||||
Inode ino;
|
||||
Block *b;
|
||||
Ffs *fs;
|
||||
Nfs3Status ok;
|
||||
int len, want;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if((ino.mode&IFMT) != IFDIR)
|
||||
return Nfs3ErrNotDir;
|
||||
|
||||
if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
len = strlen(name);
|
||||
nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
|
||||
for(i=0; i<nblock; i++){
|
||||
if(i==nblock-1)
|
||||
want = ino.size % fs->blocksize;
|
||||
else
|
||||
want = fs->blocksize;
|
||||
b = ffsfileblock(fs, &ino, i, want);
|
||||
if(b == nil)
|
||||
continue;
|
||||
p = b->data;
|
||||
ep = p+b->len;
|
||||
while(p < ep){
|
||||
de = (Dirent*)p;
|
||||
if(de->reclen == 0){
|
||||
if(debug)
|
||||
fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
p += de->reclen;
|
||||
if(p > ep){
|
||||
if(debug)
|
||||
fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
if(de->ino == 0)
|
||||
continue;
|
||||
if(4+2+2+de->namlen > de->reclen){
|
||||
if(debug)
|
||||
fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
if(de->namlen == len && memcmp(de->name, name, len) == 0){
|
||||
mkhandle(nh, de->ino);
|
||||
blockput(b);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
}
|
||||
blockput(b);
|
||||
}
|
||||
return Nfs3ErrNoEnt;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
|
||||
{
|
||||
u32int nblock;
|
||||
u32int i;
|
||||
int off, done;
|
||||
uchar *data, *dp, *dep, *p, *ep, *ndp;
|
||||
Dirent *de;
|
||||
Inode ino;
|
||||
Block *b;
|
||||
Ffs *fs;
|
||||
Nfs3Status ok;
|
||||
Nfs3Entry e;
|
||||
int want;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if((ino.mode&IFMT) != IFDIR)
|
||||
return Nfs3ErrNotDir;
|
||||
|
||||
if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if(cookie >= ino.size){
|
||||
*pcount = 0;
|
||||
*pdata = 0;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
dp = malloc(count);
|
||||
data = dp;
|
||||
if(dp == nil)
|
||||
return Nfs3ErrNoMem;
|
||||
dep = dp+count;
|
||||
*peof = 0;
|
||||
nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
|
||||
i = cookie/fs->blocksize;
|
||||
off = cookie%fs->blocksize;
|
||||
done = 0;
|
||||
for(; i<nblock && !done; i++){
|
||||
if(i==nblock-1)
|
||||
want = ino.size % fs->blocksize;
|
||||
else
|
||||
want = fs->blocksize;
|
||||
b = ffsfileblock(fs, &ino, i, want);
|
||||
if(b == nil)
|
||||
continue;
|
||||
p = b->data;
|
||||
ep = p+b->len;
|
||||
memset(&e, 0, sizeof e);
|
||||
while(p < ep){
|
||||
de = (Dirent*)p;
|
||||
if(de->reclen == 0){
|
||||
if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
p += de->reclen;
|
||||
if(p > ep){
|
||||
if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
|
||||
break;
|
||||
}
|
||||
if(de->ino == 0){
|
||||
if(debug) fprint(2, "zero inode\n");
|
||||
continue;
|
||||
}
|
||||
if(4+2+2+de->namlen > de->reclen){
|
||||
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);
|
||||
break;
|
||||
}
|
||||
if(de->name[de->namlen] != 0){
|
||||
if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
|
||||
continue;
|
||||
}
|
||||
if(debug) print("%s/%d ", de->name, (int)de->ino);
|
||||
if((uchar*)de - b->data < off)
|
||||
continue;
|
||||
e.fileid = de->ino;
|
||||
e.name = de->name;
|
||||
e.cookie = (u64int)i*fs->blocksize + (p - b->data);
|
||||
if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
dp = ndp;
|
||||
}
|
||||
off = 0;
|
||||
blockput(b);
|
||||
}
|
||||
if(i==nblock)
|
||||
*peof = 1;
|
||||
|
||||
*pcount = dp - data;
|
||||
*pdata = data;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
|
||||
u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
|
||||
{
|
||||
uchar *data;
|
||||
Block *b;
|
||||
Ffs *fs;
|
||||
int off, want, fragcount;
|
||||
Inode ino;
|
||||
Nfs3Status ok;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if(offset >= ino.size){
|
||||
*pdata = 0;
|
||||
*pcount = 0;
|
||||
*peof = 1;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
if(offset+count > ino.size)
|
||||
count = ino.size-offset;
|
||||
if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
|
||||
count = fs->blocksize - offset%fs->blocksize;
|
||||
|
||||
data = malloc(count);
|
||||
if(data == nil)
|
||||
return Nfs3ErrNoMem;
|
||||
|
||||
want = offset%fs->blocksize+count;
|
||||
if(want%fs->fragsize)
|
||||
want += fs->fragsize - want%fs->fragsize;
|
||||
|
||||
b = ffsfileblock(fs, &ino, offset/fs->blocksize, want);
|
||||
if(b == nil){
|
||||
/* BUG: distinguish sparse file from I/O error */
|
||||
memset(data, 0, count);
|
||||
}else{
|
||||
off = offset%fs->blocksize;
|
||||
fragcount = count; /* need signed variable */
|
||||
if(off+fragcount > b->len){
|
||||
fragcount = b->len - off;
|
||||
if(fragcount < 0)
|
||||
fragcount = 0;
|
||||
}
|
||||
if(fragcount > 0)
|
||||
memmove(data, b->data+off, fragcount);
|
||||
count = fragcount;
|
||||
blockput(b);
|
||||
}
|
||||
*peof = (offset+count == ino.size);
|
||||
*pcount = count;
|
||||
*pdata = data;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
static Nfs3Status
|
||||
ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
|
||||
{
|
||||
Ffs *fs;
|
||||
Nfs3Status ok;
|
||||
int len;
|
||||
Inode ino;
|
||||
Block *b;
|
||||
|
||||
fs = fsys->priv;
|
||||
if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
|
||||
return ok;
|
||||
if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
|
||||
return ok;
|
||||
|
||||
if(ino.size > 1024)
|
||||
return Nfs3ErrIo;
|
||||
len = ino.size;
|
||||
|
||||
if(ino.nblock != 0){
|
||||
/* BUG: assumes symlink fits in one block */
|
||||
b = ffsfileblock(fs, &ino, 0, len);
|
||||
if(b == nil)
|
||||
return Nfs3ErrIo;
|
||||
if(memchr(b->data, 0, len) != nil){
|
||||
blockput(b);
|
||||
return Nfs3ErrIo;
|
||||
}
|
||||
*link = malloc(len+1);
|
||||
if(*link == 0){
|
||||
blockput(b);
|
||||
return Nfs3ErrNoMem;
|
||||
}
|
||||
memmove(*link, b->data, len);
|
||||
(*link)[len] = 0;
|
||||
blockput(b);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
if(len > sizeof ino.db + sizeof ino.ib)
|
||||
return Nfs3ErrIo;
|
||||
|
||||
*link = malloc(len+1);
|
||||
if(*link == 0)
|
||||
return Nfs3ErrNoMem;
|
||||
memmove(*link, ino.db, ino.size);
|
||||
(*link)[len] = 0;
|
||||
return Nfs3Ok;
|
||||
}
|
281
src/libdiskfs/ffs.h
Normal file
281
src/libdiskfs/ffs.h
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* An FFS file system is a sequence of cylinder groups.
|
||||
*
|
||||
* Each cylinder group is laid out as follows:
|
||||
*
|
||||
* fs superblock (Fsblk)
|
||||
* cylinder group block (Cgblk)
|
||||
* inodes
|
||||
* data
|
||||
*
|
||||
* The location of the fs superblock in the first cylinder
|
||||
* group is known. The rest of the info about cylinder group
|
||||
* layout can be derived from the super block.
|
||||
*/
|
||||
|
||||
#define daddr_t u32int
|
||||
#define time_t u32int
|
||||
|
||||
typedef struct Cgblk Cgblk;
|
||||
typedef struct Cylgrp Cylgrp;
|
||||
typedef struct Cylsum Cylsum;
|
||||
typedef struct Ffs Ffs;
|
||||
typedef struct Fsblk Fsblk;
|
||||
typedef struct Inode Inode;
|
||||
typedef struct Dirent Dirent;
|
||||
|
||||
enum
|
||||
{
|
||||
BYTESPERSEC = 512,
|
||||
|
||||
/* constants for Fsblk */
|
||||
FSMAXMNTLEN = 512,
|
||||
FSNOCSPTRS = 128 / sizeof(void*) - 3,
|
||||
FSMAXSNAP = 20,
|
||||
FSMAGIC = 0x011954,
|
||||
FSCHECKSUM = 0x7c269d38,
|
||||
|
||||
/* Fsblk.inodefmt */
|
||||
FS42INODEFMT = -1,
|
||||
FS44INODEFMT = 2,
|
||||
|
||||
/* offset and size of first boot block */
|
||||
BBOFF = 0,
|
||||
BBSIZE = 8192,
|
||||
|
||||
/* offset and size of first super block */
|
||||
SBOFF = BBOFF+BBSIZE,
|
||||
SBSIZE = 8192,
|
||||
|
||||
/* minimum block size */
|
||||
MINBSIZE = 4096,
|
||||
|
||||
/* maximum fragments per block */
|
||||
MAXFRAG = 8,
|
||||
|
||||
/* constants for Cgblk */
|
||||
CGMAGIC = 0x090255,
|
||||
|
||||
/* inode-related */
|
||||
ROOTINODE = 2,
|
||||
WHITEOUT = 1,
|
||||
|
||||
NDADDR = 12,
|
||||
NIADDR = 3,
|
||||
|
||||
/* permissions in Inode.mode */
|
||||
IEXEC = 00100,
|
||||
IWRITE = 0200,
|
||||
IREAD = 0400,
|
||||
ISVTX = 01000,
|
||||
ISGID = 02000,
|
||||
ISUID = 04000,
|
||||
|
||||
/* type in Inode.mode */
|
||||
IFMT = 0170000,
|
||||
IFIFO = 0010000,
|
||||
IFCHR = 0020000,
|
||||
IFDIR = 0040000,
|
||||
IFBLK = 0060000,
|
||||
IFREG = 0100000,
|
||||
IFLNK = 0120000,
|
||||
IFSOCK = 0140000,
|
||||
IFWHT = 0160000,
|
||||
|
||||
/* type in Dirent.type */
|
||||
DTUNKNOWN = 0,
|
||||
DTFIFO = 1,
|
||||
DTCHR = 2,
|
||||
DTDIR = 4,
|
||||
DTBLK = 6,
|
||||
DTREG = 8,
|
||||
DTLNK = 10,
|
||||
DTSOCK = 12,
|
||||
DTWHT = 14,
|
||||
};
|
||||
|
||||
struct Cylsum
|
||||
{
|
||||
u32int ndir;
|
||||
u32int nbfree;
|
||||
u32int nifree;
|
||||
u32int nffree;
|
||||
};
|
||||
|
||||
struct Fsblk
|
||||
{
|
||||
u32int unused0;
|
||||
u32int unused1;
|
||||
daddr_t sfragno; /* fragment address of super block in file system */
|
||||
daddr_t cfragno; /* fragment address if cylinder block in file system */
|
||||
daddr_t ifragno; /* fragment offset of inode blocks in file system */
|
||||
daddr_t dfragno; /* fragment offset of data blocks in cg */
|
||||
u32int cgoffset; /* block (maybe fragment?) offset of Cgblk in cylinder */
|
||||
u32int cgmask;
|
||||
time_t time;
|
||||
u32int nfrag; /* number of blocks in fs * fragsperblock */
|
||||
u32int ndfrag;
|
||||
u32int ncg; /* number of cylinder groups in fs */
|
||||
u32int blocksize; /* block size in fs */
|
||||
u32int fragsize; /* frag size in fs */
|
||||
u32int fragsperblock; /* fragments per block: blocksize / fragsize */
|
||||
u32int minfree; /* ignored by us */
|
||||
u32int rotdelay; /* ... */
|
||||
u32int rps;
|
||||
u32int bmask;
|
||||
u32int fmask;
|
||||
u32int bshift;
|
||||
u32int fshift;
|
||||
u32int maxcontig;
|
||||
u32int maxbpg;
|
||||
u32int fragshift;
|
||||
u32int fsbtodbshift;
|
||||
u32int sbsize; /* size of super block */
|
||||
u32int unused2; /* more stuff we don't use ... */
|
||||
u32int unused3;
|
||||
u32int nindir;
|
||||
u32int inosperblock; /* inodes per block */
|
||||
u32int nspf;
|
||||
u32int optim;
|
||||
u32int npsect;
|
||||
u32int interleave;
|
||||
u32int trackskew;
|
||||
u32int id[2];
|
||||
daddr_t csaddr; /* blk addr of cyl grp summary area */
|
||||
u32int cssize; /* size of cyl grp summary area */
|
||||
u32int cgsize; /* cylinder group size */
|
||||
u32int trackspercyl; /* tracks per cylinder */
|
||||
u32int secspertrack; /* sectors per track */
|
||||
u32int secspercyl; /* sectors per cylinder */
|
||||
u32int ncyl; /* cylinders in fs */
|
||||
u32int cylspergroup; /* cylinders per group */
|
||||
u32int inospergroup; /* inodes per group */
|
||||
u32int fragspergroup; /* data blocks per group * fragperblock */
|
||||
Cylsum cstotal; /* more unused... */
|
||||
u8int fmod;
|
||||
u8int clean;
|
||||
u8int ronly;
|
||||
u8int flags;
|
||||
char fsmnt[FSMAXMNTLEN];
|
||||
u32int cgrotor;
|
||||
void* ocsp[FSNOCSPTRS];
|
||||
u8int* contigdirs;
|
||||
Cylsum* csp;
|
||||
u32int* maxcluster;
|
||||
u32int cpc;
|
||||
u16int opostbl[16][8];
|
||||
u32int snapinum[FSMAXSNAP];
|
||||
u32int avgfilesize;
|
||||
u32int avgfpdir;
|
||||
u32int sparecon[26];
|
||||
u32int pendingblocks;
|
||||
u32int pendinginodes;
|
||||
u32int contigsumsize;
|
||||
u32int maxsymlinklen;
|
||||
u32int inodefmt; /* format of on-disk inodes */
|
||||
u64int maxfilesize; /* maximum representable file size */
|
||||
u64int qbmask;
|
||||
u64int qfmask;
|
||||
u32int state;
|
||||
u32int postblformat;
|
||||
u32int nrpos;
|
||||
u32int postbloff;
|
||||
u32int rotbloff;
|
||||
u32int magic; /* FS_MAGIC */
|
||||
};
|
||||
|
||||
/*
|
||||
* Cylinder group block for a file system.
|
||||
*/
|
||||
struct Cgblk
|
||||
{
|
||||
u32int unused0;
|
||||
u32int magic; /* CGMAGIC */
|
||||
u32int time; /* time last written */
|
||||
u32int num; /* we are cg #cgnum */
|
||||
u16int ncyl; /* number of cylinders in gp */
|
||||
u16int nino; /* number of inodes */
|
||||
u32int nfrag; /* number of fragments */
|
||||
Cylsum csum;
|
||||
u32int rotor;
|
||||
u32int frotor;
|
||||
u32int irotor;
|
||||
u32int frsum[MAXFRAG]; /* counts of available frags */
|
||||
u32int btotoff;
|
||||
u32int boff;
|
||||
u32int imapoff; /* offset to used inode map */
|
||||
u32int fmapoff; /* offset to free fragment map */
|
||||
u32int nextfrag; /* next free fragment */
|
||||
u32int csumoff;
|
||||
u32int clusteroff;
|
||||
u32int ncluster;
|
||||
u32int sparecon[13];
|
||||
};
|
||||
|
||||
struct Cylgrp
|
||||
{
|
||||
/* these are block numbers not fragment numbers */
|
||||
u32int bno; /* disk block address of start of cg */
|
||||
u32int ibno; /* disk block address of first inode */
|
||||
u32int dbno; /* disk block address of first data */
|
||||
u32int cgblkno;
|
||||
};
|
||||
|
||||
/*
|
||||
* this is the on-disk structure
|
||||
*/
|
||||
struct Inode
|
||||
{
|
||||
u16int mode;
|
||||
u16int nlink;
|
||||
u32int unused;
|
||||
u64int size;
|
||||
u32int atime;
|
||||
u32int atimensec;
|
||||
u32int mtime;
|
||||
u32int mtimensec;
|
||||
u32int ctime;
|
||||
u32int ctimensec;
|
||||
/* rdev is db[0] */
|
||||
u32int db[NDADDR];
|
||||
u32int ib[NIADDR];
|
||||
u32int flags;
|
||||
u32int nblock;
|
||||
u32int gen;
|
||||
u32int uid;
|
||||
u32int gid;
|
||||
u32int spare[2];
|
||||
};
|
||||
|
||||
struct Dirent
|
||||
{
|
||||
u32int ino;
|
||||
u16int reclen;
|
||||
u8int type;
|
||||
u8int namlen;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* main file system structure
|
||||
*/
|
||||
struct Ffs
|
||||
{
|
||||
int blocksize;
|
||||
int nblock;
|
||||
int fragsize;
|
||||
int fragsperblock;
|
||||
int inosperblock;
|
||||
int blockspergroup;
|
||||
int fragspergroup;
|
||||
int inospergroup;
|
||||
|
||||
u32int nfrag;
|
||||
u32int ndfrag;
|
||||
|
||||
int ncg;
|
||||
Cylgrp *cg;
|
||||
|
||||
Disk *disk;
|
||||
};
|
||||
|
99
src/libdiskfs/file.c
Normal file
99
src/libdiskfs/file.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
typedef struct DiskFile DiskFile;
|
||||
struct DiskFile
|
||||
{
|
||||
Disk disk;
|
||||
int fd;
|
||||
};
|
||||
|
||||
int nfilereads;
|
||||
|
||||
static long
|
||||
preadn(int fd, void *vdata, u32int ulen, u64int offset)
|
||||
{
|
||||
long n;
|
||||
uchar *data;
|
||||
long len;
|
||||
|
||||
nfilereads++;
|
||||
len = ulen;
|
||||
data = vdata;
|
||||
// fprint(2, "readn 0x%llux 0x%ux\n", offset, ulen);
|
||||
while(len > 0){
|
||||
n = pread(fd, data, len, offset);
|
||||
if(n <= 0)
|
||||
break;
|
||||
data += n;
|
||||
offset += n;
|
||||
len -= n;
|
||||
}
|
||||
return data-(uchar*)vdata;
|
||||
}
|
||||
|
||||
static void
|
||||
diskfileblockput(Block *b)
|
||||
{
|
||||
free(b);
|
||||
}
|
||||
|
||||
uvlong nreadx;
|
||||
static Block*
|
||||
diskfileread(Disk *dd, u32int len, u64int offset)
|
||||
{
|
||||
int n;
|
||||
Block *b;
|
||||
DiskFile *d = (DiskFile*)dd;
|
||||
|
||||
b = mallocz(sizeof(Block)+len, 1);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
b->data = (uchar*)&b[1];
|
||||
nreadx += len;
|
||||
n = preadn(d->fd, b->data, len, offset);
|
||||
if(n <= 0){
|
||||
free(b);
|
||||
return nil;
|
||||
}
|
||||
b->_close = diskfileblockput;
|
||||
b->len = n;
|
||||
return b;
|
||||
}
|
||||
|
||||
static int
|
||||
diskfilesync(Disk *dd)
|
||||
{
|
||||
USED(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
diskfileclose(Disk *dd)
|
||||
{
|
||||
DiskFile *d = (DiskFile*)dd;
|
||||
|
||||
close(d->fd);
|
||||
free(d);
|
||||
}
|
||||
|
||||
Disk*
|
||||
diskopenfile(char *file)
|
||||
{
|
||||
int fd;
|
||||
DiskFile *d;
|
||||
|
||||
if((fd = open(file, OREAD)) < 0)
|
||||
return nil;
|
||||
d = mallocz(sizeof(DiskFile), 1);
|
||||
if(d == nil){
|
||||
close(fd);
|
||||
return nil;
|
||||
}
|
||||
d->disk._read = diskfileread;
|
||||
d->disk._sync = diskfilesync;
|
||||
d->disk._close = diskfileclose;
|
||||
d->fd = fd;
|
||||
return &d->disk;
|
||||
}
|
114
src/libdiskfs/fsys.c
Normal file
114
src/libdiskfs/fsys.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <sunrpc.h>
|
||||
#include <nfs3.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
int allowall;
|
||||
|
||||
static Fsys *(*opentab[])(Disk*) =
|
||||
{
|
||||
fsysopenffs,
|
||||
fsysopenkfs,
|
||||
fsysopenext2,
|
||||
fsysopenfat,
|
||||
};
|
||||
|
||||
Fsys*
|
||||
fsysopen(Disk *disk)
|
||||
{
|
||||
int i;
|
||||
Fsys *fsys;
|
||||
|
||||
for(i=0; i<nelem(opentab); i++)
|
||||
if((fsys = (*opentab[i])(disk)) != nil)
|
||||
return fsys;
|
||||
return nil;
|
||||
}
|
||||
|
||||
Block*
|
||||
fsysreadblock(Fsys *fsys, u64int blockno)
|
||||
{
|
||||
if(!fsys->_readblock){
|
||||
werrstr("no read dispatch function");
|
||||
return nil;
|
||||
}
|
||||
return (*fsys->_readblock)(fsys, blockno);
|
||||
}
|
||||
|
||||
int
|
||||
fsyssync(Fsys *fsys)
|
||||
{
|
||||
if(disksync(fsys->disk) < 0)
|
||||
return -1;
|
||||
if(!fsys->_sync)
|
||||
return 0;
|
||||
return (*fsys->_sync)(fsys);
|
||||
}
|
||||
|
||||
void
|
||||
fsysclose(Fsys *fsys)
|
||||
{
|
||||
if(!fsys->_close){
|
||||
fprint(2, "no fsysClose\n");
|
||||
abort();
|
||||
}
|
||||
(*fsys->_close)(fsys);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysroot(Fsys *fsys, Nfs3Handle *h)
|
||||
{
|
||||
if(!fsys->_root)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_root)(fsys, h);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsyslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
|
||||
{
|
||||
if(!fsys->_lookup)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_lookup)(fsys, au, h, name, nh);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
|
||||
{
|
||||
if(!fsys->_getattr)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_getattr)(fsys, au, h, attr);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **e, u32int *ne, u1int *peof)
|
||||
{
|
||||
if(!fsys->_readdir)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_readdir)(fsys, au, h, count, cookie, e, ne, peof);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int offset, uchar **data, u32int *pcount, uchar *peof)
|
||||
{
|
||||
if(!fsys->_readfile)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_readfile)(fsys, au, h, count, offset, data, pcount, peof);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **plink)
|
||||
{
|
||||
if(!fsys->_readlink)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_readlink)(fsys, au, h, plink);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
|
||||
{
|
||||
if(!fsys->_access)
|
||||
return Nfs3ErrNxio;
|
||||
return (*fsys->_access)(fsys, au, h, want, got, attr);
|
||||
}
|
11
src/libdiskfs/kfs.c
Normal file
11
src/libdiskfs/kfs.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <diskfs.h>
|
||||
|
||||
Fsys*
|
||||
fsysopenkfs(Disk *disk)
|
||||
{
|
||||
USED(disk);
|
||||
return nil;
|
||||
}
|
||||
|
31
src/libdiskfs/mkfile
Normal file
31
src/libdiskfs/mkfile
Normal file
|
@ -0,0 +1,31 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
LIB=libdiskfs.a
|
||||
|
||||
FSOFILES=\
|
||||
ext2.$O\
|
||||
fat.$O\
|
||||
ffs.$O\
|
||||
kfs.$O\
|
||||
|
||||
DISKOFILES=\
|
||||
cache.$O\
|
||||
file.$O\
|
||||
venti.$O\
|
||||
|
||||
OFILES=\
|
||||
block.$O\
|
||||
disk.$O\
|
||||
fsys.$O\
|
||||
$DISKOFILES\
|
||||
$FSOFILES\
|
||||
|
||||
HFILES=\
|
||||
fs.h
|
||||
|
||||
<$PLAN9/src/mksyslib
|
||||
|
||||
CFLAGS=$CFLAGS
|
||||
|
||||
%.acid: %.$O %.c
|
||||
$CC $CFLAGS -a $stem.c >$stem.acid
|
163
src/libdiskfs/venti.c
Normal file
163
src/libdiskfs/venti.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <diskfs.h>
|
||||
#include <venti.h>
|
||||
|
||||
extern void vtlibthread(void);
|
||||
|
||||
typedef struct DiskVenti DiskVenti;
|
||||
struct DiskVenti
|
||||
{
|
||||
Disk disk;
|
||||
VtEntry e;
|
||||
VtCache *c;
|
||||
};
|
||||
|
||||
int nfilereads;
|
||||
|
||||
/*
|
||||
* This part is like file.c but doesn't require storing the root block
|
||||
* in the cache permanently and doesn't care about locking since
|
||||
* all the blocks are read-only. Perhaps at some point this functionality
|
||||
* should go into libvac in some form.
|
||||
*/
|
||||
static int
|
||||
vtfileindices(VtEntry *e, u32int bn, int *index)
|
||||
{
|
||||
int i, np;
|
||||
|
||||
memset(index, 0, VtPointerDepth*sizeof(int));
|
||||
|
||||
np = e->psize/VtScoreSize;
|
||||
memset(index, 0, sizeof(index));
|
||||
for(i=0; bn > 0; i++){
|
||||
if(i >= VtPointerDepth){
|
||||
werrstr("bad block number %lud", (ulong)bn);
|
||||
return -1;
|
||||
}
|
||||
index[i] = bn % np;
|
||||
bn /= np;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static VtBlock*
|
||||
_vtfileblock(VtCache *c, VtEntry *e, u32int bn)
|
||||
{
|
||||
VtBlock *b, *bb;
|
||||
int i, d, index[VtPointerDepth+1], t;
|
||||
|
||||
i = vtfileindices(e, bn, index);
|
||||
if(i < 0)
|
||||
return nil;
|
||||
d = (e->type&VtTypeDepthMask);
|
||||
if(i > d){
|
||||
werrstr("bad address %d > %d (%x %x)", i, d, e->type, e->flags);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//fprint(2, "vtread %V\n", e->score);
|
||||
b = vtcacheglobal(c, e->score, e->type);
|
||||
if(b == nil)
|
||||
return nil;
|
||||
|
||||
for(i=d-1; i>=0; i--){
|
||||
t = VtDataType+i;
|
||||
//fprint(2, "vtread %V\n", b->data+index[i]*VtScoreSize);
|
||||
bb = vtcacheglobal(c, b->data+index[i]*VtScoreSize, t);
|
||||
vtblockput(b);
|
||||
if(bb == nil)
|
||||
return nil;
|
||||
b = bb;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
static void
|
||||
diskventiblockput(Block *b)
|
||||
{
|
||||
vtblockput(b->priv);
|
||||
free(b);
|
||||
}
|
||||
|
||||
static Block*
|
||||
diskventiread(Disk *dd, u32int len, u64int offset)
|
||||
{
|
||||
DiskVenti *d = (DiskVenti*)dd;
|
||||
VtBlock *vb;
|
||||
Block *b;
|
||||
int frag;
|
||||
|
||||
nfilereads++;
|
||||
vb = _vtfileblock(d->c, &d->e, offset/d->e.dsize);
|
||||
if(vb == nil)
|
||||
return nil;
|
||||
|
||||
b = mallocz(sizeof(Block), 1);
|
||||
if(b == nil){
|
||||
vtblockput(vb);
|
||||
return nil;
|
||||
}
|
||||
|
||||
b->priv = vb;
|
||||
b->_close = diskventiblockput;
|
||||
frag = offset%d->e.dsize;
|
||||
b->data = (uchar*)vb->data + frag;
|
||||
b->len = d->e.dsize - frag;
|
||||
if(b->len > len)
|
||||
b->len = len;
|
||||
return b;
|
||||
}
|
||||
|
||||
static void
|
||||
diskventiclose(Disk *dd)
|
||||
{
|
||||
DiskVenti *d = (DiskVenti*)dd;
|
||||
free(d);
|
||||
}
|
||||
|
||||
Disk*
|
||||
diskopenventi(VtCache *c, uchar score[VtScoreSize])
|
||||
{
|
||||
DiskVenti *d;
|
||||
VtEntry e;
|
||||
VtRoot root;
|
||||
VtBlock *b;
|
||||
|
||||
if((b = vtcacheglobal(c, score, VtRootType)) == nil)
|
||||
goto Err;
|
||||
if(vtrootunpack(&root, b->data) < 0)
|
||||
goto Err;
|
||||
if(root.blocksize < 512 || (root.blocksize&(root.blocksize-1))){
|
||||
werrstr("bad blocksize %d", root.blocksize);
|
||||
goto Err;
|
||||
}
|
||||
vtblockput(b);
|
||||
|
||||
if((b = vtcacheglobal(c, root.score, VtDirType)) == nil)
|
||||
goto Err;
|
||||
if(vtentryunpack(&e, b->data, 0) < 0)
|
||||
goto Err;
|
||||
vtblockput(b);
|
||||
b = nil;
|
||||
if((e.type&VtTypeBaseMask) != VtDataType){
|
||||
werrstr("not a single file");
|
||||
goto Err;
|
||||
}
|
||||
|
||||
d = mallocz(sizeof(DiskVenti), 1);
|
||||
if(d == nil)
|
||||
goto Err;
|
||||
|
||||
d->disk._read = diskventiread;
|
||||
d->disk._close = diskventiclose;
|
||||
d->e = e;
|
||||
d->c = c;
|
||||
return &d->disk;
|
||||
|
||||
Err:
|
||||
if(b)
|
||||
vtblockput(b);
|
||||
return nil;
|
||||
}
|
||||
|
35
src/libdiskfs/vfile.c
Normal file
35
src/libdiskfs/vfile.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <diskfs.h>
|
||||
#include <venti.h>
|
||||
|
||||
extern void vtLibThread(void);
|
||||
|
||||
typedef struct DiskVenti DiskVenti;
|
||||
struct DiskVenti
|
||||
{
|
||||
TvCache *c;
|
||||
Entry e;
|
||||
};
|
||||
|
||||
Disk*
|
||||
diskOpenVenti(TvCache *c, uchar score[VtScoreSize])
|
||||
{
|
||||
vtLibThread();
|
||||
|
||||
fetch vtroot
|
||||
fetch dir block
|
||||
copy e
|
||||
}
|
||||
|
||||
Block*
|
||||
diskVentiRead(Disk *dd, u32int len, u64int offset)
|
||||
{
|
||||
DiskVenti *d = (DiskVenti*)dd;
|
||||
|
||||
make offset list
|
||||
walk down blocks
|
||||
return the one
|
||||
}
|
||||
|
||||
|
Loading…
Reference in a new issue