⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ext2subs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ext2subs.c version 0.20 *  * Some strategic functions come from linux/fs/ext2 * kernel sources written by Remy Card. **/#include <u.h>#include <libc.h>#include <bio.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include "dat.h"#include "fns.h"#define putext2(e)	putbuf((e).buf)#define dirtyext2(e)	dirtybuf((e).buf)static Intmap *uidmap, *gidmap;static intgetnum(char *s, int *n){	char *r;	*n = strtol(s, &r, 10);	return (r != s);}static Intmap*idfile(char *f){	Biobuf *bin;	Intmap *map;	char *fields[3];	char *s;	int nf, id;	map = allocmap(0);	bin = Bopen(f, OREAD);	if (bin == 0)		return 0;	while ((s = Brdline(bin, '\n')) != 0) {		s[Blinelen(bin)-1] = '\0';		nf = getfields(s, fields, 3, 0, ":");		if (nf == 3 && getnum(fields[2], &id))			insertkey(map, id, strdup(fields[0]));	}	Bterm(bin);	return map;}voiduidfile(char *f){	uidmap = idfile(f);}voidgidfile(char *f){	gidmap = idfile(f);}static char*mapuid(int id){	static char s[12];	char *p;	if (uidmap && (p = lookupkey(uidmap, id)) != 0)		return p;	sprint(s, "%d", id);	return s;}static char*mapgid(int id){	static char s[12];	char *p;	if (gidmap && (p = lookupkey(gidmap, id)) != 0)		return p;	sprint(s, "%d", id);	return s;}intext2fs(Xfs *xf){	SuperBlock superblock;	/* get the super block */	seek(xf->dev, OFFSET_SUPER_BLOCK, 0);	if( sizeof(SuperBlock) != 				read(xf->dev, &superblock, sizeof(SuperBlock)) ){		chat("can't read super block %r...", xf->dev);		errno = Eformat;		return -1;	}	if( superblock.s_magic != EXT2_SUPER_MAGIC ){		chat("Bad super block...");		errno = Eformat;		return -1;	}	if( !(superblock.s_state & EXT2_VALID_FS) ){		chat("fs not checked...");		errno = Enotclean;		return -1;	}		xf->block_size = EXT2_MIN_BLOCK_SIZE << superblock.s_log_block_size;	xf->desc_per_block = xf->block_size / sizeof (GroupDesc);	xf->inodes_per_group = superblock.s_inodes_per_group;	xf->inodes_per_block = xf->block_size / sizeof (Inode);	xf->addr_per_block = xf->block_size / sizeof (uint);	xf->blocks_per_group = superblock.s_blocks_per_group;	if( xf->block_size == OFFSET_SUPER_BLOCK )		xf->superaddr = 1, xf->superoff = 0, xf->grpaddr = 2;	else if( xf->block_size == 2*OFFSET_SUPER_BLOCK ||			xf->block_size == 4*OFFSET_SUPER_BLOCK )		xf->superaddr = 0, xf->superoff = OFFSET_SUPER_BLOCK, xf->grpaddr = 1;	else {		chat(" blocks of %d bytes are not supported...", xf->block_size);		errno = Eformat;		return -1;	}	chat("good super block...");	xf->ngroups = (superblock.s_blocks_count - 				superblock.s_first_data_block + 				superblock.s_blocks_per_group -1) / 				superblock.s_blocks_per_group;	superblock.s_state &= ~EXT2_VALID_FS;	superblock.s_mnt_count++;	seek(xf->dev, OFFSET_SUPER_BLOCK, 0);	if( !rdonly && sizeof(SuperBlock) != 				write(xf->dev, &superblock, sizeof(SuperBlock)) ){		chat("can't write super block...");		errno = Eio;		return -1;	}	return 0;}Ext2getext2(Xfs *xf, char type, int n){	Iobuf *bd;	Ext2 e;	switch(type){	case EXT2_SUPER:		e.buf = getbuf(xf, xf->superaddr);		if( !e.buf ) goto error;		e.u.sb = (SuperBlock *)(e.buf->iobuf + xf->superoff);		e.type = EXT2_SUPER;		break;	case EXT2_DESC:		e.buf = getbuf(xf, DESC_ADDR(xf, n));		if( !e.buf ) goto error;		e.u.gd = DESC_OFFSET(xf, e.buf->iobuf, n);		e.type = EXT2_DESC;		break;	case EXT2_BBLOCK:		bd = getbuf(xf, DESC_ADDR(xf, n));		if( !bd ) goto error;		e.buf = getbuf(xf, DESC_OFFSET(xf, bd->iobuf, n)->bg_block_bitmap);		if( !e.buf ){			putbuf(bd);			goto error;		}		putbuf(bd);		e.u.bmp = (char *)e.buf->iobuf;		e.type = EXT2_BBLOCK;		break;	case EXT2_BINODE:		bd = getbuf(xf, DESC_ADDR(xf, n));		if( !bd ) goto error;		e.buf = getbuf(xf, DESC_OFFSET(xf, bd->iobuf, n)->bg_inode_bitmap);		if( !e.buf ){			putbuf(bd);			goto error;		}		putbuf(bd);		e.u.bmp = (char *)e.buf->iobuf;		e.type = EXT2_BINODE;		break;	default:		goto error;	}	return e;error:	panic("getext2");	return e;}intget_inode( Xfile *file, uint nr ){	unsigned long block_group, block;	Xfs *xf = file->xf;	Ext2 ed, es;	es = getext2(xf, EXT2_SUPER, 0);	if( nr < 0 || nr > es.u.sb->s_inodes_count ){		chat("inode number %d is too big...", nr);		putext2(es);		errno = Eio;		return -1;	}	putext2(es);	block_group = (nr - 1) / xf->inodes_per_group;	if( block_group >= xf->ngroups ){		chat("block group (%d) > groups count...", block_group);		errno = Eio;		return -1;	}	ed = getext2(xf, EXT2_DESC, block_group);	block = ed.u.gd->bg_inode_table + (((nr-1) % xf->inodes_per_group) / 			xf->inodes_per_block);	putext2(ed);	file->bufoffset = (nr-1) % xf->inodes_per_block;	file->inbr = nr;	file->bufaddr= block;	return 1;}intget_file( Xfile *f, char *name){		uint offset, nr, i;	Xfs *xf = f->xf;	Inode *inode;	int nblock;	DirEntry *dir;	Iobuf *buf, *ibuf;		if( !S_ISDIR(getmode(f)) )		return -1;	ibuf = getbuf(xf, f->bufaddr);	if( !ibuf )		return -1;	inode = ((Inode *)ibuf->iobuf) + f->bufoffset;	nblock = (inode->i_blocks * 512) / xf->block_size;	for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){		buf = getbuf(xf, inode->i_block[i]);		if( !buf ){			putbuf(ibuf);			return -1;		}		for(offset=0 ; offset < xf->block_size ;  ){			dir = (DirEntry *)(buf->iobuf + offset);			if( dir->name_len==strlen(name) && 					!strncmp(name, dir->name, dir->name_len) ){				nr = dir->inode;				putbuf(buf);				putbuf(ibuf);				return nr;			}			offset += dir->rec_len;		}		putbuf(buf);	}	putbuf(ibuf);	errno = Enonexist;	return -1;}char *getname(Xfile *f, char *str){	Xfile ft;	int offset, i, len;	Xfs *xf = f->xf;	Inode *inode;	int nblock;	DirEntry *dir;	Iobuf *buf, *ibuf;	ft = *f;	if( get_inode(&ft, f->pinbr) < 0 )		return 0;	if( !S_ISDIR(getmode(&ft)) )		return 0;	ibuf = getbuf(xf, ft.bufaddr);	if( !ibuf )		return 0;	inode = ((Inode *)ibuf->iobuf) + ft.bufoffset;	nblock = (inode->i_blocks * 512) / xf->block_size;	for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){		buf = getbuf(xf, inode->i_block[i]);		if( !buf ){			putbuf(ibuf);			return 0;		}		for(offset=0 ; offset < xf->block_size ;  ){			dir = (DirEntry *)(buf->iobuf + offset);			if( f->inbr == dir->inode ){				len = (dir->name_len < EXT2_NAME_LEN) ? dir->name_len : EXT2_NAME_LEN;				if (str == 0)					str = malloc(len+1);				strncpy(str, dir->name, len);   				str[len] = 0;				putbuf(buf);				putbuf(ibuf);				return str;			}			offset += dir->rec_len;		}		putbuf(buf);	}	putbuf(ibuf);	errno = Enonexist;	return 0;}voiddostat(Qid qid, Xfile *f, Dir *dir ){	Inode *inode;	Iobuf *ibuf;	char *name;	memset(dir, 0, sizeof(Dir));	if(  f->inbr == EXT2_ROOT_INODE ){		dir->name = estrdup9p("/");		dir->qid = (Qid){0,0,QTDIR};		dir->mode = DMDIR | 0777;	}else{		ibuf = getbuf(f->xf, f->bufaddr);		if( !ibuf )			return;		inode = ((Inode *)ibuf->iobuf) + f->bufoffset;		dir->length = inode->i_size;		dir->atime = inode->i_atime;		dir->mtime = inode->i_mtime;		putbuf(ibuf);		name = getname(f, 0);		dir->name = name;		dir->uid = estrdup9p(mapuid(inode->i_uid));		dir->gid = estrdup9p(mapgid(inode->i_gid));		dir->qid = qid;		dir->mode = getmode(f);		if( qid.type & QTDIR )			dir->mode |= DMDIR;	}}int dowstat(Xfile *f, Dir *stat){	Xfs *xf = f->xf;	Inode *inode;	Xfile fdir;	Iobuf *ibuf;	char name[EXT2_NAME_LEN+1];	/* change name */	getname(f, name);	if( stat->name && stat->name[0] != 0 && strcmp(name, stat->name) ){		/* get dir */		fdir = *f;		if( get_inode(&fdir, f->pinbr) < 0 ){			chat("can't get inode %d...", f->pinbr);			return -1;		}			ibuf = getbuf(xf, fdir.bufaddr);		if( !ibuf )			return -1;		inode = ((Inode *)ibuf->iobuf) +fdir.bufoffset;		/* Clean old dir entry */		if( delete_entry(xf, inode, f->inbr) < 0 ){			chat("delete entry failed...");			putbuf(ibuf);				return -1;		}		putbuf(ibuf);		/* add the new entry */		if( add_entry(&fdir, stat->name, f->inbr) < 0 ){			chat("add entry failed...");				return -1;		}		}	ibuf = getbuf(xf, f->bufaddr);	if( !ibuf )		return -1;	inode = ((Inode *)ibuf->iobuf) + f->bufoffset;	if (stat->mode != ~0)	if( (getmode(f) & 0777) != (stat->mode & 0777) ){		inode->i_mode = (getmode(f) & ~0777) | (stat->mode & 0777);		dirtybuf(ibuf);	}	if (stat->mtime != ~0)	if(  inode->i_mtime != stat->mtime ){		inode->i_mtime = stat->mtime;		dirtybuf(ibuf);	}	putbuf(ibuf);	return 1;}longreadfile(Xfile *f, void *vbuf, vlong offset, long count){	Xfs *xf = f->xf;	Inode *inode;	Iobuf *buffer, *ibuf;	long rcount;	int len, o, cur_block, baddr;	uchar *buf;	buf = vbuf;		ibuf = getbuf(xf, f->bufaddr);	if( !ibuf )		return -1;	inode = ((Inode *)ibuf->iobuf) + f->bufoffset;	if( offset >= inode->i_size ){		putbuf(ibuf);		return 0;	}	if( offset + count > inode->i_size )		count = inode->i_size - offset;	/* fast link */	if( S_ISLNK(getmode(f)) && (inode->i_size <= EXT2_N_BLOCKS<<2) ){		memcpy(&buf[0], ((char *)inode->i_block)+offset, count);		putbuf(ibuf);			return count;	}	chat("read block [ ");	cur_block = offset / xf->block_size;	o = offset % xf->block_size;	rcount = 0;	while( count > 0 ){		baddr = bmap(f, cur_block++);		if( !baddr ){			putbuf(ibuf);			return -1;		}		buffer = getbuf(xf, baddr);		if( !buffer ){			putbuf(ibuf);			return -1;		}		chat("%d ", baddr);		len = xf->block_size - o;		if( len > count )			len = count;		memcpy(&buf[rcount], &buffer->iobuf[o], len);		rcount += len;		count -= len;		o = 0;		putbuf(buffer);	}	chat("] ...");	inode->i_atime = time(0);	dirtybuf(ibuf);	putbuf(ibuf);	return rcount;}longreaddir(Xfile *f, void *vbuf, vlong offset, long count){	int off, i, len;	long rcount;	Xfs *xf = f->xf;	Inode *inode, *tinode;	int nblock;	DirEntry *edir;	Iobuf *buffer, *ibuf, *tbuf;	Dir pdir;	Xfile ft;	uchar *buf;	char name[EXT2_NAME_LEN+1];	unsigned int dirlen;	int index;	buf = vbuf;	if (offset == 0)		f->dirindex = 0;		if( !S_ISDIR(getmode(f)) )		return -1;	ibuf = getbuf(xf, f->bufaddr);	if( !ibuf )		return -1;	inode = ((Inode *)ibuf->iobuf) + f->bufoffset;	nblock = (inode->i_blocks * 512) / xf->block_size;	ft = *f;	chat("read block [ ");	index = 0;	for(i=0, rcount=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){				buffer = getbuf(xf, inode->i_block[i]);		if( !buffer ){			putbuf(ibuf);			return -1;		}		chat("%d, ", buffer->addr);		for(off=0 ; off < xf->block_size ;  ){					edir = (DirEntry *)(buffer->iobuf + off);				off += edir->rec_len;			if( (edir->name[0] == '.' ) && (edir->name_len == 1))				continue;			if(edir->name[0] == '.' && edir->name[1] == '.' && 										edir->name_len == 2)				continue;			if( edir->inode == 0 ) /* for lost+found dir ... */				continue;			if( index++ < f->dirindex )				continue;						if( get_inode(&ft, edir->inode) < 0 ){				chat("can't find ino no %d ] ...", edir->inode);error:			putbuf(buffer);				putbuf(ibuf);				return -1;			}			tbuf = getbuf(xf, ft.bufaddr);			if( !tbuf )				goto error;			tinode = ((Inode *)tbuf->iobuf) + ft.bufoffset;			memset(&pdir, 0, sizeof(Dir));									/* fill plan9 dir struct */						pdir.name = name;			len = (edir->name_len < EXT2_NAME_LEN) ? edir->name_len : EXT2_NAME_LEN;			strncpy(pdir.name, edir->name, len);   			pdir.name[len] = 0;// chat("name %s len %d\n", pdir.name, edir->name_len);			pdir.uid = mapuid(tinode->i_uid);			pdir.gid = mapgid(tinode->i_gid);			pdir.qid.path = edir->inode;			pdir.mode = tinode->i_mode;			if( edir->inode == EXT2_ROOT_INODE )				pdir.qid.path = f->xf->rootqid.path;			else if( S_ISDIR( tinode->i_mode) )				pdir.qid.type |= QTDIR;			if( pdir.qid.type & QTDIR )				pdir.mode |= DMDIR;			pdir.length = tinode->i_size;			pdir.atime = tinode->i_atime;			pdir.mtime = tinode->i_mtime;					putbuf(tbuf);			dirlen = convD2M(&pdir, &buf[rcount], count-rcount);			if ( dirlen <= BIT16SZ ) {				chat("] ...");				putbuf(buffer);				putbuf(ibuf);				return rcount;			}			rcount += dirlen;			f->dirindex++;		}		putbuf(buffer);	}	chat("] ...");	putbuf(ibuf);	return rcount;}intbmap( Xfile *f, int block ){	Xfs *xf = f->xf;	Inode *inode;	Iobuf *buf, *ibuf;	int addr;	int addr_per_block = xf->addr_per_block;	int addr_per_block_bits = ffz(~addr_per_block);		if(block < 0) {		chat("bmap() block < 0 ...");		return 0;	}	if(block >= EXT2_NDIR_BLOCKS + addr_per_block +		(1 << (addr_per_block_bits * 2)) +		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {		chat("bmap() block > big...");		return 0;	}	ibuf = getbuf(xf, f->bufaddr);	if( !ibuf )		return 0;	inode = ((Inode *)ibuf->iobuf) + f->bufoffset;	/* direct blocks */	if(block < EXT2_NDIR_BLOCKS){		putbuf(ibuf);		return inode->i_block[block];	}	block -= EXT2_NDIR_BLOCKS;		/* indirect blocks*/	if(block < addr_per_block) {		addr = inode->i_block[EXT2_IND_BLOCK];		if (!addr) goto error;		buf = getbuf(xf, addr);		if( !buf ) goto error;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -