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

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

1999/0608/sys/src/9/mpc/devsac.c:4,91999/0609/sys/src/9/mpc/devsac.c:4,10 (short | long)
1999/0608    
#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 
1999/0608/sys/src/9/mpc/devsac.c:73,1041999/0609/sys/src/9/mpc/devsac.c:74,104
1999/0608    
	Powner =	64, 
}; 
 
uchar *data = SACMEM; 
int blocksize; 
Sac root; 
1999/0609    
static uchar *data = SACMEM; 
static int blocksize; 
static Sac root; 
1999/0608    
 
void	sacstat(SacDir*, char*); 
void	io(void); 
void	usage(void); 
ulong	getl(void *p); 
vlong	getv(void *p); 
void	init(char*); 
Sac	*saccpy(Sac *s); 
Sac *saclookup(Sac *s, char *name); 
int sacdirread(Sac *s, char *p, long off, long cnt); 
void loadblock(void *buf, uchar *offset, int blocksize); 
void sacfree(Sac*); 
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    
 
void 
devinit(void) 
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) { 
print("devsac: bad magic"); 
1999/0609    
print("devsac: bad magic\n"); 
1999/0608    
		return; 
	} 
	blocksize = getl(hdr->blocksize); 
1999/0609    
print("blocksize = %d\n", blocksize); 
1999/0608    
	root.SacDir = *(SacDir*)(data + sizeof(SacHeader)); 
} 
 
1999/0608/sys/src/9/mpc/devsac.c:123,1291999/0609/sys/src/9/mpc/devsac.c:123,129
1999/0608    
	return c; 
} 
 
Chan* 
1999/0609    
static Chan* 
1999/0608    
sacclone(Chan *c, Chan *nc) 
{ 
	nc = devclone(c, nc); 
1999/0608/sys/src/9/mpc/devsac.c:131,1451999/0609/sys/src/9/mpc/devsac.c:131,147
1999/0608    
	return nc; 
} 
 
int 
devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen) 
1999/0609    
static int 
sacwalk(Chan *c, char *name) 
1999/0608    
{ 
	Sac *sac; 
1999/0609    
	Path *op; 
1999/0608    
 
1999/0609    
print("sacwalk\n"); 
1999/0608    
	isdir(c); 
	sac = c->aux; 
	if(strcmp(name, ".") == 0) 
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); 
1999/0608/sys/src/9/mpc/devsac.c:148,2351999/0609/sys/src/9/mpc/devsac.c:150,214
1999/0608    
	c->aux = sac; 
	c->qid = (Qid){getl(sac->qid), 0}; 
	op = c->path; 
1999/0609    
print("op=%ux name = %s\n", op, name); 
1999/0608    
	c->path = ptenter(&syspt, op, name); 
	decref(op); 
	return 1; 
} 
 
char * 
ropen(Fid *f) 
1999/0609    
static Chan* 
sacopen(Chan *c, int omode) 
1999/0608    
{ 
	int mode, trunc; 
1999/0609    
	ulong t, mode; 
	Sac *sac; 
	static int access[] = { 0400, 0200, 0600, 0100 }; 
1999/0608    
 
	if(f->open) 
		return Eisopen; 
	if(f->busy == 0) 
		return Enotexist; 
	mode = rhdr.mode; 
	if(f->qid.path & CHDIR){ 
		if(mode != OREAD) 
			return Eperm; 
		thdr.qid = f->qid; 
		return 0; 
	} 
	if(mode & ORCLOSE) 
		return Erdonly; 
	trunc = mode & OTRUNC; 
	mode &= OPERM; 
	if(mode==OWRITE || mode==ORDWR || trunc) 
		return Erdonly; 
	if(mode==OREAD) 
		if(!perm(f, f->sac, Pread)) 
			return Eperm; 
	if(mode==OEXEC) 
		if(!perm(f, f->sac, Pexec)) 
			return Eperm; 
	thdr.qid = f->qid; 
	f->open = 1; 
	return 0; 
} 
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    
 
char * 
rcreate(Fid *f) 
{ 
	if(f->open) 
		return Eisopen; 
	if(f->busy == 0) 
		return Enotexist; 
	return Erdonly; 
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    
} 
 
char* 
rread(Fid *f) 
1999/0609    
 
