plan 9 kernel history: overview | file list | diff list

1999/0727/mpc/devsac.c (diff list | history)

mpc/devsac.c on 1999/0608
1999/0608    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
1999/0609    
#include "../port/error.h" 
1999/0608    
 
/* 
 * Rather than reading /adm/users, which is a lot of work for 
 * a toy program, we assume all groups have the form 
 *	NNN:user:user: 
 * meaning that each user is the leader of his own group. 
 */ 
 
enum 
{ 
	OPERM	= 0x3,		/* mask of all permission types in open mode */ 
	Nram	= 512, 
}; 
 
typedef struct SacPath SacPath; 
typedef struct Sac Sac; 
typedef struct SacHeader SacHeader; 
typedef struct SacDir SacDir; 
 
enum { 
	Magic = 0x5acf5, 
}; 
 
struct SacDir 
{ 
	char	name[NAMELEN]; 
	char	uid[NAMELEN]; 
	char	gid[NAMELEN]; 
	uchar	qid[4]; 
	uchar	mode[4]; 
	uchar	atime[4]; 
	uchar	mtime[4]; 
	uchar	length[8]; 
	uchar	blocks[8]; 
}; 
 
struct SacHeader 
{ 
	uchar	magic[4]; 
	uchar	length[8]; 
	uchar	blocksize[4]; 
	uchar	md5[16]; 
}; 
 
 
struct Sac 
{ 
	SacDir; 
	SacPath *path; 
}; 
 
struct SacPath 
{ 
	Ref; 
	SacPath *up; 
	vlong blocks; 
	int entry; 
}; 
 
enum 
{ 
	Pexec =		1, 
	Pwrite = 	2, 
	Pread = 	4, 
	Pother = 	1, 
	Pgroup = 	8, 
	Powner =	64, 
}; 
 
1999/0609    
static uchar *data = SACMEM; 
static int blocksize; 
static Sac root; 
1999/0608    
 
1999/0609    
static void	sacdir(Chan *, SacDir*, char*); 
static ulong	getl(void *p); 
static vlong	getv(void *p); 
static Sac	*saccpy(Sac *s); 
static Sac *saclookup(Sac *s, char *name); 
static int sacdirread(Chan *, char *p, long off, long cnt); 
static void loadblock(void *buf, uchar *offset, int blocksize); 
static void sacfree(Sac*); 
1999/0608    
 
1999/0609    
static void 
sacinit(void) 
1999/0608    
{ 
	SacHeader *hdr; 
1999/0609    
print("sacinit\n"); 
1999/0608    
	hdr = (SacHeader*)data; 
	if(getl(hdr->magic) != Magic) { 
1999/0609    
print("devsac: bad magic\n"); 
1999/0608    
		return; 
	} 
	blocksize = getl(hdr->blocksize); 
	root.SacDir = *(SacDir*)(data + sizeof(SacHeader)); 
} 
 
static Chan* 
sacattach(char* spec) 
{ 
	Chan *c; 
	int dev; 
 
	dev = atoi(spec); 
	if(dev != 0) 
		error("bad specification"); 
 
	// check if init found sac file system in memory 
	if(blocksize == 0) 
		error("devsac: bad magic"); 
 
	c = devattach('C', spec); 
	c->qid = (Qid){getl(root.qid), 0}; 
	c->dev = dev; 
	c->aux = saccpy(&root); 
	return c; 
} 
 
1999/0609    
static Chan* 
1999/0608    
sacclone(Chan *c, Chan *nc) 
{ 
	nc = devclone(c, nc); 
	nc->aux = saccpy(c->aux); 
	return nc; 
} 
 
1999/0609    
static int 
sacwalk(Chan *c, char *name) 
1999/0608    
{ 
	Sac *sac; 
 
1999/0610    
//print("walk %s\n", name); 
 
1999/0608    
	isdir(c); 
1999/0609    
	if(name[0]=='.' && name[1]==0) 
1999/0608    
		return 1; 
1999/0609    
	sac = c->aux; 
1999/0608    
	sac = saclookup(sac, name); 
	if(sac == nil) { 
		strncpy(up->error, Enonexist, NAMELEN); 
		return 0; 
	} 
	c->aux = sac; 
	c->qid = (Qid){getl(sac->qid), 0}; 
	return 1; 
} 
 
