886 lines · 18.3 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <sunrpc.h>#include <nfs3.h>#include <diskfs.h>#include "ext2.h" static void parsedirent(Dirent*, uchar*);static void parseinode(Inode*, uchar*);static void parsegroup(Group*, uchar*);static void parsesuper(Super*, uchar*); #define debug 0 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, u32int bs, u64int off){	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;	fsys->_close = ext2close; 	if(ext2sync(fsys) < 0)		goto error; 	return fsys; error:	ext2close(fsys);	return nil;} static voidext2close(Fsys *fsys){	Ext2 *fs; 	fs = fsys->priv;	free(fs);	free(fsys);} static intext2group(Ext2 *fs, u32int i, Group *g){	Block *b;	u64int addr; 	if(i >= fs->ngroup)		return -1; 	addr = fs->groupaddr + i/fs->descperblock;	b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);	if(b == nil)		return -1;	parsegroup(g, b->data+i%fs->descperblock*GroupSize);	blockput(b);	return 0;} static Block*ext2blockread(Fsys *fsys, u64int vbno){	Block *bitb;	Group g;	uchar *bits;	u32int bno, boff, bitblock;	u64int bitpos;	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(ext2group(fs, bno/fs->blockspergroup, &g) < 0){		if(debug)			fprint(2, "loading group: %r...");		return nil;	}/*	if(debug)		fprint(2, "ext2 group %d: bitblock=%ud inodebitblock=%ud inodeaddr=%ud freeblocks=%ud freeinodes=%ud useddirs=%ud\n",			(int)(bno/fs->blockspergroup),			g.bitblock,			g.inodebitblock,			g.inodeaddr,			g.freeblockscount,			g.freeinodescount,			g.useddirscount);	if(debug)		fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g.bitblock);*/	bitblock = g.bitblock;	bitpos = (u64int)bitblock*fs->blocksize; 	if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){		if(debug)			fprint(2, "loading bitblock: %r...");		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 in group %d: bitblock %d/%lld bits[%d] = %#x\n",				boff, bno/fs->blockspergroup, 				(int)bitblock,				bitpos,				boff>>3,				bits[boff>>3]);		blockput(bitb);		return nil;	}	blockput(bitb); 	bno += fs->firstblock;	return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);} static Block*ext2datablock(Ext2 *fs, u32int bno, int size){	USED(size);	return ext2blockread(fs->fsys, bno);} static Block*ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size){	int ppb;	Block *b;	u32int *a;	u32int obno, pbno; 	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];		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;		pbno = a[bno/ppb];		bno = bno%ppb;		blockput(b);		b = ext2datablock(fs, pbno, fs->blocksize);		if(b == nil)			return nil;		a = (u32int*)b->data;		bno = a[bno];		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;		pbno = a[bno/(ppb*ppb)];		bno = bno%(ppb*ppb);		blockput(b);		b = ext2datablock(fs, pbno, fs->blocksize);		if(b == nil)			return nil;		a = (u32int*)b->data;		pbno = a[bno/ppb];		bno = bno%ppb;		blockput(b);		b = ext2datablock(fs, pbno, fs->blocksize);		if(b == nil)			return nil;		a = (u32int*)b->data;		bno = a[bno];		blockput(b);		return ext2datablock(fs, bno, size);	} 	fprint(2, "ext2fileblock %ud: too big\n", obno);	return nil;} static intchecksuper(Super *super){	if(super->magic != SUPERMAGIC){		werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);		return -1;	}	return 0;} static intext2sync(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)		return -1;	parsesuper(&super, b->data);	blockput(b);	if(checksuper(&super) < 0)		return -1;	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;	if(super.revlevel >= 1)		fs->inosize = super.inosize;	else		fs->inosize = 128;	fs->inosperblock = fs->blocksize / fs->inosize;	if(fs->blocksize == SBOFF)		fs->groupaddr = 2;	else		fs->groupaddr = 1;	fs->descperblock = fs->blocksize / GroupSize;	fs->firstblock = super.firstdatablock; 	fsys->blocksize = fs->blocksize;	fsys->nblock = fs->nblock;	if(debug) 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(ext2group(fs, i, &g) >= 0)				fprint(2, "grp %d: bitblock=%d\n", i, g.bitblock);	}	return 0;} static voidmkhandle(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 u32intbyte2u32(uchar *p){	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];} static Nfs3Statushandle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino){	int i;	uint ioff;	u32int inum;	u32int addr;	Block *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(ext2group(fs, i, &g) < 0)		return Nfs3ErrIo;	addr = g.inodeaddr + ioff/fs->inosperblock;	if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)		return Nfs3ErrIo;	parseinode(ino, b->data+fs->inosize*(ioff%fs->inosperblock));	blockput(b);	return Nfs3Ok;} static Nfs3Statusext2root(Fsys *fsys, Nfs3Handle *h){	USED(fsys);	mkhandle(h, ROOTINODE);	return Nfs3Ok;} static u64intinosize(Inode* ino){	u64int size; 	size = ino->size;	if((ino->mode&IFMT)==IFREG)		size |= (u64int)ino->diracl << 32;	return size;} static Nfs3Statusino2attr(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 = inosize(ino);	attr->used = (u64int)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 intingroup(SunAuthUnix *au, uint gid){	int i; 	for(i=0; i<au->ng; i++)		if(au->g[i] == gid)			return 1;	return 0;} static Nfs3Statusinoperm(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 Nfs3Statusext2getattr(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 Nfs3Statusext2access(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);} 

Lines 1–500 of 886.