static long 
sacread(Chan *c, void *a, long n, vlong off) 
1999/0608    
{ 
	Sac *sac; 
	char *buf, *buf2; 
	long off; 
	int n, cnt, i, j; 
1999/0609    
	int nn, cnt, i, j; 
1999/0608    
	uchar *blocks; 
	vlong length; 
 
	if(f->busy == 0) 
		return Enotexist; 
	sac = f->sac; 
	thdr.count = 0; 
	off = rhdr.offset; 
	buf = thdr.data; 
	cnt = rhdr.count; 
	if(f->qid.path & CHDIR){ 
		cnt = (rhdr.count/DIRLEN)*DIRLEN; 
1999/0609    
	buf = a; 
	cnt = n; 
	if(c->qid.path & CHDIR){ 
		cnt = (cnt/DIRLEN)*DIRLEN; 
1999/0608    
		if(off%DIRLEN) 
			return "i/o error"; 
		thdr.count = sacdirread(sac, buf, off, cnt); 
		return 0; 
1999/0609    
			error("i/o error"); 
		return sacdirread(c, buf, off, cnt); 
1999/0608    
	} 
1999/0609    
print("data read\n"); 
	sac = c->aux; 
1999/0608    
	length = getv(sac->length); 
	if(off >= length) { 
		rhdr.count = 0; 
1999/0609    
	if(off >= length) 
1999/0608    
		return 0; 
	} 
	if(cnt > length-off) 
		cnt = length-off; 
	thdr.count = cnt; 
	if(cnt == 0) 
		return 0; 
1999/0609    
	n = cnt; 
1999/0608    
	blocks = data + getv(sac->blocks); 
	buf2 = malloc(blocksize); 
	while(cnt > 0) { 
1999/0608/sys/src/9/mpc/devsac.c:236,3031999/0609/sys/src/9/mpc/devsac.c:215,261
1999/0608    
		i = off/blocksize; 
		loadblock(buf2, blocks+i*8, blocksize); 
		j = off-i*blocksize; 
		n = blocksize-j; 
		if(n > cnt) 
			n = cnt; 
		memmove(buf, buf2+j, n); 
		cnt -= n; 
		off += n; 
1999/0609    
		nn = blocksize-j; 
		if(nn > cnt) 
			nn = cnt; 
		memmove(buf, buf2+j, nn); 
		cnt -= nn; 
		off += nn; 
1999/0608    
	} 
	free(buf2); 
	return 0; 
1999/0609    
	return n; 
1999/0608    
} 
 
char* 
sacwrite(Fid *f) 
1999/0609    
static long 
sacwrite(Chan *, void *, long, vlong) 
1999/0608    
{ 
	if(f->busy == 0) 
		return Enotexist; 
	return Erdonly; 
} 
                 
char * 
rclunk(Fid *f) 
{ 
	f->busy = 0; 
	f->open = 0; 
	free(f->user); 
	sacfree(f->sac); 
1999/0609    
	error(Eperm); 
1999/0608    
	return 0; 
} 
 
char * 
rremove(Fid *f) 
1999/0609    
static void 
sacclose(Chan* c) 
1999/0608    
{ 
	f->busy = 0; 
	f->open = 0; 
	free(f->user); 
	sacfree(f->sac); 
	return Erdonly; 
1999/0609    
	Sac *sac = c->aux; 
print("close %ux\n", sac); 
	c->aux = nil; 
	sacfree(sac); 
1999/0608    
} 
 
char * 
rstat(Fid *f) 
{ 
	if(f->busy == 0) 
		return Enotexist; 
	sacstat(f->sac, thdr.stat); 
	return 0; 
} 
 
char * 
rwstat(Fid *f) 
1999/0609    
static void 
sacstat(Chan *c, char *db) 
1999/0608    
{ 
	if(f->busy == 0) 
		return Enotexist; 
	return Erdonly; 
1999/0609    
	sacdir(c, c->aux, db); 
1999/0608    
} 
 
Sac* 
1999/0609    
static Sac* 
1999/0608    
saccpy(Sac *s) 
{ 
	Sac *ss; 
	 
	ss = malloc(sizeof(Sac)); 
1999/0609    
print("saccpy = %ux\n", ss); 
1999/0608    
	*ss = *s; 
	if(ss->path) 
		incref(ss->path); 
1999/0608/sys/src/9/mpc/devsac.c:304,3101999/0609/sys/src/9/mpc/devsac.c:262,268
1999/0608    
	return ss; 
} 
 
SacPath * 
1999/0609    
static SacPath * 
1999/0608    
sacpathalloc(SacPath *p, vlong blocks, int entry) 
{ 
	SacPath *pp = malloc(sizeof(SacPath)); 
1999/0608/sys/src/9/mpc/devsac.c:327,3331999/0609/sys/src/9/mpc/devsac.c:285,291
1999/0608    
} 
 
 
void 
1999/0609    
static void 
1999/0608    
sacfree(Sac *s) 
{ 
	sacpathfree(s->path); 
1999/0608/sys/src/9/mpc/devsac.c:334,3411999/0609/sys/src/9/mpc/devsac.c:292,299
1999/0608    
	free(s); 
} 
 
void 
sacstat(SacDir *s, char *buf) 
1999/0609    
static void 
sacdir(Chan *c, SacDir *s, char *buf) 
1999/0608    
{ 
	Dir dir; 
 
1999/0608/sys/src/9/mpc/devsac.c:349,3581999/0609/sys/src/9/mpc/devsac.c:307,318
1999/0608    
	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); 
} 
 
void 
1999/0609    
static void 
1999/0608    
loadblock(void *buf, uchar *offset, int blocksize) 
{ 
	vlong block, n; 
1999/0608/sys/src/9/mpc/devsac.c:364,3781999/0609/sys/src/9/mpc/devsac.c:324,339
1999/0608    
		if(n < 0) 
			n = -n; 
		n -= block; 
//fprint(2, "blocksize = %d, block = %lld n = %lld\n", blocksize, block, n); 
1999/0609    
print("blocksize = %d, block = %lld n = %lld\n", blocksize, block, n); 
1999/0608    
		if(unsac(buf, data+block, blocksize, n)<0) 
			panic("unsac failed!"); 
	} else { 
1999/0609    
print("memmove: blocksize = %d\n", blocksize); 
1999/0608    
		memmove(buf, data+block, blocksize); 
	} 
} 
 
Sac* 
1999/0609    
static Sac* 
1999/0608    
sacparent(Sac *s) 
{ 
	uchar *blocks; 
1999/0608/sys/src/9/mpc/devsac.c:382,3941999/0609/sys/src/9/mpc/devsac.c:343,355
1999/0608    
 
	p = s->path; 
	if(p == nil || p->up == nil) { 
		pathfree(p); 
1999/0609    
		sacpathfree(p); 
1999/0608    
		*s = root; 
		return s; 
	} 
	p = p->up; 
 
//fprint(2, "sacparent = %lld %d\n", p->blocks, p->entry); 
1999/0609    
print("sacparent = %lld %d\n", p->blocks, p->entry); 
1999/0608    
	blocks = data + p->blocks; 
	per = blocksize/sizeof(SacDir); 
	i = p->entry/per; 
1999/0608/sys/src/9/mpc/devsac.c:395,4151999/0609/sys/src/9/mpc/devsac.c:356,379
1999/0608    
	buf = malloc(per*sizeof(SacDir)); 
	loadblock(buf, blocks + i*8, per*sizeof(SacDir)); 
	s->SacDir = buf[p->entry-i*per]; 
//fprint(2, "sacparent = %s\n", s->name); 
1999/0609    
print("sacparent = %s\n", s->name); 
1999/0608    
	free(buf); 
	incref(p); 
	pathfree(s->path); 
1999/0609    
	sacpathfree(s->path); 
1999/0608    
	s->path = p; 
	return s; 
} 
 