1999/0609    
static Chan* 
sacopen(Chan *c, int omode) 
1999/0608    
{ 
1999/0609    
	ulong t, mode; 
	Sac *sac; 
	static int access[] = { 0400, 0200, 0600, 0100 }; 
1999/0608    
 
1999/0609    
	sac = c->aux; 
	mode = getl(sac->mode); 
	if(strcmp(up->user, sac->uid) == 0) 
		mode = mode; 
	else if(strcmp(up->user, sac->gid) == 0) 
		mode = mode<<3; 
	else 
		mode = mode<<6; 
1999/0608    
 
1999/0609    
	t = access[omode&3]; 
	if((t & mode) != t) 
			error(Eperm); 
	c->offset = 0; 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	return c; 
1999/0608    
} 
 
1999/0609    
 
static long 
sacread(Chan *c, void *a, long n, vlong off) 
1999/0608    
{ 
	Sac *sac; 
	char *buf, *buf2; 
1999/0609    
	int nn, cnt, i, j; 
1999/0608    
	uchar *blocks; 
	vlong length; 
 
1999/0609    
	buf = a; 
	cnt = n; 
	if(c->qid.path & CHDIR){ 
		cnt = (cnt/DIRLEN)*DIRLEN; 
1999/0608    
		if(off%DIRLEN) 
1999/0609    
			error("i/o error"); 
		return sacdirread(c, buf, off, cnt); 
1999/0608    
	} 
1999/0609    
	sac = c->aux; 
1999/0610    
//print("sacread: %s %llx %d\n", sac->name, off, n); 
1999/0608    
	length = getv(sac->length); 
1999/0609    
	if(off >= length) 
1999/0608    
		return 0; 
	if(cnt > length-off) 
		cnt = length-off; 
	if(cnt == 0) 
		return 0; 
1999/0609    
	n = cnt; 
1999/0608    
	blocks = data + getv(sac->blocks); 
	buf2 = malloc(blocksize); 
	while(cnt > 0) { 
		i = off/blocksize; 
		loadblock(buf2, blocks+i*8, blocksize); 
		j = off-i*blocksize; 
1999/0609    
		nn = blocksize-j; 
		if(nn > cnt) 
			nn = cnt; 
		memmove(buf, buf2+j, nn); 
		cnt -= nn; 
		off += nn; 
1999/0610    
		buf += nn; 
1999/0608    
	} 
	free(buf2); 
1999/0609    
	return n; 
1999/0608    
} 
 
1999/0609    
static long 
sacwrite(Chan *, void *, long, vlong) 
1999/0608    
{ 
1999/0609    
	error(Eperm); 
1999/0608    
	return 0; 
} 
 
1999/0609    
static void 
sacclose(Chan* c) 
1999/0608    
{ 
1999/0609    
	Sac *sac = c->aux; 
	c->aux = nil; 
	sacfree(sac); 
1999/0608    
} 
 
 
1999/0609    
static void 
sacstat(Chan *c, char *db) 
1999/0608    
{ 
1999/0609    
	sacdir(c, c->aux, db); 
1999/0608    
} 
 
1999/0609    
static Sac* 
1999/0608    
saccpy(Sac *s) 
{ 
	Sac *ss; 
	 
	ss = malloc(sizeof(Sac)); 
	*ss = *s; 
	if(ss->path) 
		incref(ss->path); 
	return ss; 
} 
 
1999/0609    
static SacPath * 
1999/0608    
sacpathalloc(SacPath *p, vlong blocks, int entry) 
{ 
	SacPath *pp = malloc(sizeof(SacPath)); 
	pp->ref = 1; 
	pp->blocks = blocks; 
	pp->entry = entry; 
	pp->up = p; 
	return pp; 
} 
 
static void 
sacpathfree(SacPath *p) 
{ 
	if(p == nil) 
		return; 
	if(decref(p) > 0) 
		return; 
	sacpathfree(p->up); 
	free(p); 
} 
 
 
1999/0609    
static void 
1999/0608    
sacfree(Sac *s) 
{ 
	sacpathfree(s->path); 
	free(s); 
} 
 
1999/0609    
static void 
sacdir(Chan *c, SacDir *s, char *buf) 
1999/0608    
{ 
	Dir dir; 
 
	memmove(dir.name, s->name, NAMELEN); 
	dir.qid = (Qid){getl(s->qid), 0}; 
	dir.mode = getl(s->mode); 
	dir.length = getv(s->length); 
	if(dir.mode &CHDIR) 
		dir.length *= DIRLEN; 
	strcpy(dir.uid, s->uid); 
	strcpy(dir.gid, s->gid); 
	dir.atime = getl(s->atime); 
	dir.mtime = getl(s->mtime); 
1999/0609    
	dir.type = devtab[c->type]->dc; 
	dir.dev = c->dev; 
1999/0608    
	convD2M(&dir, buf); 
} 
 