int 
sacdirread(Sac *s, char *p, long off, long cnt) 
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    
print("sacdirread %d %d\n", off, cnt); 
	s = c->aux; 
1999/0608    
	blocks = data + getv(s->blocks); 
	per = blocksize/sizeof(SacDir); 
	ndir = getv(s->length); 
1999/0608/sys/src/9/mpc/devsac.c:428,4341999/0609/sys/src/9/mpc/devsac.c:392,398
1999/0608    
			iblock = j; 
		} 
		j *= per; 
		sacstat(buf+i-j, p); 
1999/0609    
		sacdir(c, buf+i-j, p); 
1999/0608    
		p += DIRLEN; 
	} 
	free(buf); 
1999/0608/sys/src/9/mpc/devsac.c:435,4451999/0609/sys/src/9/mpc/devsac.c:399,409
1999/0608    
	return cnt*DIRLEN; 
} 
 
Sac* 
1999/0609    
static Sac* 
1999/0608    
saclookup(Sac *s, char *name) 
{ 
	int ndir; 
	int top, bot, i, j, k, per; 
1999/0609    
	int i, j, k, per; 
1999/0608    
	uchar *blocks; 
	SacDir *buf; 
	int iblock; 
1999/0608/sys/src/9/mpc/devsac.c:453,4881999/0609/sys/src/9/mpc/devsac.c:417,424
1999/0608    
	buf = malloc(per*sizeof(SacDir)); 
	iblock = -1; 
 
	if(1) { 
		// linear search 
		for(i=0; i<ndir; i++) { 
			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) { 
//print("walk %s %lld %d\n", name, getv(s->blocks), i); 
				s->path = sacpathalloc(s->path, getv(s->blocks), i); 
				s->SacDir = *sd; 
				free(buf); 
				return s; 
			} 
		} 
		free(buf); 
		return 0; 
	} 
                 
	// binary search 
	top = ndir; 
	bot = 0; 
	while(bot != top){ 
if(bot>top) 
sysfatal("binary serach failed: %d %d\n", bot, top); 
		i = (bot+top)>>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)); 
1999/0608/sys/src/9/mpc/devsac.c:492,6061999/0609/sys/src/9/mpc/devsac.c:428,445
1999/0608    
		sd = buf+i-j; 
		k = strcmp(name, sd->name); 
		if(k == 0) { 
			s->path = sacpathalloc(s->path, getv(s->blocks), i); 
1999/0609    
print("walk %s %lld %d\n", name, getv(s->blocks), i); 
		s->path = sacpathalloc(s->path, getv(s->blocks), i); 
1999/0608    
			s->SacDir = *sd; 
			free(buf); 
1999/0609    
			return s; 
1999/0608    
		} 
		if(k < 0) { 
			top = i; 
			sd = buf; 
			if(strcmp(name, sd->name) < 0) 
				top = j; 
		} else { 
			bot = i+1; 
			if(ndir-j < per) 
				i = ndir-j; 
			else 
				i = per; 
			sd = buf+i-1; 
			if(strcmp(name, sd->name) > 0) 
				bot = j+i; 
		} 
	} 
1999/0609    
	free(buf); 
1999/0608    
	return 0; 
} 
 
Fid * 
newfid(int fid) 
{ 
	Fid *f, *ff; 
                 
	ff = 0; 
	for(f = fids; f; f = f->next) 
		if(f->fid == fid) 
			return f; 
		else if(!ff && !f->busy) 
			ff = f; 
	if(ff){ 
		ff->fid = fid; 
		return ff; 
	} 
	f = malloc(sizeof *f); 
//fprint(2, "newfid\n"); 
	memset(f, 0 , sizeof(Fid)); 
	f->fid = fid; 
	f->next = fids; 
	fids = f; 
	return f; 
} 
                 
void 
io(void) 
{ 
	char *err; 
	int n; 
                 
	for(;;){ 
		/* 
		 * reading from a pipe or a network device 
		 * will give an error after a few eof reads 
		 * however, we cannot tell the difference 
		 * between a zero-length read and an interrupt 
		 * on the processes writing to us, 
		 * so we wait for the error 
		 */ 
		n = read(mfd[0], mdata, sizeof mdata); 
		if(n == 0) 
			continue; 
		if(n < 0) 
			error("mount read"); 
		if(convM2S(mdata, &rhdr, n) == 0) 
			continue; 
                 
		if(debug) 
			fprint(2, "sacfs:<-%F\n", &rhdr); 
                 
		thdr.data = mdata + MAXMSG; 
		if(!fcalls[rhdr.type]) 
			err = "bad fcall type"; 
		else 
			err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); 
		if(err){ 
			thdr.type = Rerror; 
			strncpy(thdr.ename, err, ERRLEN); 
		}else{ 
			thdr.type = rhdr.type + 1; 
			thdr.fid = rhdr.fid; 
		} 
		thdr.tag = rhdr.tag; 
		if(debug) 
			fprint(2, "ramfs:->%F\n", &thdr);/**/ 
		n = convS2M(&thdr, mdata); 
		if(write(mfd[1], mdata, n) != n) 
			error("mount write"); 
	} 
} 
                 
int 
perm(Fid *f, Sac *s, int p) 
{ 
	ulong perm = getl(s->mode); 
	if((p*Pother) & perm) 
		return 1; 
	if(strcmp(f->user, s->gid)==0 && ((p*Pgroup) & perm)) 
		return 1; 
	if(strcmp(f->user, s->uid)==0 && ((p*Powner) & perm)) 
		return 1; 
	return 0; 
} 
                 
                 
ulong 
1999/0609    
static ulong 
1999/0608    
getl(void *p) 
{ 
	uchar *a = p; 
1999/0608/sys/src/9/mpc/devsac.c:608,6141999/0609/sys/src/9/mpc/devsac.c:447,453
1999/0608    
	return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]; 
} 
 
vlong 
1999/0609    
static vlong 
1999/0608    
getv(void *p) 
{ 
	uchar *a = p; 
1999/0609/sys/src/9/mpc/devsac.c:98,1041999/0610/sys/src/9/mpc/devsac.c:98,103 (short | long)
1999/0608    
		return; 
	} 
	blocksize = getl(hdr->blocksize); 
1999/0609    
print("blocksize = %d\n", blocksize); 
1999/0608    
	root.SacDir = *(SacDir*)(data + sizeof(SacHeader)); 
} 
 
1999/0609/sys/src/9/mpc/devsac.c:137,1431999/0610/sys/src/9/mpc/devsac.c:136,143
1999/0608    
	Sac *sac; 
1999/0609    
	Path *op; 
1999/0608    
 
1999/0609    
print("sacwalk\n"); 
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/sys/src/9/mpc/devsac.c:150,1561999/0610/sys/src/9/mpc/devsac.c:150,155
1999/0608    
	c->aux = sac; 
	c->qid = (Qid){getl(sac->qid), 0}; 
	op = c->path; 
1999/0609    
print("op=%ux name = %s\n", op, name); 
1999/0608    
	c->path = ptenter(&syspt, op, name); 
	decref(op); 
	return 1; 
1999/0609/sys/src/9/mpc/devsac.c:199,2061999/0610/sys/src/9/mpc/devsac.c:198,205
1999/0609    
			error("i/o error"); 
		return sacdirread(c, buf, off, cnt); 
1999/0608    
	} 
1999/0609    
print("data read\n"); 
	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; 
1999/0609/sys/src/9/mpc/devsac.c:221,2261999/0610/sys/src/9/mpc/devsac.c:220,226
1999/0609    
		memmove(buf, buf2+j, nn); 
		cnt -= nn; 
		off += nn; 
1999/0610    
		buf += nn; 
1999/0608    
	} 
	free(buf2); 
1999/0609    
	return n; 
1999/0609/sys/src/9/mpc/devsac.c:237,2431999/0610/sys/src/9/mpc/devsac.c:237,242
1999/0609    
sacclose(Chan* c) 
1999/0608    
{ 
1999/0609    
	Sac *sac = c->aux; 
print("close %ux\n", sac); 
	c->aux = nil; 
	sacfree(sac); 
1999/0608    
} 
1999/0609/sys/src/9/mpc/devsac.c:255,2611999/0610/sys/src/9/mpc/devsac.c:254,259
1999/0608    
	Sac *ss; 
	 
	ss = malloc(sizeof(Sac)); 
1999/0609    
print("saccpy = %ux\n", ss); 
1999/0608    
	*ss = *s; 
	if(ss->path) 
		incref(ss->path); 
1999/0609/sys/src/9/mpc/devsac.c:324,3341999/0610/sys/src/9/mpc/devsac.c:322,330
1999/0608    
		if(n < 0) 
			n = -n; 
		n -= block; 
1999/0609    
print("blocksize = %d, block = %lld n = %lld\n", blocksize, block, n); 
1999/0608    
		if(unsac(buf, data+block, blocksize, n)<0) 
			panic("unsac failed!"); 
	} else { 
1999/0609    
print("memmove: blocksize = %d\n", blocksize); 
1999/0608    
		memmove(buf, data+block, blocksize); 
	} 
} 
1999/0609/sys/src/9/mpc/devsac.c:349,3551999/0610/sys/src/9/mpc/devsac.c:345,350
1999/0608    
	} 
	p = p->up; 
 
1999/0609    
print("sacparent = %lld %d\n", p->blocks, p->entry); 
1999/0608    
	blocks = data + p->blocks; 
	per = blocksize/sizeof(SacDir); 
	i = p->entry/per; 
1999/0609/sys/src/9/mpc/devsac.c:356,3621999/0610/sys/src/9/mpc/devsac.c:351,356
1999/0608    
	buf = malloc(per*sizeof(SacDir)); 
	loadblock(buf, blocks + i*8, per*sizeof(SacDir)); 
	s->SacDir = buf[p->entry-i*per]; 
1999/0609    
print("sacparent = %s\n", s->name); 
1999/0608    
	free(buf); 
	incref(p); 
1999/0609    
	sacpathfree(s->path); 
1999/0609/sys/src/9/mpc/devsac.c:372,3781999/0610/sys/src/9/mpc/devsac.c:366,371
1999/0608    
	int iblock, per, i, j, ndir; 
1999/0609    
	Sac *s; 
1999/0608    
 
1999/0609    
print("sacdirread %d %d\n", off, cnt); 
	s = c->aux; 
1999/0608    
	blocks = data + getv(s->blocks); 
	per = blocksize/sizeof(SacDir); 
1999/0609/sys/src/9/mpc/devsac.c:428,4341999/0610/sys/src/9/mpc/devsac.c:421,426
1999/0608    
		sd = buf+i-j; 
		k = strcmp(name, sd->name); 
		if(k == 0) { 
1999/0609    
print("walk %s %lld %d\n", name, getv(s->blocks), i); 
		s->path = sacpathalloc(s->path, getv(s->blocks), i); 
1999/0608    
			s->SacDir = *sd; 
			free(buf); 
1999/0610/sys/src/9/mpc/devsac.c:134,1401999/0727/sys/src/9/mpc/devsac.c:134,139 (short | long)
1999/0609    
sacwalk(Chan *c, char *name) 
1999/0608    
{ 
	Sac *sac; 
1999/0609    
	Path *op; 
1999/0608    
 
1999/0610    
//print("walk %s\n", name); 
 
1999/0610/sys/src/9/mpc/devsac.c:149,1571999/0727/sys/src/9/mpc/devsac.c:148,153
1999/0608    
	} 
	c->aux = sac; 
	c->qid = (Qid){getl(sac->qid), 0}; 
	op = c->path; 
	c->path = ptenter(&syspt, op, name); 
	decref(op); 
	return 1; 
} 
 