1999/0609    
static void 
1999/0608    
loadblock(void *buf, uchar *offset, int blocksize) 
{ 
	vlong block, n; 
 
	block = getv(offset); 
	if(block < 0) { 
		block = -block; 
		n = getv(offset+8); 
		if(n < 0) 
			n = -n; 
		n -= block; 
		if(unsac(buf, data+block, blocksize, n)<0) 
			panic("unsac failed!"); 
	} else { 
		memmove(buf, data+block, blocksize); 
	} 
} 
 
1999/0609    
static Sac* 
1999/0608    
sacparent(Sac *s) 
{ 
	uchar *blocks; 
	SacDir *buf; 
	int per, i; 
	SacPath *p; 
 
	p = s->path; 
	if(p == nil || p->up == nil) { 
1999/0609    
		sacpathfree(p); 
1999/0608    
		*s = root; 
		return s; 
	} 
	p = p->up; 
 
	blocks = data + p->blocks; 
	per = blocksize/sizeof(SacDir); 
	i = p->entry/per; 
	buf = malloc(per*sizeof(SacDir)); 
	loadblock(buf, blocks + i*8, per*sizeof(SacDir)); 
	s->SacDir = buf[p->entry-i*per]; 
	free(buf); 
	incref(p); 
1999/0609    
	sacpathfree(s->path); 
1999/0608    
	s->path = p; 
	return s; 
} 
 
1999/0609    
static int 
sacdirread(Chan *c, char *p, long off, long cnt) 
1999/0608    
{ 
	uchar *blocks; 
	SacDir *buf; 
	int iblock, per, i, j, ndir; 
1999/0609    
	Sac *s; 
1999/0608    
 
1999/0609    
	s = c->aux; 
1999/0608    
	blocks = data + getv(s->blocks); 
	per = blocksize/sizeof(SacDir); 
	ndir = getv(s->length); 
	off /= DIRLEN; 
	cnt /= DIRLEN; 
	if(off >= ndir) 
		return 0; 
	if(cnt > ndir-off) 
		cnt = ndir-off; 
	iblock = -1; 
	buf = malloc(per*sizeof(SacDir)); 
	for(i=off; i<off+cnt; i++) { 
		j = i/per; 
		if(j != iblock) { 
			loadblock(buf, blocks + j*8, per*sizeof(SacDir)); 
			iblock = j; 
		} 
		j *= per; 
1999/0609    
		sacdir(c, buf+i-j, p); 
1999/0608    
		p += DIRLEN; 
	} 
	free(buf); 
	return cnt*DIRLEN; 
} 
 
1999/0609    
static Sac* 
1999/0608    
saclookup(Sac *s, char *name) 
{ 
	int ndir; 
1999/0609    
	int i, j, k, per; 
1999/0608    
	uchar *blocks; 
	SacDir *buf; 
	int iblock; 
	SacDir *sd; 
	 
	if(strcmp(name, "..") == 0) 
		return sacparent(s); 
	blocks = data + getv(s->blocks); 
	per = blocksize/sizeof(SacDir); 
	ndir = getv(s->length); 
	buf = malloc(per*sizeof(SacDir)); 
	iblock = -1; 
 
1999/0609    
	// linear search 
	for(i=0; i<ndir; i++) { 
1999/0608    
		j = i/per; 
		if(j != iblock) { 
			loadblock(buf, blocks + j*8, per*sizeof(SacDir)); 
			iblock = j; 
		} 
		j *= per; 
		sd = buf+i-j; 
		k = strcmp(name, sd->name); 
		if(k == 0) { 
1999/0609    
		s->path = sacpathalloc(s->path, getv(s->blocks), i); 
1999/0608    
			s->SacDir = *sd; 
			free(buf); 
1999/0609    
			return s; 
1999/0608    
		} 
	} 
1999/0609    
	free(buf); 
1999/0608    
	return 0; 
} 
 
1999/0609    
static ulong 
1999/0608    
getl(void *p) 
{ 
	uchar *a = p; 
 
	return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]; 
} 
 
1999/0609    
static vlong 
1999/0608    
getv(void *p) 
{ 
	uchar *a = p; 
	ulong l0, l1; 
	vlong v; 
 
	l0 = (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]; 
	a += 4; 
	l1 = (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]; 
	 
	v = l0; 
	v <<= 32; 
	v |= l1; 
	return v; 
} 
 
Dev sacdevtab = { 
	'C', 
	"sac", 
 
	devreset, 
	sacinit, 
	sacattach, 
	sacclone, 
	sacwalk, 
	sacstat, 
	sacopen, 
	devcreate, 
	sacclose, 
	sacread, 
	devbread, 
	sacwrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)