1999/0727/sys/src/9/mpc/devsac.c:17,221999/0806/sys/src/9/mpc/devsac.c:17,23 (short | long)
1999/0608    
{ 
	OPERM	= 0x3,		/* mask of all permission types in open mode */ 
	Nram	= 512, 
1999/0806    
	CacheSize = 20, 
1999/0608    
}; 
 
typedef struct SacPath SacPath; 
1999/0727/sys/src/9/mpc/devsac.c:23,281999/0806/sys/src/9/mpc/devsac.c:24,30
1999/0608    
typedef struct Sac Sac; 
typedef struct SacHeader SacHeader; 
typedef struct SacDir SacDir; 
1999/0806    
typedef struct Cache Cache; 
1999/0608    
 
enum { 
	Magic = 0x5acf5, 
1999/0727/sys/src/9/mpc/devsac.c:64,691999/0806/sys/src/9/mpc/devsac.c:66,78
1999/0608    
	int entry; 
}; 
 
1999/0806    
struct Cache 
{ 
	long block; 
	ulong age; 
	uchar *data; 
}; 
 
1999/0608    
enum 
{ 
	Pexec =		1, 
1999/0727/sys/src/9/mpc/devsac.c:77,821999/0806/sys/src/9/mpc/devsac.c:86,93
1999/0609    
static uchar *data = SACMEM; 
static int blocksize; 
static Sac root; 
1999/0806    
static Cache cache[CacheSize]; 
static ulong cacheage; 
1999/0608    
 
1999/0609    
static void	sacdir(Chan *, SacDir*, char*); 
static ulong	getl(void *p); 
1999/0727/sys/src/9/mpc/devsac.c:91,961999/0806/sys/src/9/mpc/devsac.c:102,110
1999/0609    
sacinit(void) 
1999/0608    
{ 
	SacHeader *hdr; 
1999/0806    
	uchar *p; 
	int i; 
 
1999/0609    
print("sacinit\n"); 
1999/0608    
	hdr = (SacHeader*)data; 
	if(getl(hdr->magic) != Magic) { 
1999/0727/sys/src/9/mpc/devsac.c:99,1041999/0806/sys/src/9/mpc/devsac.c:113,125
1999/0608    
	} 
	blocksize = getl(hdr->blocksize); 
	root.SacDir = *(SacDir*)(data + sizeof(SacHeader)); 
1999/0806    
	p = malloc(CacheSize*blocksize); 
	if(p == nil) 
		error("allocating cache"); 
	for(i=0; i<CacheSize; i++) { 
		cache[i].data = p; 
		p += blocksize; 
	} 
1999/0608    
} 
 
static Chan* 
1999/0727/sys/src/9/mpc/devsac.c:310,3191999/0806/sys/src/9/mpc/devsac.c:331,362
1999/0608    
loadblock(void *buf, uchar *offset, int blocksize) 
{ 
	vlong block, n; 
1999/0806    
	ulong age; 
	int i, j; 
1999/0608    
 
	block = getv(offset); 
	if(block < 0) { 
		block = -block; 
1999/0806    
		cacheage++; 
		// age has wraped 
		if(cacheage == 0) { 
			for(i=0; i<CacheSize; i++) 
				cache[i].age = 0; 
		} 
		j = 0; 
		age = cache[0].age; 
		for(i=0; i<CacheSize; i++) { 
			if(cache[i].age < age) { 
				age = cache[i].age; 
				j = i; 
			} 
			if(cache[i].block != block) 
				continue; 
			memmove(buf, cache[i].data, blocksize); 
			cache[i].age = cacheage; 
			return; 
		} 
 
1999/0608    
		n = getv(offset+8); 
		if(n < 0) 
			n = -n; 
1999/0727/sys/src/9/mpc/devsac.c:320,3251999/0806/sys/src/9/mpc/devsac.c:363,371
1999/0608    
		n -= block; 
		if(unsac(buf, data+block, blocksize, n)<0) 
			panic("unsac failed!"); 
1999/0806    
		memmove(cache[j].data, buf, blocksize); 
		cache[j].age = cacheage; 
		cache[j].block = block; 
1999/0608    
	} else { 
		memmove(buf, data+block, blocksize); 
	} 
1999/0806/sys/src/9/mpc/devsac.c:18,231999/0807/sys/src/9/mpc/devsac.c:18,24 (short | long)
1999/0608    
	OPERM	= 0x3,		/* mask of all permission types in open mode */ 
	Nram	= 512, 
1999/0806    
	CacheSize = 20, 
1999/0807    
	OffsetSize = 4,		/* size in bytes of an offset */ 
1999/0608    
}; 
 
typedef struct SacPath SacPath; 
1999/0806/sys/src/9/mpc/devsac.c:62,691999/0807/sys/src/9/mpc/devsac.c:63,71
1999/0608    
{ 
	Ref; 
	SacPath *up; 
	vlong blocks; 
1999/0807    
	long blocks; 
1999/0608    
	int entry; 
1999/0807    
	int nentry; 
1999/0608    
}; 
 
1999/0806    
struct Cache 
1999/0806/sys/src/9/mpc/devsac.c:91,971999/0807/sys/src/9/mpc/devsac.c:93,98
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); 
1999/0806/sys/src/9/mpc/devsac.c:199,2111999/0807/sys/src/9/mpc/devsac.c:200,213
1999/0608    
 
1999/0609    
 
static long 
sacread(Chan *c, void *a, long n, vlong off) 
1999/0807    
sacread(Chan *c, void *a, long n, vlong voff) 
1999/0608    
{ 
	Sac *sac; 
	char *buf, *buf2; 
1999/0609    
	int nn, cnt, i, j; 
1999/0608    
	uchar *blocks; 
	vlong length; 
1999/0807    
	long length; 
	long off = voff; 
1999/0608    
 
1999/0609    
	buf = a; 
	cnt = n; 
1999/0806/sys/src/9/mpc/devsac.c:216,2231999/0807/sys/src/9/mpc/devsac.c:218,224
1999/0609    
		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/0807    
	length = getl(sac->length); 
1999/0609    
	if(off >= length) 
1999/0608    
		return 0; 
	if(cnt > length-off) 
1999/0806/sys/src/9/mpc/devsac.c:225,2371999/0807/sys/src/9/mpc/devsac.c:226,241
1999/0608    
	if(cnt == 0) 
		return 0; 
1999/0609    
	n = cnt; 
1999/0608    
	blocks = data + getv(sac->blocks); 
1999/0807    
	blocks = data + getl(sac->blocks); 
1999/0608    
	buf2 = malloc(blocksize); 
	while(cnt > 0) { 
		i = off/blocksize; 
		loadblock(buf2, blocks+i*8, blocksize); 
1999/0807    
		nn = blocksize; 
		if(nn > length-i*blocksize) 
			nn = length-i*blocksize; 
		loadblock(buf2, blocks+i*OffsetSize, nn); 
1999/0608    
		j = off-i*blocksize; 
1999/0609    
		nn = blocksize-j; 
1999/0807    
		nn -= j; 
1999/0609    
		if(nn > cnt) 
			nn = cnt; 
		memmove(buf, buf2+j, nn); 
1999/0806/sys/src/9/mpc/devsac.c:278,2891999/0807/sys/src/9/mpc/devsac.c:282,294
1999/0608    
} 
 
1999/0609    
static SacPath * 
1999/0608    
sacpathalloc(SacPath *p, vlong blocks, int entry) 
1999/0807    
sacpathalloc(SacPath *p, long blocks, int entry, int nentry) 
1999/0608    
{ 
	SacPath *pp = malloc(sizeof(SacPath)); 
	pp->ref = 1; 
	pp->blocks = blocks; 
	pp->entry = entry; 
1999/0807    
	pp->nentry = nentry; 
1999/0608    
	pp->up = p; 
	return pp; 
} 
1999/0806/sys/src/9/mpc/devsac.c:315,3251999/0807/sys/src/9/mpc/devsac.c:320,330
1999/0608    
	memmove(dir.name, s->name, NAMELEN); 
	dir.qid = (Qid){getl(s->qid), 0}; 
	dir.mode = getl(s->mode); 
	dir.length = getv(s->length); 
1999/0807    
	dir.length = getl(s->length); 
1999/0608    
	if(dir.mode &CHDIR) 
		dir.length *= DIRLEN; 
	strcpy(dir.uid, s->uid); 
	strcpy(dir.gid, s->gid); 
1999/0807    
	memmove(dir.uid, s->uid, NAMELEN); 
	memmove(dir.gid, s->gid, NAMELEN); 
1999/0608    
	dir.atime = getl(s->atime); 
	dir.mtime = getl(s->mtime); 
1999/0609    
	dir.type = devtab[c->type]->dc; 
1999/0806/sys/src/9/mpc/devsac.c:330,3401999/0807/sys/src/9/mpc/devsac.c:335,345
1999/0609    
static void 
1999/0608    
loadblock(void *buf, uchar *offset, int blocksize) 
{ 
	vlong block, n; 
1999/0807    
	long block, n; 
1999/0806    
	ulong age; 
	int i, j; 
1999/0608    
 
	block = getv(offset); 
1999/0807    
	block = getl(offset); 
1999/0608    
	if(block < 0) { 
		block = -block; 
1999/0806    
		cacheage++; 
1999/0806/sys/src/9/mpc/devsac.c:357,3631999/0807/sys/src/9/mpc/devsac.c:362,368
1999/0806    
			return; 
		} 
 
1999/0608    
		n = getv(offset+8); 
1999/0807    
		n = getl(offset+OffsetSize); 
1999/0608    
		if(n < 0) 
			n = -n; 
		n -= block; 
1999/0806/sys/src/9/mpc/devsac.c:376,3821999/0807/sys/src/9/mpc/devsac.c:381,387
1999/0608    
{ 
	uchar *blocks; 
	SacDir *buf; 
	int per, i; 
1999/0807    
	int per, i, n; 
1999/0608    
	SacPath *p; 
 
	p = s->path; 
1999/0806/sys/src/9/mpc/devsac.c:390,3971999/0807/sys/src/9/mpc/devsac.c:395,405
1999/0608    
	blocks = data + p->blocks; 
	per = blocksize/sizeof(SacDir); 
	i = p->entry/per; 
1999/0807    
	n = per; 
	if(n > p->nentry-i*per) 
		n = p->nentry-i*per; 
1999/0608    
	buf = malloc(per*sizeof(SacDir)); 
	loadblock(buf, blocks + i*8, per*sizeof(SacDir)); 
1999/0807    
	loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir)); 
1999/0608    
	s->SacDir = buf[p->entry-i*per]; 
	free(buf); 
	incref(p); 
1999/0806/sys/src/9/mpc/devsac.c:405,4171999/0807/sys/src/9/mpc/devsac.c:413,425
1999/0608    
{ 
	uchar *blocks; 
	SacDir *buf; 
	int iblock, per, i, j, ndir; 
1999/0807    
	int iblock, per, i, j, n, ndir; 
1999/0609    
	Sac *s; 
1999/0608    
 
1999/0609    
	s = c->aux; 
1999/0608    
	blocks = data + getv(s->blocks); 
1999/0807    
	blocks = data + getl(s->blocks); 
1999/0608    
	per = blocksize/sizeof(SacDir); 
	ndir = getv(s->length); 
1999/0807    
	ndir = getl(s->length); 
1999/0608    
	off /= DIRLEN; 
	cnt /= DIRLEN; 
	if(off >= ndir) 
1999/0806/sys/src/9/mpc/devsac.c:423,4291999/0807/sys/src/9/mpc/devsac.c:431,440
1999/0608    
	for(i=off; i<off+cnt; i++) { 
		j = i/per; 
		if(j != iblock) { 
			loadblock(buf, blocks + j*8, per*sizeof(SacDir)); 
1999/0807    
			n = per; 
			if(n > ndir-j*per) 
				n = ndir-j*per; 
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir)); 
1999/0608    
			iblock = j; 
		} 
		j *= per; 
1999/0806/sys/src/9/mpc/devsac.c:438,4441999/0807/sys/src/9/mpc/devsac.c:449,455
1999/0608    
saclookup(Sac *s, char *name) 
{ 
	int ndir; 
1999/0609    
	int i, j, k, per; 
1999/0807    
	int i, j, k, n, per; 
1999/0608    
	uchar *blocks; 
	SacDir *buf; 
	int iblock; 
1999/0806/sys/src/9/mpc/devsac.c:446,4541999/0807/sys/src/9/mpc/devsac.c:457,465
1999/0608    
	 
	if(strcmp(name, "..") == 0) 
		return sacparent(s); 
	blocks = data + getv(s->blocks); 
1999/0807    
	blocks = data + getl(s->blocks); 
1999/0608    
	per = blocksize/sizeof(SacDir); 
	ndir = getv(s->length); 
1999/0807    
	ndir = getl(s->length); 
1999/0608    
	buf = malloc(per*sizeof(SacDir)); 
	iblock = -1; 
 
1999/0806/sys/src/9/mpc/devsac.c:456,4621999/0807/sys/src/9/mpc/devsac.c:467,476
1999/0609    
	for(i=0; i<ndir; i++) { 
1999/0608    
		j = i/per; 
		if(j != iblock) { 
			loadblock(buf, blocks + j*8, per*sizeof(SacDir)); 
1999/0807    
			n = per; 
			if(n > ndir-j*per) 
				n = ndir-j*per; 
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir)); 
1999/0608    
			iblock = j; 
		} 
		j *= per; 
1999/0806/sys/src/9/mpc/devsac.c:463,4691999/0807/sys/src/9/mpc/devsac.c:477,483
1999/0608    
		sd = buf+i-j; 
		k = strcmp(name, sd->name); 
		if(k == 0) { 
1999/0609    
		s->path = sacpathalloc(s->path, getv(s->blocks), i); 
1999/0807    
		s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir); 
1999/0608    
			s->SacDir = *sd; 
			free(buf); 
1999/0609    
			return s; 
1999/0806/sys/src/9/mpc/devsac.c:479,5011999/0807/sys/src/9/mpc/devsac.c:493,498
1999/0608    
	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 = { 
1999/0807/sys/src/9/mpc/devsac.c:162,1671999/1231/sys/src/9/mpc/devsac.c:162,169 (short | long)
1999/0608    
	isdir(c); 
1999/0609    
	if(name[0]=='.' && name[1]==0) 
1999/0608    
		return 1; 
1999/1231    
	if(name[0]=='.' && name[1]=='.' && name[2]==0) 
		return 1; 
1999/0609    
	sac = c->aux; 
1999/0608    
	sac = saclookup(sac, name); 
	if(sac == nil) { 
1999/1231/sys/src/9/mpc/devsac.c:6,182000/0516/sys/src/9/mpc/devsac.c:6,11 (short | long)
1999/0608    
#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 */ 
1999/1231/sys/src/9/mpc/devsac.c:85,912000/0516/sys/src/9/mpc/devsac.c:78,85
1999/0608    
	Powner =	64, 
}; 
 
1999/0609    
static uchar *data = SACMEM; 
2000/0516    
static char *sacfs = "fs.sac"; 
static uchar *data; 
1999/0609    
static int blocksize; 
static Sac root; 
1999/0806    
static Cache cache[CacheSize]; 
1999/1231/sys/src/9/mpc/devsac.c:104,1122000/0516/sys/src/9/mpc/devsac.c:98,123
1999/0608    
{ 
	SacHeader *hdr; 
1999/0806    
	uchar *p; 
2000/0516    
	char *s; 
1999/0806    
	int i; 
 
1999/0609    
print("sacinit\n"); 
2000/0516    
	s = getconf("flash"); 
	if(s == nil) { 
		print("devsac: no flash file system\n"); 
		return; 
	} 
 
	p = (uchar*)strtoul(s, 0, 0); 
	if(p == 0) { 
		print("devsac: bad address for flash file system\n"); 
		return; 
	} 
	data = tarlookup(p, sacfs, &i); 
	if(data == 0) { 
		print("devsac: could not find file: %s\n", sacfs); 
		return; 
	} 
1999/0608    
	hdr = (SacHeader*)data; 
	if(getl(hdr->magic) != Magic) { 
1999/0609    
print("devsac: bad magic\n"); 
2000/0516/sys/src/9/mpc/devsac.c:173,1802000/1208/sys/src/9/mpc/devsac.c:173,178 (short | long)
1999/0608    
	isdir(c); 
1999/0609    
	if(name[0]=='.' && name[1]==0) 
1999/0608    
		return 1; 
1999/1231    
	if(name[0]=='.' && name[1]=='.' && name[2]==0) 
		return 1; 
1999/0609    
	sac = c->aux; 
1999/0608    
	sac = saclookup(sac, name); 
	if(sac == nil) { 
2000/1208/sys/src/9/mpc/devsac.c:1,5282001/0527/sys/src/9/mpc/devsac.c:0 (short | long)
Deleted.
rsc Mon Mar 7 10:28:39 2005
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    
                 
enum 
{ 
	OPERM	= 0x3,		/* mask of all permission types in open mode */ 
	Nram	= 512, 
1999/0806    
	CacheSize = 20, 
1999/0807    
	OffsetSize = 4,		/* size in bytes of an offset */ 
1999/0608    
}; 
                 
typedef struct SacPath SacPath; 
typedef struct Sac Sac; 
typedef struct SacHeader SacHeader; 
typedef struct SacDir SacDir; 
1999/0806    
typedef struct Cache Cache; 
1999/0608    
                 
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; 
1999/0807    
	long blocks; 
1999/0608    
	int entry; 
1999/0807    
	int nentry; 
1999/0608    
}; 
                 
1999/0806    
struct Cache 
{ 
	long block; 
	ulong age; 
	uchar *data; 
}; 
                 
1999/0608    
enum 
{ 
	Pexec =		1, 
	Pwrite = 	2, 
	Pread = 	4, 
	Pother = 	1, 
	Pgroup = 	8, 
	Powner =	64, 
}; 
                 
2000/0516    
static char *sacfs = "fs.sac"; 
static uchar *data; 
1999/0609    
static int blocksize; 
static Sac root; 
1999/0806    
static Cache cache[CacheSize]; 
static ulong cacheage; 
1999/0608    
                 
1999/0609    
static void	sacdir(Chan *, SacDir*, char*); 
static ulong	getl(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/0806    
	uchar *p; 
2000/0516    
	char *s; 
1999/0806    
	int i; 
                 
1999/0609    
print("sacinit\n"); 
2000/0516    
	s = getconf("flash"); 
	if(s == nil) { 
		print("devsac: no flash file system\n"); 
		return; 
	} 
                 
	p = (uchar*)strtoul(s, 0, 0); 
	if(p == 0) { 
		print("devsac: bad address for flash file system\n"); 
		return; 
	} 
	data = tarlookup(p, sacfs, &i); 
	if(data == 0) { 
		print("devsac: could not find file: %s\n", sacfs); 
		return; 
	} 
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)); 
1999/0806    
	p = malloc(CacheSize*blocksize); 
	if(p == nil) 
		error("allocating cache"); 
	for(i=0; i<CacheSize; i++) { 
		cache[i].data = p; 
		p += blocksize; 
	} 
1999/0608    
} 
                 
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 
1999/0807    
sacread(Chan *c, void *a, long n, vlong voff) 
1999/0608    
{ 
	Sac *sac; 
	char *buf, *buf2; 
1999/0609    
	int nn, cnt, i, j; 
1999/0608    
	uchar *blocks; 
1999/0807    
	long length; 
	long off = voff; 
1999/0608    
                 
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/0807    
	length = getl(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/0807    
	blocks = data + getl(sac->blocks); 
1999/0608    
	buf2 = malloc(blocksize); 
	while(cnt > 0) { 
		i = off/blocksize; 
1999/0807    
		nn = blocksize; 
		if(nn > length-i*blocksize) 
			nn = length-i*blocksize; 
		loadblock(buf2, blocks+i*OffsetSize, nn); 
1999/0608    
		j = off-i*blocksize; 
1999/0807    
		nn -= j; 
1999/0609    
		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/0807    
sacpathalloc(SacPath *p, long blocks, int entry, int nentry) 
1999/0608    
{ 
	SacPath *pp = malloc(sizeof(SacPath)); 
	pp->ref = 1; 
	pp->blocks = blocks; 
	pp->entry = entry; 
1999/0807    
	pp->nentry = nentry; 
1999/0608    
	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); 
1999/0807    
	dir.length = getl(s->length); 
1999/0608    
	if(dir.mode &CHDIR) 
		dir.length *= DIRLEN; 
1999/0807    
	memmove(dir.uid, s->uid, NAMELEN); 
	memmove(dir.gid, s->gid, NAMELEN); 
1999/0608    
	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) 
{ 
1999/0807    
	long block, n; 
1999/0806    
	ulong age; 
	int i, j; 
1999/0608    
                 
1999/0807    
	block = getl(offset); 
1999/0608    
	if(block < 0) { 
		block = -block; 
1999/0806    
		cacheage++; 
		// age has wraped 
		if(cacheage == 0) { 
			for(i=0; i<CacheSize; i++) 
				cache[i].age = 0; 
		} 
		j = 0; 
		age = cache[0].age; 
		for(i=0; i<CacheSize; i++) { 
			if(cache[i].age < age) { 
				age = cache[i].age; 
				j = i; 
			} 
			if(cache[i].block != block) 
				continue; 
			memmove(buf, cache[i].data, blocksize); 
			cache[i].age = cacheage; 
			return; 
		} 
                 
1999/0807    
		n = getl(offset+OffsetSize); 
1999/0608    
		if(n < 0) 
			n = -n; 
		n -= block; 
		if(unsac(buf, data+block, blocksize, n)<0) 
			panic("unsac failed!"); 
1999/0806    
		memmove(cache[j].data, buf, blocksize); 
		cache[j].age = cacheage; 
		cache[j].block = block; 
1999/0608    
	} else { 
		memmove(buf, data+block, blocksize); 
	} 
} 
                 
1999/0609    
static Sac* 
1999/0608    
sacparent(Sac *s) 
{ 
	uchar *blocks; 
	SacDir *buf; 
1999/0807    
	int per, i, n; 
1999/0608    
	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; 
1999/0807    
	n = per; 
	if(n > p->nentry-i*per) 
		n = p->nentry-i*per; 
1999/0608    
	buf = malloc(per*sizeof(SacDir)); 
1999/0807    
	loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir)); 
1999/0608    
	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; 
1999/0807    
	int iblock, per, i, j, n, ndir; 
1999/0609    
	Sac *s; 
1999/0608    
                 
1999/0609    
	s = c->aux; 
1999/0807    
	blocks = data + getl(s->blocks); 
1999/0608    
	per = blocksize/sizeof(SacDir); 
1999/0807    
	ndir = getl(s->length); 
1999/0608    
	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) { 
1999/0807    
			n = per; 
			if(n > ndir-j*per) 
				n = ndir-j*per; 
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir)); 
1999/0608    
			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/0807    
	int i, j, k, n, per; 
1999/0608    
	uchar *blocks; 
	SacDir *buf; 
	int iblock; 
	SacDir *sd; 
	                 
	if(strcmp(name, "..") == 0) 
		return sacparent(s); 
1999/0807    
	blocks = data + getl(s->blocks); 
1999/0608    
	per = blocksize/sizeof(SacDir); 
1999/0807    
	ndir = getl(s->length); 
1999/0608    
	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) { 
1999/0807    
			n = per; 
			if(n > ndir-j*per) 
				n = ndir-j*per; 
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir)); 
1999/0608    
			iblock = j; 
		} 
		j *= per; 
		sd = buf+i-j; 
		k = strcmp(name, sd->name); 
		if(k == 0) { 
1999/0807    
		s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir); 
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]; 
} 
                 
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)