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

1996/0206/port/devtinyfs.c (diff list | history)

1996/0116/sys/src/9/port/devtinyfs.c:13,211996/0120/sys/src/9/port/devtinyfs.c:13,20 (short | long)
1996/0116    
 
enum{ 
	Qdir, 
	Qmedium, 
                 
	Nfile=	32, 
1996/0120    
	Qmedium, 
1996/0116    
}; 
 
 
1996/0116/sys/src/9/port/devtinyfs.c:22,281996/0120/sys/src/9/port/devtinyfs.c:21,27
1996/0116    
struct { 
	QLock; 
	Chan	*c; 
	Dirtab	file[Nfile]; 
1996/0120    
	Dirtab	file[Nfile+1]; 
1996/0116    
	int	nfile; 
} tinyfs; 
 
1996/0116/sys/src/9/port/devtinyfs.c:34,411996/0120/sys/src/9/port/devtinyfs.c:33,41
1996/0116    
	d = tinyfs.file; 
	memmove(d->name, "medium"); 
	d->qid.vers = 0; 
	d->qid.path = Qdata; 
1996/0120    
	d->qid.path = Qmedium; 
1996/0116    
	d->perm = 0666; 
1996/0120    
	tinyfs.nfile = 1; 
1996/0116    
} 
 
void 
1996/0116/sys/src/9/port/devtinyfs.c:46,511996/0120/sys/src/9/port/devtinyfs.c:46,53
1996/0116    
Chan * 
tinyfsattach(char *spec) 
{ 
1996/0120    
	c = namec((char*)arg[0], Aopen, arg[1], 0); 
 
1996/0116    
	return devattach('E', spec); 
} 
 
1996/0116/sys/src/9/port/devtinyfs.c:97,1031996/0120/sys/src/9/port/devtinyfs.c:99,105
1996/0116    
	d->qid.vers = 0; 
	d->qid.path = tinyfs.high++; 
	tinyfs.nfile++; 
			                 
1996/0120    
 
1996/0116    
	qunlock(&tinyfs); 
 
	c->mode = openmode(omode); 
1996/0120/sys/src/9/port/devtinyfs.c:17,281996/0122/sys/src/9/port/devtinyfs.c:17,39 (short | long)
1996/0120    
	Qmedium, 
1996/0116    
}; 
 
1996/0122    
typedef struct FS FS; 
1996/0116    
 
struct { 
1996/0122    
struct FS { 
1996/0116    
	QLock; 
1996/0122    
	Ref	r; 
	int	dev; 
	FS	*next; 
1996/0116    
	Chan	*c; 
1996/0120    
	Dirtab	file[Nfile+1]; 
1996/0122    
	Dirtab	*file; 
1996/0116    
	int	nfile; 
1996/0122    
	int	maxfile; 
}; 
 
struct { 
	QLock; 
	FS	*l; 
	int	hidev; 
1996/0116    
} tinyfs; 
 
void 
1996/0120/sys/src/9/port/devtinyfs.c:46,541996/0122/sys/src/9/port/devtinyfs.c:57,90
1996/0116    
Chan * 
tinyfsattach(char *spec) 
{ 
1996/0120    
	c = namec((char*)arg[0], Aopen, arg[1], 0); 
1996/0122    
	FS *fs, **l; 
	Chan *c, *cc; 
1996/0120    
 
1996/0116    
	return devattach('E', spec); 
1996/0122    
	cc = namec((char*)arg[0], Aopen, arg[1], 0); 
	qlock(&tinyfs); 
	l = &tinyfs.l; 
	for(fs = tinyfs.l; fs != 0; fs = fs->next){ 
		if(eqchan(c, fs->c)) 
			break; 
		l = &(fs->next); 
	} 
	if(fs){ 
		incref(&fs->r); 
		qunlock(&tinyfs); 
		close(cc); 
	} else { 
		fs = smalloc(sizeof(*fs)); 
		*l = fs; 
		fs->c = cc; 
		incref(&fs->r); 
		qunlock(&tinyfs); 
	} 
 
	c = devattach('E', spec); 
	c->aux = fs; 
	c->dev = fs->dev; 
 
	return c; 
1996/0116    
} 
 
Chan * 
1996/0122/sys/src/9/port/devtinyfs.c:13,201996/0123/sys/src/9/port/devtinyfs.c:13,23 (short | long)
1996/0116    
 
enum{ 
	Qdir, 
	Nfile=	32, 
1996/0123    
	Nfile=		32, 
1996/0120    
	Qmedium, 
1996/0123    
 
	Magic=		0xfeedbeef, 
	Superlen=	64, 
1996/0116    
}; 
 
1996/0122    
typedef struct FS FS; 
1996/0122/sys/src/9/port/devtinyfs.c:25,331996/0123/sys/src/9/port/devtinyfs.c:28,36
1996/0122    
	int	dev; 
	FS	*next; 
1996/0116    
	Chan	*c; 
1996/0122    
	Dirtab	*file; 
1996/0116    
	int	nfile; 
1996/0122    
	int	maxfile; 
1996/0123    
	uchar	*fat; 
	ulong	nclust; 
	ulong	clustsize; 
1996/0122    
}; 
 
struct { 
1996/0122/sys/src/9/port/devtinyfs.c:39,521996/0123/sys/src/9/port/devtinyfs.c:42,47
1996/0116    
void 
tinyfsreset(void) 
{ 
	Dirtab *d; 
                 
	d = tinyfs.file; 
	memmove(d->name, "medium"); 
	d->qid.vers = 0; 
1996/0120    
	d->qid.path = Qmedium; 
1996/0116    
	d->perm = 0666; 
1996/0120    
	tinyfs.nfile = 1; 
1996/0116    
} 
 
void 
1996/0122/sys/src/9/port/devtinyfs.c:54,591996/0123/sys/src/9/port/devtinyfs.c:49,123
1996/0116    
{ 
} 
 
1996/0123    
#define GETS(x) ((x)[0]|((x)[1]<<8)) 
#define PUTS(x, v) {(x)[0] = (v);(x)[1] = ((v)>>8);} 
 
#define GETL(x) (GETS(x)|(GETS(x+2)<<16)) 
#define PUTL(x, v) {PUTS(x, v);PUTS(x+2, (v)>>16)};  
 
/* 
 *  see if we have a reasonable fat/root directory 
 */ 
static int 
fsinit(FS *fs) 
{ 
	uchar buf[DIRLEN]; 
	Dir d; 
	ulong x; 
 
	n = devtab[fs->c->type].read(fs->c, buf, Superlen, 0); 
	if(n != Superlen) 
		error(Eio); 
	x = GETL(buf); 
	if(x != Magic) 
		return -1; 
	fs->clustsize = GETL(buf+4); 
	fs->nclust = GETL(buf+8); 
	x = fs->clustsize*fs->nclust; 
 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
	if(d.length < 128) 
		error("tinyfs medium too small"); 
	if(d.length < x) 
		return -1; 
 
	fs->fat = smalloc(2*fs->nclust); 
	n = devtab[fs->c->type].read(fs->c, buf, 2*fs->nclust, Superlen); 
	fd(n != 2*fs->nclust) 
		error(Eio); 
 
	x = GETS(fs->fat); 
	if(x == 0) 
		return -1; 
 
	return 0; 
} 
 
/* 
 *  set up the fat and then a root directory (starting at first cluster (1)) 
 */ 
static void 
fssetup(FS *fs) 
{ 
	uchar buf[DIRLEN]; 
	Dir d; 
 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
	fs->clustsize = d.length>>16; 
	if(fs->clustsize < 64) 
		fs->clustsize = 64; 
	fs->nclust = (d.length - 12)/fs->clustsize; 
	fs->fat = smalloc(2*fs->nclust); 
	n = devtab[fs->c->type].write(fs->c, buf, 2*fs->nclust, Superlen); 
	if(n < 2*fs->nclust) 
		error(Eio); 
	n = devtab[fs->c->type].write(fs->c, buf, Superlen, 0); 
	if(n < Superlen) 
		error(Eio); 
} 
 
1996/0116    
Chan * 
tinyfsattach(char *spec) 
{ 
1996/0122/sys/src/9/port/devtinyfs.c:61,661996/0123/sys/src/9/port/devtinyfs.c:125,135
1996/0122    
	Chan *c, *cc; 
1996/0120    
 
1996/0122    
	cc = namec((char*)arg[0], Aopen, arg[1], 0); 
1996/0123    
	if(waserror()){ 
		close(cc); 
		unlock(&fs); 
		nexterror(); 
	} 
1996/0122    
	qlock(&tinyfs); 
	l = &tinyfs.l; 
	for(fs = tinyfs.l; fs != 0; fs = fs->next){ 
1996/0122/sys/src/9/port/devtinyfs.c:74,841996/0123/sys/src/9/port/devtinyfs.c:143,161
1996/0122    
		close(cc); 
	} else { 
		fs = smalloc(sizeof(*fs)); 
		*l = fs; 
		fs->c = cc; 
		incref(&fs->r); 
1996/0123    
		if(waserror()){ 
			free(fs); 
			nexterror(); 
		} 
		if(fsinit(fs) < 0) 
			fssetup(fs); 
		poperror(); 
		*l = fs; 
1996/0122    
		qunlock(&tinyfs); 
	} 
1996/0123    
	poperror(); 
1996/0122    
 
	c = devattach('E', spec); 
	c->aux = fs; 
1996/0122/sys/src/9/port/devtinyfs.c:123,1431996/0123/sys/src/9/port/devtinyfs.c:200,205
1996/0116    
		qunlock(&tinyfs); 
		nexterror(); 
	} 
	qlock(&tinyfs); 
                 
	if(tinyfs.nfile == Nfile) 
		error("out of space"); 
	for(d = tinyfs.file; d < tinyfs.file[tinyfs.nfile]; d++) 
		if(strcmp(name, d->name) == 0) 
			error("create race"); 
	strncpy(d->name, name, sizeof(d->name)-1); 
	d->perm = perm; 
	d->qid.vers = 0; 
	d->qid.path = tinyfs.high++; 
	tinyfs.nfile++; 
1996/0120    
                 
1996/0116    
	qunlock(&tinyfs); 
                 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->qid = d->qid; 
1996/0123/sys/src/9/port/devtinyfs.c:13,271996/0131/sys/src/9/port/devtinyfs.c:13,28 (short | long)
1996/0116    
 
enum{ 
	Qdir, 
1996/0123    
	Nfile=		32, 
1996/0120    
	Qmedium, 
1996/0123    
 
	Magic=		0xfeedbeef, 
	Superlen=	64, 
1996/0131    
	Blen=	48, 
 
	Tdir=	0, 
	Tdata, 
	Tend, 
1996/0116    
}; 
 
1996/0122    
typedef struct FS FS; 
1996/0116    
                 
1996/0122    
struct FS { 
1996/0116    
	QLock; 
1996/0122    
	Ref	r; 
1996/0123/sys/src/9/port/devtinyfs.c:28,361996/0131/sys/src/9/port/devtinyfs.c:29,36
1996/0122    
	int	dev; 
	FS	*next; 
1996/0116    
	Chan	*c; 
1996/0123    
	uchar	*fat; 
	ulong	nclust; 
	ulong	clustsize; 
1996/0131    
	uchar	*map; 
	int	nblocks; 
1996/0122    
}; 
 
struct { 
1996/0123/sys/src/9/port/devtinyfs.c:39,441996/0131/sys/src/9/port/devtinyfs.c:39,50
1996/0122    
	int	hidev; 
1996/0116    
} tinyfs; 
 
1996/0131    
#define GETS(x) ((x)[0]|((x)[1]<<8)) 
#define PUTS(x, v) {(x)[0] = (v);(x)[1] = ((v)>>8);} 
 
#define GETL(x) (GETS(x)|(GETS(x+2)<<16)) 
#define PUTL(x, v) {PUTS(x, v);PUTS(x+2, (v)>>16)}; 
 
1996/0116    
void 
tinyfsreset(void) 
{ 
1996/0123/sys/src/9/port/devtinyfs.c:49,601996/0131/sys/src/9/port/devtinyfs.c:55,106
1996/0116    
{ 
} 
 
1996/0123    
#define GETS(x) ((x)[0]|((x)[1]<<8)) 
#define PUTS(x, v) {(x)[0] = (v);(x)[1] = ((v)>>8);} 
1996/0131    
static uchar 
checksum(uchar *p) 
{ 
	uchar *e; 
	uchar s; 
1996/0123    
 
#define GETL(x) (GETS(x)|(GETS(x+2)<<16)) 
#define PUTL(x, v) {PUTS(x, v);PUTS(x+2, (v)>>16)};  
1996/0131    
	s = 0; 
	for(e = p + Blen; p < e; p++) 
		s += *p; 
} 
1996/0123    
 
1996/0131    
static void 
mapclr(FS *fs, int bno) 
{ 
	fs->map[bno>>3] &= ~(1<<(bno&7)); 
} 
 
static void 
mapset(FS *fs, int bno) 
{ 
	fs->map[bno>>3] |= 1<<(bno&7); 
} 
 
static int 
mapalloc(FS *fs) 
{ 
	int i, j, lim; 
	uchar x; 
 
	qlock(fs); 
	lim = (fs->nblocks + 8 - 1)/8; 
	for(i = 0; i < lim; i++){ 
		x = fs->map[i]; 
		if(x == 0xff) 
			continue; 
		for(j = 0; j < 8; j++) 
			if((x & (1<<j)) == 0){ 
				fs->map[i] = x|(1<<j); 
				qunlock(fs); 
				return i*8 + j; 
			} 
	} 
	qunlock(fs); 
	return -1; 
} 
 
1996/0123    
/* 
 *  see if we have a reasonable fat/root directory 
 */ 
1996/0123/sys/src/9/port/devtinyfs.c:61,971996/0131/sys/src/9/port/devtinyfs.c:107,141
1996/0123    
static int 
fsinit(FS *fs) 
{ 
	uchar buf[DIRLEN]; 
1996/0131    
	uchar buf[Blen+DIRLEN]; 
1996/0123    
	Dir d; 
	ulong x; 
1996/0131    
	ulong x, bno; 
1996/0123    
 
	n = devtab[fs->c->type].read(fs->c, buf, Superlen, 0); 
	if(n != Superlen) 
		error(Eio); 
	x = GETL(buf); 
	if(x != Magic) 
		return -1; 
	fs->clustsize = GETL(buf+4); 
	fs->nclust = GETL(buf+8); 
	x = fs->clustsize*fs->nclust; 
                 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
	if(d.length < 128) 
1996/0131    
	fs->nblocks = d.length/Blen; 
	if(fs->nblocks < 3) 
1996/0123    
		error("tinyfs medium too small"); 
	if(d.length < x) 
		return -1; 
 
	fs->fat = smalloc(2*fs->nclust); 
	n = devtab[fs->c->type].read(fs->c, buf, 2*fs->nclust, Superlen); 
	fd(n != 2*fs->nclust) 
		error(Eio); 
1996/0131    
	/* bitmap for block usage */ 
	x = (fs->nblocks + 8 - 1)/8; 
	fs->map = malloc(x); 
	memset(fs->map, 0x0, x); 
	for(bno = fs->nblocks; bno < x*8; bno++) 
		mapset(fs, bno); 
1996/0123    
 
	x = GETS(fs->fat); 
	if(x == 0) 
		return -1; 
                 
	return 0; 
1996/0131    
	for(bno = 0; bno < fs->nblocks; bno++){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
			break; 
		if(checksum(buf) != 0) 
			continue; 
		switch(buf[0]){ 
		case Tdir: 
			mapset(fs, bno); 
			break; 
		} 
	} 
1996/0123    
} 
 
/* 
1996/0131/sys/src/9/port/devtinyfs.c:15,421996/0201/sys/src/9/port/devtinyfs.c:15,79 (short | long)
1996/0116    
	Qdir, 
1996/0120    
	Qmedium, 
1996/0123    
 
1996/0131    
	Blen=	48, 
1996/0201    
	Maxfs=		10,	/* max file systems */ 
1996/0131    
 
	Tdir=	0, 
	Tdata, 
	Tend, 
1996/0201    
	Blen=		48,	/* block length */ 
	Nlen=		28,	/* name length */ 
	Dlen=		Blen - 4, 
 
	Tagdir=		'd', 
	Tagdata=	'D', 
	Tagend=		'e', 
	Tagfree=	'f', 
 
	Nopin=		0xffff; 
1996/0116    
}; 
 
1996/0122    
typedef struct FS FS; 
struct FS { 
1996/0116    
	QLock; 
1996/0122    
	Ref	r; 
	int	dev; 
	FS	*next; 
1996/0201    
/* medium representation of a Tdir */ 
typedef struct Mdir Mdir; 
struct Mdir { 
	uchar	type; 
	uchar	bno[2]; 
	uchar	pin[2]; 
	char	name[Nlen]; 
	char	pad[Blen - Nlen - 6]; 
	uchar	sum; 
}; 
 
/* medium representation of a Tdata/Tend */ 
typedef struct Mdata Mdata; 
struct Mdata { 
	uchar	type; 
	uchar	bno[2]; 
	char	data[Dlen]; 
	uchar	sum; 
}; 
 
typedef struct Tfile Tfile; 
struct Tfile { 
	char	name[NAMELEN]; 
	ushort	bno; 
	ushort	dbno; 
	ushort	pin; 
	ulong	length; 
}; 
 
typedef struct Tfs Tfs; 
struct Tfs { 
	Lock; 
	int	r; 
1996/0116    
	Chan	*c; 
1996/0131    
	uchar	*map; 
	int	nblocks; 
1996/0201    
	Tfile	*f; 
	int	nf; 
	int	fsize; 
1996/0122    
}; 
 
struct { 
	QLock; 
	FS	*l; 
	int	hidev; 
1996/0201    
	Tfs	fs[Maxfs]; 
	short	nfs; 
1996/0116    
} tinyfs; 
 
1996/0131    
#define GETS(x) ((x)[0]|((x)[1]<<8)) 
1996/0131/sys/src/9/port/devtinyfs.c:45,601996/0201/sys/src/9/port/devtinyfs.c:82,87
1996/0131    
#define GETL(x) (GETS(x)|(GETS(x+2)<<16)) 
#define PUTL(x, v) {PUTS(x, v);PUTS(x+2, (v)>>16)}; 
 
1996/0116    
void 
tinyfsreset(void) 
{ 
} 
                 
void 
tinyfsinit(void) 
{ 
} 
                 
1996/0131    
static uchar 
checksum(uchar *p) 
{ 
1996/0131/sys/src/9/port/devtinyfs.c:67,861996/0201/sys/src/9/port/devtinyfs.c:94,119
1996/0131    
} 
1996/0123    
 
1996/0131    
static void 
mapclr(FS *fs, int bno) 
1996/0201    
mapclr(Tfs *fs, ulong bno) 
1996/0131    
{ 
	fs->map[bno>>3] &= ~(1<<(bno&7)); 
} 
 
static void 
mapset(FS *fs, int bno) 
1996/0201    
mapset(Tfs *fs, ulong bno) 
1996/0131    
{ 
	fs->map[bno>>3] |= 1<<(bno&7); 
} 
 
static int 
mapalloc(FS *fs) 
1996/0201    
isalloced(Tfs *fs, ulong bno) 
1996/0131    
{ 
1996/0201    
	return fs->map[bno>>3] & (1<<(bno&7)); 
} 
 
static int 
mapalloc(Tfs *fs) 
{ 
1996/0131    
	int i, j, lim; 
	uchar x; 
 
1996/0131/sys/src/9/port/devtinyfs.c:101,1151996/0201/sys/src/9/port/devtinyfs.c:134,242
1996/0131    
	return -1; 
} 
 
1996/0201    
static Mdir* 
validdir(Tfs *fs, uchar *p) 
{ 
	Mdir *md; 
	ulong x; 
 
	if(checksum(p) != 0) 
		return 0; 
	if(buf[0] != Tagdir) 
		return 0; 
	md = (Mdir*)p; 
	x = GETS(md->bno); 
	if(x >= fs->nblocks) 
		return 0; 
	return md; 
} 
 
static Mdata* 
validdata(Tfs *fs, uchar *p) 
{ 
	Mdata *md; 
	ulong x; 
 
	if(checksum(p) != 0) 
		return 0; 
	md = (Mdir*)p; 
	switch(buf[0]){ 
	case Tagdata: 
		x = GETS(md->bno); 
		if(x >= fs->nblocks) 
			return 0; 
		break; 
	case Tagend: 
		x = GETS(md->bno); 
		if(x > Blen - 4) 
			return 0; 
		break; 
	} 
	return md; 
} 
 
static void 
freefile(Tfs *fs, Tfile *f, ulong bend) 
{ 
	uchar buf[Blen]; 
	ulong bno; 
	int n; 
	Mdata *md; 
 
	/* remove blocks from map */ 
	bno = f->dbno; 
	while(bend != bno){ 
		mapclr(fs, bno); 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
			break; 
		md = validdata(buf); 
		if(md == 0) 
			break; 
		if(md->type == Tagend) 
			break; 
		bno = GETS(md->bno); 
	} 
 
	/* change file type to free on medium */ 
	n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno); 
	if(n != Blen) 
		return; 
	buf[0] = Tagfree; 
	devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
 
	/* forget we ever knew about it */ 
	memset(f, 0, sizeof(*f)); 
} 
 
static void 
expand(Tfs *fs) 
{ 
	Tfile *f; 
 
	fs->fsize += 8; 
	f = smalloc(fs->fsize*sizeof(*f)); 
 
	lock(fs); 
	memmove(f, fs->f, fs->nf*sizoef(f)); 
	free(fs->f); 
	fs->f = f; 
	unlock(fs); 
} 
 
1996/0123    
/* 
 *  see if we have a reasonable fat/root directory 
 */ 
static int 
fsinit(FS *fs) 
1996/0201    
static void 
fsinit(Tfs *fs) 
1996/0123    
{ 
1996/0131    
	uchar buf[Blen+DIRLEN]; 
1996/0123    
	Dir d; 
1996/0131    
	ulong x, bno; 
1996/0201    
	int n; 
	Tfile *f; 
	Mdir *mdir; 
	Mdata *mdat; 
1996/0123    
 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
1996/0131/sys/src/9/port/devtinyfs.c:119,2091996/0201/sys/src/9/port/devtinyfs.c:246,381
1996/0123    
 
1996/0131    
	/* bitmap for block usage */ 
	x = (fs->nblocks + 8 - 1)/8; 
	fs->map = malloc(x); 
1996/0201    
	fs->map = smalloc(x); 
1996/0131    
	memset(fs->map, 0x0, x); 
	for(bno = fs->nblocks; bno < x*8; bno++) 
		mapset(fs, bno); 
1996/0123    
 
1996/0201    
	/* find files */ 
1996/0131    
	for(bno = 0; bno < fs->nblocks; bno++){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
			break; 
		if(checksum(buf) != 0) 
1996/0201    
 
		mdir = validdir(buf); 
		if(mdir == 0) 
1996/0131    
			continue; 
		switch(buf[0]){ 
		case Tdir: 
1996/0201    
 
		if(fs->nfs <= fs->fsize) 
			expand(fs); 
		f = &fs->f[fs->nf++]; 
 
		x = GETS(mdir->bno); 
		mapset(fs, bno); 
		strncpy(f->name, mdir->name, sizeof(f->name)); 
		f->pin = GETS(mdir->pin); 
		f->bno = bno; 
		f->dbno = x; 
	} 
 
	/* follow files */ 
	for(f = fs->f; f; f = f->next){ 
		bno = fs->dbno; 
		for(;;) { 
			if(isalloced(fs, bno)){ 
				freefile(f, bno); 
				break; 
			} 
			n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
			if(n != Blen){ 
				freefile(fs, f, bno); 
				break; 
			} 
			mdata = validdata(fs, buf); 
			if(mdata == 0){ 
				freefile(fs, f, bno); 
				break; 
			} 
1996/0131    
			mapset(fs, bno); 
			break; 
1996/0201    
			switch(mdata->type){ 
			case Tagdata: 
				bno = GETS(mdata->bno); 
				f->len += Dlen; 
				break; 
			case Tagend: 
				f->len += GETS(mdata->bno); 
				break; 
			} 
1996/0131    
		} 
	} 
1996/0123    
} 
 
/* 
 *  set up the fat and then a root directory (starting at first cluster (1)) 
 */ 
static void 
fssetup(FS *fs) 
1996/0201    
static int 
tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 
1996/0123    
{ 
	uchar buf[DIRLEN]; 
	Dir d; 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
	Qid qid; 
1996/0123    
 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
	fs->clustsize = d.length>>16; 
	if(fs->clustsize < 64) 
		fs->clustsize = 64; 
	fs->nclust = (d.length - 12)/fs->clustsize; 
	fs->fat = smalloc(2*fs->nclust); 
	n = devtab[fs->c->type].write(fs->c, buf, 2*fs->nclust, Superlen); 
	if(n < 2*fs->nclust) 
		error(Eio); 
	n = devtab[fs->c->type].write(fs->c, buf, Superlen, 0); 
	if(n < Superlen) 
		error(Eio); 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	if(i >= fs->nf) 
		return -1; 
	f = &fs->f[i]; 
	qid.path = i; 
	qid.vers = 0; 
	devdir(c, qid, f->name, f->length, eve, f->pin==Nopin?0444:0666, dp); 
	return 1; 
1996/0123    
} 
 
1996/0201    
void 
tinyfsreset(void) 
{ 
	if(Nlen > NAMELEN) 
		panic("tinyfsreset"); 
} 
 
void 
tinyfsinit(void) 
{ 
} 
 
1996/0116    
Chan * 
tinyfsattach(char *spec) 
{ 
1996/0122    
	FS *fs, **l; 
1996/0201    
	Tfs *fs; 
1996/0122    
	Chan *c, *cc; 
1996/0201    
	int i; 
1996/0120    
 
1996/0122    
	cc = namec((char*)arg[0], Aopen, arg[1], 0); 
1996/0123    
	if(waserror()){ 
		close(cc); 
		unlock(&fs); 
1996/0201    
		qunlock(&tinyfs); 
1996/0123    
		nexterror(); 
	} 
1996/0201    
 
1996/0122    
	qlock(&tinyfs); 
	l = &tinyfs.l; 
	for(fs = tinyfs.l; fs != 0; fs = fs->next){ 
		if(eqchan(c, fs->c)) 
1996/0201    
	for(i = 0; i < tinyfs.nfs; i++){ 
		fs = &tinyfs.fs[i]; 
		if(fs && eqchan(c, fs->c)) 
1996/0122    
			break; 
		l = &(fs->next); 
	} 
	if(fs){ 
		incref(&fs->r); 
		qunlock(&tinyfs); 
1996/0201    
	if(i < tinyfs.nfs){ 
		lock(fs); 
		fs->r++; 
		unlock(fs); 
1996/0122    
		close(cc); 
	} else { 
		fs = smalloc(sizeof(*fs)); 
1996/0201    
		if(tinyfs.nfs >= Maxfs) 
			error("too many tinyfs's"); 
		fs = &tinyfs.fs[tinyfs.nfs]; 
		memset(fs, 0, sizeof(*fs)); 
1996/0122    
		fs->c = cc; 
		incref(&fs->r); 
1996/0123    
		if(waserror()){ 
			free(fs); 
			nexterror(); 
		} 
		if(fsinit(fs) < 0) 
			fssetup(fs); 
		poperror(); 
		*l = fs; 
1996/0122    
		qunlock(&tinyfs); 
1996/0201    
		fs->r = 1; 
		fsinit(fs); 
		tinyfs.nfs++; 
1996/0122    
	} 
1996/0201    
	qunlock(&tinyfs); 
1996/0123    
	poperror(); 
1996/0122    
 
	c = devattach('E', spec); 
	c->aux = fs; 
	c->dev = fs->dev; 
1996/0201    
	c = devattach('U', spec); 
	c->dev = fs - tinyfs.fs; 
	c->qid.path = CHDIR; 
	c->qid.vers = 0; 
1996/0122    
 
	return c; 
1996/0116    
} 
1996/0131/sys/src/9/port/devtinyfs.c:217,2521996/0201/sys/src/9/port/devtinyfs.c:389,462
1996/0116    
int 
tinyfswalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, tinyfs.file, tinyfs.nfile, devgen); 
1996/0201    
	return devwalk(c, name, 0, 0, tinyfsgen); 
1996/0116    
} 
 
void 
tinyfsstat(Chan *c, char *db) 
{ 
	devstat(c, db, tinyfs.file, tinyfs.nfile, devgen); 
1996/0201    
	devstat(c, db, 0, 0, tinyfsgen); 
1996/0116    
} 
 
Chan * 
tinyfsopen(Chan *c, int omode) 
{ 
	return devopen(c, omode, tinyfs.file, tinyfs.nfile, devgen); 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
 
	fs = &tinyfs.fs[c->dev]; 
 
	if(c->path & CHDIR){ 
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
		lock(fs); 
		f = fs->f[c->path]; 
		unlock(fs); 
 
		if(f->pin == Nopin){ 
			if(omode != OREAD) 
				error(Eperm); 
		} else { 
			if(omode != ORDWR) 
				error(Eperm); 
		} 
	} 
 
	return devopen(c, omode, 0, 0, tinyfsgen); 
1996/0116    
} 
 
void 
tinyfscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	Dirtab	*d; 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
1996/0116    
 
	if(perm & CHDIR) 
		error("directory creation illegal"); 
 
	if(waserror()){ 
		qunlock(&tinyfs); 
		nexterror(); 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	for(;;) { 
		lock(fs); 
		for(i = 0; i < fs->fsize; i++){ 
			f = &fs->f[i]; 
			if(f->name[0] == 0){ 
				strncpy(f->name, name, sizeof(f->name)-1); 
				break; 
			} 
		} 
		if(i < fs->fsize) 
			break; 
 
		unlock(fs); 
		expand(fs); 
1996/0116    
	} 
1996/0201    
	unlock(fs); 
 
	c->qid.path = f - fs->f; 
	c->qid.vers = 1;		/* creating */ 
1996/0116    
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->qid = d->qid; 
} 
 
void 
1996/0131/sys/src/9/port/devtinyfs.c:266,2711996/0201/sys/src/9/port/devtinyfs.c:476,512
1996/0116    
void 
tinyfsclose(Chan *c) 
{ 
1996/0201    
	Tfs *fs, **l; 
	Tfile *f, *nf; 
 
	fs = c->aux; 
	lock(fs); 
	fs->ref--; 
	unlock(fs); 
 
	if(fs->ref) 
		return; 
 
	qlock(&tinyfs); 
	lock(fs); 
	if(fs->ref == 0){ 
		for(l = &fs->l; *l;){ 
			if(*l == fs){ 
				*l = fs->next; 
				break; 
			} 
			l = &(*l)->next; 
		} 
		for(f = fs->f; f; f = nf){ 
			nf = f->next; 
			free(f); 
		} 
		free(fs->map); 
		close(fs->c); 
		free(fs); 
	} 
	unlock(fs); 
	qunlock(&tinyfs); 
1996/0116    
} 
 
long 
1996/0131/sys/src/9/port/devtinyfs.c:273,2791996/0201/sys/src/9/port/devtinyfs.c:514,520
1996/0116    
{ 
	switch(c->qid.path & ~CHDIR){ 
	case Qdir: 
		return devdirread(c, a, n, tinyfstab, Ntinyfstab, devgen); 
1996/0201    
		return devdirread(c, a, n, tinyfstab, Ntinyfstab, tinyfsgen); 
1996/0116    
	case Qdata: 
		break; 
	default: 
1996/0201/sys/src/9/port/devtinyfs.c:1,51996/0202/sys/src/9/port/devtinyfs.c:1,5 (short | long)
1996/0116    
/* 
 *  template for making a new device 
1996/0202    
 *  a pity the code isn't also tiny... 
1996/0116    
 */ 
 
#include	"u.h" 
1996/0201/sys/src/9/port/devtinyfs.c:26,351996/0202/sys/src/9/port/devtinyfs.c:26,36
1996/0201    
	Tagend=		'e', 
	Tagfree=	'f', 
 
	Nopin=		0xffff; 
1996/0202    
	Notapin=		0xffff, 
	Notabno=		0xffff, 
1996/0116    
}; 
 
1996/0201    
/* medium representation of a Tdir */ 
1996/0202    
/* representation of a Tdir on medium */ 
1996/0201    
typedef struct Mdir Mdir; 
struct Mdir { 
	uchar	type; 
1996/0201/sys/src/9/port/devtinyfs.c:40,461996/0202/sys/src/9/port/devtinyfs.c:41,47
1996/0201    
	uchar	sum; 
}; 
 
/* medium representation of a Tdata/Tend */ 
1996/0202    
/* representation of a Tdata/Tend on medium */ 
1996/0201    
typedef struct Mdata Mdata; 
struct Mdata { 
	uchar	type; 
1996/0201/sys/src/9/port/devtinyfs.c:51,661996/0202/sys/src/9/port/devtinyfs.c:52,69
1996/0201    
 
typedef struct Tfile Tfile; 
struct Tfile { 
1996/0202    
	int	r; 
1996/0201    
	char	name[NAMELEN]; 
	ushort	bno; 
	ushort	dbno; 
	ushort	pin; 
1996/0202    
	char	creating; 
1996/0201    
	ulong	length; 
}; 
 
typedef struct Tfs Tfs; 
struct Tfs { 
	Lock; 
1996/0202    
	QLock; 
1996/0201    
	int	r; 
1996/0116    
	Chan	*c; 
1996/0131    
	uchar	*map; 
1996/0201/sys/src/9/port/devtinyfs.c:91,961996/0202/sys/src/9/port/devtinyfs.c:94,100
1996/0131    
	s = 0; 
	for(e = p + Blen; p < e; p++) 
		s += *p; 
1996/0202    
	return s; 
1996/0131    
} 
1996/0123    
 
1996/0131    
static void 
1996/0201/sys/src/9/port/devtinyfs.c:175,1801996/0202/sys/src/9/port/devtinyfs.c:179,205
1996/0201    
	return md; 
} 
 
1996/0202    
static int 
writedir(Tfs *fs, Tfile *f) 
{ 
	Mdir *md; 
	int n; 
	uchar buf[Blen]; 
 
	if(f->bno == Notabno) 
		return Blen; 
 
	md = (Mdir*)buf; 
	memset(buf, 0, Blen); 
	md->type = Tagdir; 
	strncpy(md->name, f->name, sizeof(md->name)-1); 
	PUTS(md->bno, f->dbno); 
	PUTS(md->pin, f->pin); 
	f->sum = 0 - checksum(buf); 
 
	return devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
} 
 
1996/0201    
static void 
freefile(Tfs *fs, Tfile *f, ulong bend) 
{ 
1996/0201/sys/src/9/port/devtinyfs.c:185,1911996/0202/sys/src/9/port/devtinyfs.c:210,216
1996/0201    
 
	/* remove blocks from map */ 
	bno = f->dbno; 
	while(bend != bno){ 
1996/0202    
	while(bno != bend && bno != Notabno){ 
1996/0201    
		mapclr(fs, bno); 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
1996/0201/sys/src/9/port/devtinyfs.c:199,2091996/0202/sys/src/9/port/devtinyfs.c:224,236
1996/0201    
	} 
 
	/* change file type to free on medium */ 
	n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno); 
	if(n != Blen) 
		return; 
	buf[0] = Tagfree; 
	devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
1996/0202    
	if(f->bno != Notabno){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno); 
		if(n != Blen) 
			return; 
		buf[0] = Tagfree; 
		devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
	} 
1996/0201    
 
	/* forget we ever knew about it */ 
	memset(f, 0, sizeof(*f)); 
1996/0201/sys/src/9/port/devtinyfs.c:217,2311996/0202/sys/src/9/port/devtinyfs.c:244,296
1996/0201    
	fs->fsize += 8; 
	f = smalloc(fs->fsize*sizeof(*f)); 
 
	lock(fs); 
	memmove(f, fs->f, fs->nf*sizoef(f)); 
	free(fs->f); 
	fs->f = f; 
	unlock(fs); 
} 
 
1996/0202    
static Tfile* 
newfile(Tfs *fs, char *name) 
{ 
	int i; 
	Tfile *f; 
 
	/* find free entry in file table */ 
	for(;;) { 
		for(i = 0; i < fs->fsize; i++){ 
			f = &fs->f[i]; 
			if(f->name[0] == 0){ 
				strncpy(f->name, name, sizeof(f->name)-1); 
				break; 
			} 
		} 
 
		if(i < fs->fsize) 
			break; 
 
		expand(fs); 
	} 
 
	f->creating = 1; 
	f->dbno = Notabno; 
	f->bno = mapalloc(fs); 
 
	/* write directory block */ 
	if(waserror()){ 
		filefree(fs, f, Notabno); 
		nexterror(); 
	} 
	if(b->bno == Notabno) 
		error("out of space"); 
	writedir(fs, f); 
	poperror(); 
	 
	return f; 
} 
 
1996/0123    
/* 
 *  see if we have a reasonable fat/root directory 
1996/0202    
 *  Read the whole medium and build a file table and used 
 *  block bitmap.  Inconsistent files are purged. 
1996/0123    
 */ 
1996/0201    
static void 
fsinit(Tfs *fs) 
1996/0201/sys/src/9/port/devtinyfs.c:263,2681996/0202/sys/src/9/port/devtinyfs.c:328,334
1996/0201    
 
		if(fs->nfs <= fs->fsize) 
			expand(fs); 
1996/0202    
 
1996/0201    
		f = &fs->f[fs->nf++]; 
 
		x = GETS(mdir->bno); 
1996/0201/sys/src/9/port/devtinyfs.c:305,3101996/0202/sys/src/9/port/devtinyfs.c:371,379
1996/0131    
	} 
1996/0123    
} 
 
1996/0202    
/* 
 *  single directory 
 */ 
1996/0201    
static int 
tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 
1996/0123    
{ 
1996/0201/sys/src/9/port/devtinyfs.c:318,3241996/0202/sys/src/9/port/devtinyfs.c:387,393
1996/0201    
	f = &fs->f[i]; 
	qid.path = i; 
	qid.vers = 0; 
	devdir(c, qid, f->name, f->length, eve, f->pin==Nopin?0444:0666, dp); 
1996/0202    
	devdir(c, qid, f->name, f->length, eve, 0664, dp); 
1996/0201    
	return 1; 
1996/0123    
} 
 
1996/0201/sys/src/9/port/devtinyfs.c:355,3631996/0202/sys/src/9/port/devtinyfs.c:424,432
1996/0122    
			break; 
	} 
1996/0201    
	if(i < tinyfs.nfs){ 
		lock(fs); 
1996/0202    
		qlock(fs); 
1996/0201    
		fs->r++; 
		unlock(fs); 
1996/0202    
		qunlock(fs); 
1996/0122    
		close(cc); 
	} else { 
1996/0201    
		if(tinyfs.nfs >= Maxfs) 
1996/0201/sys/src/9/port/devtinyfs.c:383,3881996/0202/sys/src/9/port/devtinyfs.c:452,461
1996/0116    
Chan * 
tinyfsclone(Chan *c, Chan *nc) 
{ 
1996/0202    
	qlock(fs); 
	fs->r++; 
	qunlock(fs); 
 
1996/0116    
	return devclone(c, nc); 
} 
 
1996/0201/sys/src/9/port/devtinyfs.c:389,3951996/0202/sys/src/9/port/devtinyfs.c:462,477
1996/0116    
int 
tinyfswalk(Chan *c, char *name) 
{ 
1996/0201    
	return devwalk(c, name, 0, 0, tinyfsgen); 
1996/0202    
	int n; 
 
	qlock(fs); 
	n = devwalk(c, name, 0, 0, tinyfsgen); 
	if(n != 0 && c->qid.path != CHDIR){ 
		fs = &tinyfs.fs[c->dev]; 
		fs->f[c->qid.path].r++; 
	} 
	qunlock(fs); 
	return n; 
1996/0116    
} 
 
void 
1996/0201/sys/src/9/port/devtinyfs.c:410,4261996/0202/sys/src/9/port/devtinyfs.c:492,506
1996/0201    
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
		lock(fs); 
		f = fs->f[c->path]; 
		unlock(fs); 
                 
		if(f->pin == Nopin){ 
			if(omode != OREAD) 
				error(Eperm); 
		} else { 
			if(omode != ORDWR) 
				error(Eperm); 
1996/0202    
		qlock(fs); 
		if(omode == (OTRUNC|ORDWR)){ 
			f = newfile(fs, fs->f[c->qid.path]); 
			c->qid.path = f - fs->f; 
		} else if(omode != OREAD){ 
			qunlock(fs); 
			error(Eperm); 
1996/0201    
		} 
1996/0202    
		qunlock(fs); 
1996/0201    
	} 
 
	return devopen(c, omode, 0, 0, tinyfsgen); 
1996/0201/sys/src/9/port/devtinyfs.c:435,4621996/0202/sys/src/9/port/devtinyfs.c:515,527
1996/0116    
	if(perm & CHDIR) 
		error("directory creation illegal"); 
 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	for(;;) { 
		lock(fs); 
		for(i = 0; i < fs->fsize; i++){ 
			f = &fs->f[i]; 
			if(f->name[0] == 0){ 
				strncpy(f->name, name, sizeof(f->name)-1); 
				break; 
			} 
		} 
		if(i < fs->fsize) 
			break; 
1996/0202    
	qlock(fs); 
	f = newfile(fs, name); 
	qunlock(fs); 
1996/0201    
 
		unlock(fs); 
		expand(fs); 
1996/0116    
	} 
1996/0201    
	unlock(fs); 
                 
	c->qid.path = f - fs->f; 
	c->qid.vers = 1;		/* creating */ 
1996/0202    
	c->qid.vers = 0; 
1996/0116    
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
} 
 
void 
1996/0201/sys/src/9/port/devtinyfs.c:478,4941996/0202/sys/src/9/port/devtinyfs.c:543,572
1996/0116    
{ 
1996/0201    
	Tfs *fs, **l; 
	Tfile *f, *nf; 
1996/0202    
	int i; 
1996/0201    
 
	fs = c->aux; 
	lock(fs); 
	fs->ref--; 
	unlock(fs); 
 
	if(fs->ref) 
		return; 
1996/0202    
	qlock(fs); 
1996/0201    
 
	qlock(&tinyfs); 
	lock(fs); 
1996/0202    
	/* dereference file and remove old versions */ 
	if(c->qid.path != CHDIR){ 
		f = &fs->f[c->qid.path]; 
		f->r--; 
		if(f->r == 0 && f->creating){ 
			/* remove all other files with this name */ 
			for(i = 0; i < fs->fsize; i++){ 
				nf = &fs->f[i]; 
				if(f == nf) 
					continue; 
				if(strcmp(nf->name, f->name) == 0) 
					freefile(fs, nf, Notabno); 
			} 
		} 
	} 
 
	/* dereference fs and remove on zero refs */ 
	fs->r--; 
1996/0201    
	if(fs->ref == 0){ 
		for(l = &fs->l; *l;){ 
			if(*l == fs){ 
1996/0202/sys/src/9/port/devtinyfs.c:28,331996/0203/sys/src/9/port/devtinyfs.c:28,36 (short | long)
1996/0201    
 
1996/0202    
	Notapin=		0xffff, 
	Notabno=		0xffff, 
1996/0203    
 
	Fcreating=	1, 
	Frmonclose=	2, 
1996/0116    
}; 
 
1996/0202    
/* representation of a Tdir on medium */ 
1996/0202/sys/src/9/port/devtinyfs.c:57,631996/0203/sys/src/9/port/devtinyfs.c:60,66
1996/0201    
	ushort	bno; 
	ushort	dbno; 
	ushort	pin; 
1996/0202    
	char	creating; 
1996/0203    
	uchar	flag; 
1996/0201    
	ulong	length; 
}; 
 
1996/0202/sys/src/9/port/devtinyfs.c:271,2771996/0203/sys/src/9/port/devtinyfs.c:274,280
1996/0202    
		expand(fs); 
	} 
 
	f->creating = 1; 
1996/0203    
	f->flag = Fcreating; 
1996/0202    
	f->dbno = Notabno; 
	f->bno = mapalloc(fs); 
 
1996/0202/sys/src/9/port/devtinyfs.c:553,5721996/0203/sys/src/9/port/devtinyfs.c:556,586
1996/0202    
	if(c->qid.path != CHDIR){ 
		f = &fs->f[c->qid.path]; 
		f->r--; 
		if(f->r == 0 && f->creating){ 
			/* remove all other files with this name */ 
			for(i = 0; i < fs->fsize; i++){ 
				nf = &fs->f[i]; 
				if(f == nf) 
					continue; 
				if(strcmp(nf->name, f->name) == 0) 
					freefile(fs, nf, Notabno); 
1996/0203    
		if(f->r == 0){ 
			if(f->creating){ 
				/* remove all other files with this name */ 
				for(i = 0; i < fs->fsize; i++){ 
					nf = &fs->f[i]; 
					if(f == nf) 
						continue; 
					if(strcmp(nf->name, f->name) == 0){ 
						if(nf->r) 
							nf->flag |= Frmonclose; 
						else 
							freefile(fs, nf, Notabno); 
					} 
				} 
				f->flag &= ~(Frmonclose|Fcreating); 
1996/0202    
			} 
1996/0203    
			if(f->flag & Frmonclose){ 
				freefile(fs, f, Notabno); 
1996/0202    
		} 
	} 
 
	/* dereference fs and remove on zero refs */ 
	fs->r--; 
1996/0203    
	unlock(fs); 
	qlock(&tinyfs); 
1996/0201    
	if(fs->ref == 0){ 
		for(l = &fs->l; *l;){ 
			if(*l == fs){ 
1996/0202/sys/src/9/port/devtinyfs.c:575,5891996/0203/sys/src/9/port/devtinyfs.c:589,599
1996/0201    
			} 
			l = &(*l)->next; 
		} 
		for(f = fs->f; f; f = nf){ 
			nf = f->next; 
			free(f); 
		} 
1996/0203    
		free(fs-f); 
1996/0201    
		free(fs->map); 
		close(fs->c); 
		free(fs); 
1996/0203    
		memset(fs, 0, sizeof(*fs)); 
1996/0201    
	} 
	unlock(fs); 
	qunlock(&tinyfs); 
1996/0116    
} 
 
1996/0202/sys/src/9/port/devtinyfs.c:590,6041996/0203/sys/src/9/port/devtinyfs.c:600,619
1996/0116    
long 
tinyfsread(Chan *c, void *a, long n, ulong offset) 
{ 
	switch(c->qid.path & ~CHDIR){ 
	case Qdir: 
1996/0203    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
 
	if(c->qid.path & CHDIR) 
1996/0201    
		return devdirread(c, a, n, tinyfstab, Ntinyfstab, tinyfsgen); 
1996/0116    
	case Qdata: 
		break; 
	default: 
		n=0; 
		break; 
	} 
1996/0203    
 
	fs = tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
	if(offset >= f->length) 
		return 0; 
	if(n + offset >= f->length) 
		n = f->length - offset; 
 
1996/0116    
	return n; 
} 
 
1996/0203/sys/src/9/port/devtinyfs.c:55,601996/0206/sys/src/9/port/devtinyfs.c:55,61 (short | long)
1996/0201    
 
typedef struct Tfile Tfile; 
struct Tfile { 
1996/0206    
	Lock; 
1996/0202    
	int	r; 
1996/0201    
	char	name[NAMELEN]; 
	ushort	bno; 
1996/0203/sys/src/9/port/devtinyfs.c:182,1871996/0206/sys/src/9/port/devtinyfs.c:183,199
1996/0201    
	return md; 
} 
 
1996/0206    
static Mdata* 
readdata(Tfs *fs, ulong bno, uchar *buf) 
{ 
	if(bno >= fs->nblocks) 
		return 0; 
	n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
	if(n != Blen) 
		return 0; 
	return validdata(fs, buf); 
} 
 
1996/0202    
static int 
writedir(Tfs *fs, Tfile *f) 
{ 
1996/0203/sys/src/9/port/devtinyfs.c:603,6081996/0206/sys/src/9/port/devtinyfs.c:615,623
1996/0203    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
1996/0206    
	ulong bno, tbno; 
	Mdata *md; 
	uchar buf[Blen]; 
1996/0203    
 
	if(c->qid.path & CHDIR) 
1996/0201    
		return devdirread(c, a, n, tinyfstab, Ntinyfstab, tinyfsgen); 
1996/0203/sys/src/9/port/devtinyfs.c:613,6181996/0206/sys/src/9/port/devtinyfs.c:628,649
1996/0203    
		return 0; 
	if(n + offset >= f->length) 
		n = f->length - offset; 
1996/0206    
 
	/* walk to first data block */ 
	bno = f->dbno; 
	for(sofar = 0; sofar < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf); 
		if(md == 0) 
			error(Eio); 
		bno = GETS(md->bno); 
	} 
 
	/* read first block */ 
	i = offset%Blen; 
 
	/* read data */ 
	for(sofar = 0; sofar+Blen < offset; sofar += Blen){ 
	 
1996/0203    
 
1996/0116    
	return n; 
} 
1996/0206/sys/src/9/port/devtinyfs.c:160,1661996/0217/sys/src/9/port/devtinyfs.c:160,166 (short | long)
1996/0201    
} 
 
static Mdata* 
validdata(Tfs *fs, uchar *p) 
1996/0217    
validdata(Tfs *fs, uchar *p, int *lenp) 
1996/0201    
{ 
	Mdata *md; 
	ulong x; 
1996/0206/sys/src/9/port/devtinyfs.c:173,1831996/0217/sys/src/9/port/devtinyfs.c:173,187
1996/0201    
		x = GETS(md->bno); 
		if(x >= fs->nblocks) 
			return 0; 
1996/0217    
		if(lenp) 
			*lenp = Dlen; 
1996/0201    
		break; 
	case Tagend: 
		x = GETS(md->bno); 
		if(x > Blen - 4) 
1996/0217    
		if(x > Dlen) 
1996/0201    
			return 0; 
1996/0217    
		if(lenp) 
			*lenp = x; 
1996/0201    
		break; 
	} 
	return md; 
1996/0206/sys/src/9/port/devtinyfs.c:184,1971996/0217/sys/src/9/port/devtinyfs.c:188,203
1996/0201    
} 
 
1996/0206    
static Mdata* 
readdata(Tfs *fs, ulong bno, uchar *buf) 
1996/0217    
readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp) 
1996/0206    
{ 
1996/0217    
	Mdata *md; 
 
1996/0206    
	if(bno >= fs->nblocks) 
		return 0; 
	n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
	if(n != Blen) 
		return 0; 
	return validdata(fs, buf); 
1996/0217    
	return validdata(fs, buf, lenp); 
1996/0206    
} 
 
1996/0202    
static int 
1996/0206/sys/src/9/port/devtinyfs.c:230,2361996/0217/sys/src/9/port/devtinyfs.c:236,242
1996/0201    
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
			break; 
		md = validdata(buf); 
1996/0217    
		md = validdata(fs, buf, 0); 
1996/0201    
		if(md == 0) 
			break; 
		if(md->type == Tagend) 
1996/0206/sys/src/9/port/devtinyfs.c:259,2651996/0217/sys/src/9/port/devtinyfs.c:265,271
1996/0201    
	fs->fsize += 8; 
	f = smalloc(fs->fsize*sizeof(*f)); 
 
	memmove(f, fs->f, fs->nf*sizoef(f)); 
1996/0217    
	memmove(f, fs->f, fs->nf*sizeof(f)); 
1996/0201    
	free(fs->f); 
	fs->f = f; 
} 
1996/0206/sys/src/9/port/devtinyfs.c:305,3111996/0217/sys/src/9/port/devtinyfs.c:311,318
1996/0202    
 
1996/0123    
/* 
1996/0202    
 *  Read the whole medium and build a file table and used 
 *  block bitmap.  Inconsistent files are purged. 
1996/0217    
 *  block bitmap.  Inconsistent files are purged.  The medium 
 *  had better be small or this could take a while. 
1996/0123    
 */ 
1996/0201    
static void 
fsinit(Tfs *fs) 
1996/0206/sys/src/9/port/devtinyfs.c:313,3191996/0217/sys/src/9/port/devtinyfs.c:320,326
1996/0131    
	uchar buf[Blen+DIRLEN]; 
1996/0123    
	Dir d; 
1996/0131    
	ulong x, bno; 
1996/0201    
	int n; 
1996/0217    
	int n, done; 
1996/0201    
	Tfile *f; 
	Mdir *mdir; 
	Mdata *mdat; 
1996/0206/sys/src/9/port/devtinyfs.c:341,3471996/0217/sys/src/9/port/devtinyfs.c:348,354
1996/0201    
		if(mdir == 0) 
1996/0131    
			continue; 
1996/0201    
 
		if(fs->nfs <= fs->fsize) 
1996/0217    
		if(fs->nfs >= fs->fsize) 
1996/0201    
			expand(fs); 
1996/0202    
 
1996/0201    
		f = &fs->f[fs->nf++]; 
1996/0206/sys/src/9/port/devtinyfs.c:355,3631996/0217/sys/src/9/port/devtinyfs.c:362,370
1996/0201    
	} 
 
	/* follow files */ 
	for(f = fs->f; f; f = f->next){ 
1996/0217    
	for(f = fs->f; f < &(fs->f[fs->nf]); f++){ 
1996/0201    
		bno = fs->dbno; 
		for(;;) { 
1996/0217    
		for(done = 0; !done;) { 
1996/0201    
			if(isalloced(fs, bno)){ 
				freefile(f, bno); 
				break; 
1996/0206/sys/src/9/port/devtinyfs.c:367,3731996/0217/sys/src/9/port/devtinyfs.c:374,380
1996/0201    
				freefile(fs, f, bno); 
				break; 
			} 
			mdata = validdata(fs, buf); 
1996/0217    
			mdata = validdata(fs, buf, 0); 
1996/0201    
			if(mdata == 0){ 
				freefile(fs, f, bno); 
				break; 
1996/0206/sys/src/9/port/devtinyfs.c:380,3871996/0217/sys/src/9/port/devtinyfs.c:387,397
1996/0201    
				break; 
			case Tagend: 
				f->len += GETS(mdata->bno); 
1996/0217    
				done = 1; 
1996/0201    
				break; 
			} 
1996/0217    
			if(done) 
				f->flag &= ~Fcreating; 
1996/0131    
		} 
	} 
1996/0123    
} 
1996/0206/sys/src/9/port/devtinyfs.c:569,5751996/0217/sys/src/9/port/devtinyfs.c:579,585
1996/0202    
		f = &fs->f[c->qid.path]; 
		f->r--; 
1996/0203    
		if(f->r == 0){ 
			if(f->creating){ 
1996/0217    
			if(f->flag & Fcreating){ 
1996/0203    
				/* remove all other files with this name */ 
				for(i = 0; i < fs->fsize; i++){ 
					nf = &fs->f[i]; 
1996/0206/sys/src/9/port/devtinyfs.c:601,6071996/0217/sys/src/9/port/devtinyfs.c:611,617
1996/0201    
			} 
			l = &(*l)->next; 
		} 
1996/0203    
		free(fs-f); 
1996/0217    
		free(fs->f); 
1996/0201    
		free(fs->map); 
		close(fs->c); 
1996/0203    
		memset(fs, 0, sizeof(*fs)); 
1996/0206/sys/src/9/port/devtinyfs.c:618,6261996/0217/sys/src/9/port/devtinyfs.c:628,637
1996/0206    
	ulong bno, tbno; 
	Mdata *md; 
	uchar buf[Blen]; 
1996/0217    
	uchar *p = a; 
1996/0203    
 
	if(c->qid.path & CHDIR) 
1996/0201    
		return devdirread(c, a, n, tinyfstab, Ntinyfstab, tinyfsgen); 
1996/0217    
		return devdirread(c, a, n, 0, 0, tinyfsgen); 
1996/0203    
 
	fs = tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
1996/0206/sys/src/9/port/devtinyfs.c:629,6511996/0217/sys/src/9/port/devtinyfs.c:640,672
1996/0203    
	if(n + offset >= f->length) 
		n = f->length - offset; 
1996/0206    
 
	/* walk to first data block */ 
1996/0217    
	/* walk to starting data block */ 
1996/0206    
	bno = f->dbno; 
	for(sofar = 0; sofar < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf); 
1996/0217    
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf, 0); 
1996/0206    
		if(md == 0) 
			error(Eio); 
		bno = GETS(md->bno); 
	} 
 
	/* read first block */ 
	i = offset%Blen; 
                 
	/* read data */ 
	for(sofar = 0; sofar+Blen < offset; sofar += Blen){ 
	                 
1996/0217    
	offset = offset%Blen; 
	for(sofar = 0; sofar < n; sofar += i){ 
		md = readdata(fs, bno, buf, &i); 
		if(md == 0) 
			error(Eio); 
		i -= offset; 
		if(i > n) 
			i = n; 
		if(i < 0) 
			break; 
		memmove(p, md->data, i); 
		p += i; 
		bno = GETS(md->bno); 
		offset = 0; 
	} 
1996/0203    
 
1996/0116    
	return n; 
1996/0217    
	return sofar; 
1996/0116    
} 
 
Block* 
1996/0206/sys/src/9/port/devtinyfs.c:657,6761996/0217/sys/src/9/port/devtinyfs.c:678,721
1996/0116    
long 
tinyfswrite(Chan *c, char *a, long n, ulong offset) 
{ 
	if(waserror()){ 
		qunlock(&tinyfs); 
		nexterror(); 
1996/0217    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
	ulong bno, tbno; 
	Mdata *md; 
	uchar buf[Blen]; 
	uchar *p = a; 
 
	if(c->qid.path & CHDIR) 
		error(Eperm); 
 
	fs = tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
 
	/* walk to first data block */ 
	bno = f->dbno; 
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf, 0); 
		if(md == 0) 
			error(Eio); 
		bno = GETS(md->bno); 
1996/0116    
	} 
	qlock(&tinyfs); 
	qunlock(&tinyfs); 
 
	switch(c->qid.path & ~CHDIR){ 
	case Qdata: 
		break; 
	default: 
		error(Ebadusefd); 
1996/0217    
	/* write data */ 
	offset = offset%Blen; 
	for(sofar = 0; sofar < n; sofar += i){ 
		md = readdata(fs, bno, buf, 0); 
		if(md == 0) 
			error(Eio); 
		i = Blen - offset; 
		if(i > n) 
			i = n; 
		memmove(p, a, i); 
		bno = GETS(md->bno); 
		offset = 0; 
1996/0116    
	} 
	return n; 
1996/0217    
 
	return sofar; 
1996/0116    
} 
 
long 
1996/0217/sys/src/9/port/devtinyfs.c:150,1561996/0218/sys/src/9/port/devtinyfs.c:150,156 (short | long)
1996/0201    
 
	if(checksum(p) != 0) 
		return 0; 
	if(buf[0] != Tagdir) 
1996/0218    
	if(p[0] != Tagdir) 
1996/0201    
		return 0; 
	md = (Mdir*)p; 
	x = GETS(md->bno); 
1996/0217/sys/src/9/port/devtinyfs.c:167,1741996/0218/sys/src/9/port/devtinyfs.c:167,174
1996/0201    
 
	if(checksum(p) != 0) 
		return 0; 
	md = (Mdir*)p; 
	switch(buf[0]){ 
1996/0218    
	md = (Mdata*)p; 
	switch(md->type){ 
1996/0201    
	case Tagdata: 
		x = GETS(md->bno); 
		if(x >= fs->nblocks) 
1996/0217/sys/src/9/port/devtinyfs.c:190,2141996/0218/sys/src/9/port/devtinyfs.c:190,236
1996/0206    
static Mdata* 
1996/0217    
readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp) 
1996/0206    
{ 
1996/0217    
	Mdata *md; 
                 
1996/0206    
	if(bno >= fs->nblocks) 
		return 0; 
	n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
	if(n != Blen) 
		return 0; 
1996/0218    
	if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) 
		error(Eio); 
1996/0217    
	return validdata(fs, buf, lenp); 
1996/0206    
} 
 
1996/0202    
static int 
1996/0218    
static void 
writedata(Tfs *fs, ulong bno, ulong next, uchar *buf, int len, int last) 
{ 
	Mdata md; 
 
	if(bno >= fs->nblocks) 
		error(Eio); 
	if(len > Dlen) 
		len = Dlen; 
	if(len < 0) 
		error(Eio); 
	memset(&md, 0, sizeof(md)); 
	if(last){ 
		md.type = Tagend; 
		PUTS(md.bno, len); 
	} else { 
		md.type = Tagdata; 
		PUTS(md.bno, next); 
	} 
	memmove(md.data, buf, len); 
	md.sum = 0 - checksum((uchar*)&md); 
	 
	if(devtab[fs->c->type].write(fs->c, &md, Blen, Blen*bno) != Blen) 
		error(Eio); 
} 
 
static void 
1996/0202    
writedir(Tfs *fs, Tfile *f) 
{ 
	Mdir *md; 
	int n; 
	uchar buf[Blen]; 
 
	if(f->bno == Notabno) 
		return Blen; 
1996/0218    
		return; 
1996/0202    
 
	md = (Mdir*)buf; 
	memset(buf, 0, Blen); 
1996/0217/sys/src/9/port/devtinyfs.c:216,2241996/0218/sys/src/9/port/devtinyfs.c:238,247
1996/0202    
	strncpy(md->name, f->name, sizeof(md->name)-1); 
	PUTS(md->bno, f->dbno); 
	PUTS(md->pin, f->pin); 
	f->sum = 0 - checksum(buf); 
1996/0218    
	md->sum = 0 - checksum(buf); 
1996/0202    
 
	return devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
1996/0218    
	if(devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno) != Blen) 
		error(Eio); 
1996/0202    
} 
 
1996/0201    
static void 
1996/0217/sys/src/9/port/devtinyfs.c:277,2821996/0218/sys/src/9/port/devtinyfs.c:300,306
1996/0202    
	Tfile *f; 
 
	/* find free entry in file table */ 
1996/0218    
	f = 0; 
1996/0202    
	for(;;) { 
		for(i = 0; i < fs->fsize; i++){ 
			f = &fs->f[i]; 
1996/0217/sys/src/9/port/devtinyfs.c:298,3071996/0218/sys/src/9/port/devtinyfs.c:322,331
1996/0202    
 
	/* write directory block */ 
	if(waserror()){ 
		filefree(fs, f, Notabno); 
1996/0218    
		freefile(fs, f, Notabno); 
1996/0202    
		nexterror(); 
	} 
	if(b->bno == Notabno) 
1996/0218    
	if(f->bno == Notabno) 
1996/0202    
		error("out of space"); 
	writedir(fs, f); 
	poperror(); 
1996/0217/sys/src/9/port/devtinyfs.c:317,3321996/0218/sys/src/9/port/devtinyfs.c:341,357
1996/0201    
static void 
fsinit(Tfs *fs) 
1996/0123    
{ 
1996/0131    
	uchar buf[Blen+DIRLEN]; 
1996/0218    
	char dbuf[DIRLEN]; 
1996/0123    
	Dir d; 
1996/0218    
	uchar buf[Blen]; 
1996/0131    
	ulong x, bno; 
1996/0217    
	int n, done; 
1996/0201    
	Tfile *f; 
	Mdir *mdir; 
	Mdata *mdat; 
1996/0218    
	Mdata *mdata; 
1996/0123    
 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
1996/0218    
	devtab[fs->c->type].stat(fs->c, dbuf); 
	convM2D(dbuf, &d); 
1996/0131    
	fs->nblocks = d.length/Blen; 
	if(fs->nblocks < 3) 
1996/0123    
		error("tinyfs medium too small"); 
1996/0217/sys/src/9/port/devtinyfs.c:344,3541996/0218/sys/src/9/port/devtinyfs.c:369,379
1996/0131    
		if(n != Blen) 
			break; 
1996/0201    
 
		mdir = validdir(buf); 
1996/0218    
		mdir = validdir(fs, buf); 
1996/0201    
		if(mdir == 0) 
1996/0131    
			continue; 
1996/0201    
 
1996/0217    
		if(fs->nfs >= fs->fsize) 
1996/0218    
		if(fs->nf >= fs->fsize) 
1996/0201    
			expand(fs); 
1996/0202    
 
1996/0201    
		f = &fs->f[fs->nf++]; 
1996/0217/sys/src/9/port/devtinyfs.c:363,3721996/0218/sys/src/9/port/devtinyfs.c:388,397
1996/0201    
 
	/* follow files */ 
1996/0217    
	for(f = fs->f; f < &(fs->f[fs->nf]); f++){ 
1996/0201    
		bno = fs->dbno; 
1996/0218    
		bno = f->dbno; 
1996/0217    
		for(done = 0; !done;) { 
1996/0201    
			if(isalloced(fs, bno)){ 
				freefile(f, bno); 
1996/0218    
				freefile(fs, f, bno); 
1996/0201    
				break; 
			} 
			n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
1996/0217/sys/src/9/port/devtinyfs.c:383,3921996/0218/sys/src/9/port/devtinyfs.c:408,417
1996/0201    
			switch(mdata->type){ 
			case Tagdata: 
				bno = GETS(mdata->bno); 
				f->len += Dlen; 
1996/0218    
				f->length += Dlen; 
1996/0201    
				break; 
			case Tagend: 
				f->len += GETS(mdata->bno); 
1996/0218    
				f->length += GETS(mdata->bno); 
1996/0217    
				done = 1; 
1996/0201    
				break; 
			} 
1996/0217/sys/src/9/port/devtinyfs.c:406,4111996/0218/sys/src/9/port/devtinyfs.c:431,438
1996/0201    
	Tfile *f; 
	Qid qid; 
1996/0123    
 
1996/0218    
	USED(ntab, tab); 
 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	if(i >= fs->nf) 
		return -1; 
1996/0217/sys/src/9/port/devtinyfs.c:435,4411996/0218/sys/src/9/port/devtinyfs.c:462,468
1996/0122    
	Chan *c, *cc; 
1996/0201    
	int i; 
1996/0120    
 
1996/0122    
	cc = namec((char*)arg[0], Aopen, arg[1], 0); 
1996/0218    
	cc = namec(spec, Aopen, ORDWR, 0); 
1996/0123    
	if(waserror()){ 
		close(cc); 
1996/0201    
		qunlock(&tinyfs); 
1996/0217/sys/src/9/port/devtinyfs.c:443,4511996/0218/sys/src/9/port/devtinyfs.c:470,479
1996/0123    
	} 
1996/0201    
 
1996/0122    
	qlock(&tinyfs); 
1996/0218    
	fs = 0; 
1996/0201    
	for(i = 0; i < tinyfs.nfs; i++){ 
		fs = &tinyfs.fs[i]; 
		if(fs && eqchan(c, fs->c)) 
1996/0218    
		if(fs && eqchan(cc, fs->c, 0)) 
1996/0122    
			break; 
	} 
1996/0201    
	if(i < tinyfs.nfs){ 
1996/0217/sys/src/9/port/devtinyfs.c:477,4821996/0218/sys/src/9/port/devtinyfs.c:505,514
1996/0116    
Chan * 
tinyfsclone(Chan *c, Chan *nc) 
{ 
1996/0218    
	Tfs *fs; 
 
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
	fs->r++; 
	qunlock(fs); 
1996/0217/sys/src/9/port/devtinyfs.c:488,4941996/0218/sys/src/9/port/devtinyfs.c:520,529
1996/0116    
tinyfswalk(Chan *c, char *name) 
{ 
1996/0202    
	int n; 
1996/0218    
	Tfs *fs; 
1996/0202    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
	n = devwalk(c, name, 0, 0, tinyfsgen); 
	if(n != 0 && c->qid.path != CHDIR){ 
1996/0217/sys/src/9/port/devtinyfs.c:513,5251996/0218/sys/src/9/port/devtinyfs.c:548,560
1996/0201    
 
	fs = &tinyfs.fs[c->dev]; 
 
	if(c->path & CHDIR){ 
1996/0218    
	if(c->qid.path & CHDIR){ 
1996/0201    
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
1996/0202    
		qlock(fs); 
		if(omode == (OTRUNC|ORDWR)){ 
			f = newfile(fs, fs->f[c->qid.path]); 
1996/0218    
			f = newfile(fs, fs->f[c->qid.path].name); 
1996/0202    
			c->qid.path = f - fs->f; 
		} else if(omode != OREAD){ 
			qunlock(fs); 
1996/0217/sys/src/9/port/devtinyfs.c:540,5451996/0218/sys/src/9/port/devtinyfs.c:575,582
1996/0116    
	if(perm & CHDIR) 
		error("directory creation illegal"); 
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
	f = newfile(fs, name); 
	qunlock(fs); 
1996/0217/sys/src/9/port/devtinyfs.c:570,5761996/0218/sys/src/9/port/devtinyfs.c:607,613
1996/0201    
	Tfile *f, *nf; 
1996/0202    
	int i; 
1996/0201    
 
	fs = c->aux; 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
1996/0201    
 
1996/0202    
	qlock(fs); 
1996/0201    
 
1996/0217/sys/src/9/port/devtinyfs.c:594,6001996/0218/sys/src/9/port/devtinyfs.c:631,637
1996/0203    
				} 
				f->flag &= ~(Frmonclose|Fcreating); 
1996/0202    
			} 
1996/0203    
			if(f->flag & Frmonclose){ 
1996/0218    
			if(f->flag & Frmonclose) 
1996/0203    
				freefile(fs, f, Notabno); 
1996/0202    
		} 
	} 
1996/0217/sys/src/9/port/devtinyfs.c:601,6091996/0218/sys/src/9/port/devtinyfs.c:638,646
1996/0202    
 
	/* dereference fs and remove on zero refs */ 
	fs->r--; 
1996/0203    
	unlock(fs); 
1996/0218    
	qunlock(fs); 
1996/0203    
	qlock(&tinyfs); 
1996/0201    
	if(fs->ref == 0){ 
1996/0218    
	if(fs->r == 0){ 
1996/0201    
		for(l = &fs->l; *l;){ 
			if(*l == fs){ 
				*l = fs->next; 
1996/0217/sys/src/9/port/devtinyfs.c:625,6311996/0218/sys/src/9/port/devtinyfs.c:662,668
1996/0203    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
1996/0206    
	ulong bno, tbno; 
1996/0218    
	ulong bno; 
1996/0206    
	Mdata *md; 
	uchar buf[Blen]; 
1996/0217    
	uchar *p = a; 
1996/0217/sys/src/9/port/devtinyfs.c:644,6511996/0218/sys/src/9/port/devtinyfs.c:681,686
1996/0206    
	bno = f->dbno; 
1996/0217    
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf, 0); 
1996/0206    
		if(md == 0) 
			error(Eio); 
		bno = GETS(md->bno); 
	} 
 
1996/0217/sys/src/9/port/devtinyfs.c:653,6601996/0218/sys/src/9/port/devtinyfs.c:688,693
1996/0217    
	offset = offset%Blen; 
	for(sofar = 0; sofar < n; sofar += i){ 
		md = readdata(fs, bno, buf, &i); 
		if(md == 0) 
			error(Eio); 
		i -= offset; 
		if(i > n) 
			i = n; 
1996/0217/sys/src/9/port/devtinyfs.c:680,6861996/0218/sys/src/9/port/devtinyfs.c:713,719
1996/0116    
{ 
1996/0217    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
1996/0218    
	int sofar, i, x; 
1996/0217    
	ulong bno, tbno; 
	Mdata *md; 
	uchar buf[Blen]; 
1996/0217/sys/src/9/port/devtinyfs.c:689,7191996/0218/sys/src/9/port/devtinyfs.c:722,787
1996/0217    
	if(c->qid.path & CHDIR) 
		error(Eperm); 
 
1996/0218    
	if(n == 0) 
		return 0; 
 
1996/0217    
	fs = tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
 
	/* walk to first data block */ 
1996/0218    
	/* files are append only, anything else is illegal */ 
	if(offset != f->length) 
		error("append only"); 
 
	qlock(fs); 
	if(waserror()){ 
		f->flag |= Frmonclose; 
		qunlock(fs); 
		nexterror(); 
	} 
 
	/* walk to last data block */ 
1996/0217    
	bno = f->dbno; 
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf, 0); 
		if(md == 0) 
			error(Eio); 
1996/0218    
		if(md->type == Tagend) 
			break; 
1996/0217    
		bno = GETS(md->bno); 
1996/0116    
	} 
 
1996/0217    
	/* write data */ 
	offset = offset%Blen; 
	for(sofar = 0; sofar < n; sofar += i){ 
		md = readdata(fs, bno, buf, 0); 
		if(md == 0) 
			error(Eio); 
		i = Blen - offset; 
		if(i > n) 
			i = n; 
		memmove(p, a, i); 
		bno = GETS(md->bno); 
		offset = 0; 
1996/0218    
	sofar = 0; 
	i = offset%Dlen; 
	if(i){ 
		x = n; 
		if(i + x > Dlen) 
			x = Dlen - i; 
		memmove(md->data + i, p, sofar); 
		f->length += x; 
		sofar += x; 
1996/0116    
	} 
1996/0218    
 
	while(x = n - sofar) { 
		tbno = mapalloc(fs); 
		if(f->length == 0){ 
			f->dbno = tbno; 
			writedir(fs, f); 
		} else { 
			writedata(fs, bno, tbno, md->data, Dlen, 0); 
		} 
		if(x > Dlen) 
			x = Dlen; 
		memmove(md->data, p + sofar, x); 
		sofar += x; 
		f->length += x; 
		bno = tbno; 
	} 
 
	i = f->length%Dlen; 
	if(i == 0) 
		i = Dlen; 
	writedata(fs, bno, tbno, md->data, i, 1); 
 
	poperror(); 
	qunlock(fs); 
1996/0217    
 
	return sofar; 
1996/0116    
} 
1996/0218/sys/src/9/port/devtinyfs.c:49,551996/0220/sys/src/9/port/devtinyfs.c:49,55 (short | long)
1996/0201    
struct Mdata { 
	uchar	type; 
	uchar	bno[2]; 
	char	data[Dlen]; 
1996/0220    
	uchar	data[Dlen]; 
1996/0201    
	uchar	sum; 
}; 
 
1996/0218/sys/src/9/port/devtinyfs.c:63,681996/0220/sys/src/9/port/devtinyfs.c:63,72
1996/0201    
	ushort	pin; 
1996/0203    
	uchar	flag; 
1996/0201    
	ulong	length; 
1996/0220    
 
	/* hint to avoid egregious reading */ 
	ushort	fbno; 
	ulong	finger; 
1996/0201    
}; 
 
typedef struct Tfs Tfs; 
1996/0218/sys/src/9/port/devtinyfs.c:80,861996/0220/sys/src/9/port/devtinyfs.c:84,89
1996/0122    
struct { 
	QLock; 
1996/0201    
	Tfs	fs[Maxfs]; 
	short	nfs; 
1996/0116    
} tinyfs; 
 
1996/0131    
#define GETS(x) ((x)[0]|((x)[1]<<8)) 
1996/0218/sys/src/9/port/devtinyfs.c:125,1311996/0220/sys/src/9/port/devtinyfs.c:128,133
1996/0131    
	int i, j, lim; 
	uchar x; 
 
	qlock(fs); 
	lim = (fs->nblocks + 8 - 1)/8; 
	for(i = 0; i < lim; i++){ 
		x = fs->map[i]; 
1996/0218/sys/src/9/port/devtinyfs.c:134,1451996/0220/sys/src/9/port/devtinyfs.c:136,146
1996/0131    
		for(j = 0; j < 8; j++) 
			if((x & (1<<j)) == 0){ 
				fs->map[i] = x|(1<<j); 
				qunlock(fs); 
				return i*8 + j; 
			} 
	} 
	qunlock(fs); 
	return -1; 
1996/0220    
 
	return Notabno; 
1996/0131    
} 
 
1996/0201    
static Mdir* 
1996/0218/sys/src/9/port/devtinyfs.c:245,2631996/0220/sys/src/9/port/devtinyfs.c:246,262
1996/0202    
} 
 
1996/0201    
static void 
freefile(Tfs *fs, Tfile *f, ulong bend) 
1996/0220    
freeblocks(Tfs *fs, ulong bno, ulong bend) 
1996/0201    
{ 
	uchar buf[Blen]; 
	ulong bno; 
	int n; 
	Mdata *md; 
 
	/* remove blocks from map */ 
	bno = f->dbno; 
1996/0220    
	if(waserror()) 
		return; 
 
1996/0202    
	while(bno != bend && bno != Notabno){ 
1996/0201    
		mapclr(fs, bno); 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
1996/0220    
		if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) 
1996/0201    
			break; 
1996/0217    
		md = validdata(fs, buf, 0); 
1996/0201    
		if(md == 0) 
1996/0218/sys/src/9/port/devtinyfs.c:267,2791996/0220/sys/src/9/port/devtinyfs.c:266,289
1996/0201    
		bno = GETS(md->bno); 
	} 
 
1996/0220    
	poperror(); 
} 
 
static void 
freefile(Tfs *fs, Tfile *f, ulong bend) 
{ 
	uchar buf[Blen]; 
 
	/* remove blocks from map */ 
	freeblocks(fs, f->dbno, bend); 
 
1996/0201    
	/* change file type to free on medium */ 
1996/0202    
	if(f->bno != Notabno){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno); 
		if(n != Blen) 
1996/0220    
		if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1996/0202    
			return; 
		buf[0] = Tagfree; 
		devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
1996/0220    
		mapclr(fs, f->bno); 
1996/0202    
	} 
1996/0201    
 
	/* forget we ever knew about it */ 
1996/0218/sys/src/9/port/devtinyfs.c:288,2951996/0220/sys/src/9/port/devtinyfs.c:298,307
1996/0201    
	fs->fsize += 8; 
	f = smalloc(fs->fsize*sizeof(*f)); 
 
1996/0217    
	memmove(f, fs->f, fs->nf*sizeof(f)); 
1996/0201    
	free(fs->f); 
1996/0220    
	if(fs->f){ 
		memmove(f, fs->f, fs->nf*sizeof(*f)); 
		free(fs->f); 
	} 
1996/0201    
	fs->f = f; 
} 
 
1996/0218/sys/src/9/port/devtinyfs.c:310,3171996/0220/sys/src/9/port/devtinyfs.c:322,332
1996/0202    
			} 
		} 
 
		if(i < fs->fsize) 
1996/0220    
		if(i < fs->fsize){ 
			if(i >= fs->nf) 
				fs->nf = i+1; 
1996/0202    
			break; 
1996/0220    
		} 
1996/0202    
 
		expand(fs); 
	} 
1996/0218/sys/src/9/port/devtinyfs.c:319,3241996/0220/sys/src/9/port/devtinyfs.c:334,341
1996/0203    
	f->flag = Fcreating; 
1996/0202    
	f->dbno = Notabno; 
	f->bno = mapalloc(fs); 
1996/0220    
	f->fbno = Notabno; 
	f->r = 1; 
1996/0202    
 
	/* write directory block */ 
	if(waserror()){ 
1996/0218/sys/src/9/port/devtinyfs.c:437,4421996/0220/sys/src/9/port/devtinyfs.c:454,461
1996/0201    
	if(i >= fs->nf) 
		return -1; 
	f = &fs->f[i]; 
1996/0220    
	if(f->name[0] == 0) 
		return 0; 
1996/0201    
	qid.path = i; 
	qid.vers = 0; 
1996/0202    
	devdir(c, qid, f->name, f->length, eve, 0664, dp); 
1996/0218/sys/src/9/port/devtinyfs.c:461,4971996/0220/sys/src/9/port/devtinyfs.c:480,528
1996/0201    
	Tfs *fs; 
1996/0122    
	Chan *c, *cc; 
1996/0201    
	int i; 
1996/0220    
	char *p; 
1996/0120    
 
1996/0218    
	cc = namec(spec, Aopen, ORDWR, 0); 
1996/0220    
	p = 0; 
	if(strcmp(spec, "hd0") == 0) 
		p = "#H/hd0nvram"; 
	else 
		error("bad spec"); 
 
	cc = namec(p, Aopen, ORDWR, 0); 
1996/0123    
	if(waserror()){ 
		close(cc); 
1996/0201    
		qunlock(&tinyfs); 
1996/0123    
		nexterror(); 
	} 
1996/0201    
 
1996/0122    
	qlock(&tinyfs); 
1996/0218    
	fs = 0; 
1996/0201    
	for(i = 0; i < tinyfs.nfs; i++){ 
1996/0220    
	for(i = 0; i < Maxfs; i++){ 
1996/0201    
		fs = &tinyfs.fs[i]; 
1996/0218    
		if(fs && eqchan(cc, fs->c, 0)) 
1996/0220    
		qlock(fs); 
		if(fs->r && eqchan(cc, fs->c, 0)) 
1996/0122    
			break; 
1996/0220    
		qunlock(fs); 
1996/0122    
	} 
1996/0201    
	if(i < tinyfs.nfs){ 
1996/0202    
		qlock(fs); 
1996/0220    
	if(i < Maxfs){ 
1996/0201    
		fs->r++; 
1996/0202    
		qunlock(fs); 
1996/0122    
		close(cc); 
	} else { 
1996/0201    
		if(tinyfs.nfs >= Maxfs) 
1996/0220    
		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ 
			qlock(fs); 
			if(fs->r == 0) 
				break; 
			qunlock(fs); 
		} 
		if(fs == &tinyfs.fs[Maxfs]) 
1996/0201    
			error("too many tinyfs's"); 
		fs = &tinyfs.fs[tinyfs.nfs]; 
		memset(fs, 0, sizeof(*fs)); 
1996/0122    
		fs->c = cc; 
1996/0201    
		fs->r = 1; 
1996/0220    
		fs->f = 0; 
		fs->nf = 0; 
		fs->fsize = 0; 
1996/0201    
		fsinit(fs); 
		tinyfs.nfs++; 
1996/0220    
		qunlock(fs); 
1996/0122    
	} 
1996/0201    
	qunlock(&tinyfs); 
1996/0123    
	poperror(); 
1996/0122    
 
1996/0201    
	c = devattach('U', spec); 
1996/0218/sys/src/9/port/devtinyfs.c:553,5661996/0220/sys/src/9/port/devtinyfs.c:584,607
1996/0201    
			error(Eperm); 
	} else { 
1996/0202    
		qlock(fs); 
		if(omode == (OTRUNC|ORDWR)){ 
1996/0220    
		if(waserror()){ 
			qunlock(fs); 
			nexterror(); 
		} 
		switch(omode){ 
		case OTRUNC|ORDWR: 
		case OTRUNC|OWRITE: 
1996/0218    
			f = newfile(fs, fs->f[c->qid.path].name); 
1996/0220    
			fs->f[c->qid.path].r--; 
1996/0202    
			c->qid.path = f - fs->f; 
		} else if(omode != OREAD){ 
			qunlock(fs); 
1996/0220    
			break; 
		case OREAD: 
			break; 
		default: 
1996/0202    
			error(Eperm); 
1996/0201    
		} 
1996/0202    
		qunlock(fs); 
1996/0220    
		poperror(); 
1996/0201    
	} 
 
	return devopen(c, omode, 0, 0, tinyfsgen); 
1996/0218/sys/src/9/port/devtinyfs.c:572,5851996/0220/sys/src/9/port/devtinyfs.c:613,630
1996/0201    
	Tfs *fs; 
	Tfile *f; 
1996/0116    
 
	if(perm & CHDIR) 
		error("directory creation illegal"); 
1996/0220    
	USED(perm); 
1996/0116    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
1996/0220    
	if(waserror()){ 
		qunlock(fs); 
		nexterror(); 
	} 
1996/0202    
	f = newfile(fs, name); 
	qunlock(fs); 
1996/0220    
	poperror(); 
1996/0201    
 
	c->qid.path = f - fs->f; 
1996/0202    
	c->qid.vers = 0; 
1996/0218/sys/src/9/port/devtinyfs.c:589,5961996/0220/sys/src/9/port/devtinyfs.c:634,649
1996/0116    
void 
tinyfsremove(Chan *c) 
{ 
	USED(c); 
	error(Eperm); 
1996/0220    
	Tfs *fs; 
	Tfile *f; 
 
	if(c->qid.path == CHDIR) 
		error(Eperm); 
	fs = &tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
	qlock(fs); 
	freefile(fs, f, Notabno); 
	qunlock(fs); 
1996/0116    
} 
 
void 
1996/0218/sys/src/9/port/devtinyfs.c:603,6091996/0220/sys/src/9/port/devtinyfs.c:656,662
1996/0116    
void 
tinyfsclose(Chan *c) 
{ 
1996/0201    
	Tfs *fs, **l; 
1996/0220    
	Tfs *fs; 
1996/0201    
	Tfile *f, *nf; 
1996/0202    
	int i; 
1996/0201    
 
1996/0218/sys/src/9/port/devtinyfs.c:612,6591996/0220/sys/src/9/port/devtinyfs.c:665,712
1996/0202    
	qlock(fs); 
1996/0201    
 
1996/0202    
	/* dereference file and remove old versions */ 
	if(c->qid.path != CHDIR){ 
		f = &fs->f[c->qid.path]; 
		f->r--; 
1996/0203    
		if(f->r == 0){ 
1996/0217    
			if(f->flag & Fcreating){ 
1996/0203    
				/* remove all other files with this name */ 
				for(i = 0; i < fs->fsize; i++){ 
					nf = &fs->f[i]; 
					if(f == nf) 
						continue; 
					if(strcmp(nf->name, f->name) == 0){ 
						if(nf->r) 
							nf->flag |= Frmonclose; 
						else 
							freefile(fs, nf, Notabno); 
1996/0220    
	if(!waserror()){ 
		if(c->qid.path != CHDIR){ 
			f = &fs->f[c->qid.path]; 
			f->r--; 
			if(f->r == 0){ 
				if(f->flag & Frmonclose) 
					freefile(fs, f, Notabno); 
				else if(f->flag & Fcreating){ 
					/* remove all other files with this name */ 
					for(i = 0; i < fs->fsize; i++){ 
						nf = &fs->f[i]; 
						if(f == nf) 
							continue; 
						if(strcmp(nf->name, f->name) == 0){ 
							if(nf->r) 
								nf->flag |= Frmonclose; 
							else 
								freefile(fs, nf, Notabno); 
						} 
1996/0203    
					} 
1996/0220    
					f->flag &= ~Fcreating; 
1996/0203    
				} 
				f->flag &= ~(Frmonclose|Fcreating); 
1996/0202    
			} 
1996/0218    
			if(f->flag & Frmonclose) 
1996/0203    
				freefile(fs, f, Notabno); 
1996/0202    
		} 
1996/0220    
		poperror(); 
1996/0202    
	} 
 
	/* dereference fs and remove on zero refs */ 
	fs->r--; 
1996/0218    
	qunlock(fs); 
1996/0203    
	qlock(&tinyfs); 
1996/0218    
	if(fs->r == 0){ 
1996/0201    
		for(l = &fs->l; *l;){ 
			if(*l == fs){ 
				*l = fs->next; 
				break; 
			} 
			l = &(*l)->next; 
		} 
1996/0217    
		free(fs->f); 
1996/0201    
		free(fs->map); 
1996/0220    
		if(fs->f) 
			free(fs->f); 
		fs->f = 0; 
		fs->nf = 0; 
		fs->fsize = 0; 
		if(fs->map) 
			free(fs->map); 
		fs->map = 0; 
1996/0201    
		close(fs->c); 
1996/0203    
		memset(fs, 0, sizeof(*fs)); 
1996/0220    
		fs->c = 0; 
1996/0201    
	} 
	qunlock(&tinyfs); 
1996/0220    
	qunlock(fs); 
1996/0116    
} 
 
long 
1996/0218/sys/src/9/port/devtinyfs.c:661,6671996/0220/sys/src/9/port/devtinyfs.c:714,720
1996/0116    
{ 
1996/0203    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
1996/0220    
	int sofar, i, off; 
1996/0218    
	ulong bno; 
1996/0206    
	Mdata *md; 
	uchar buf[Blen]; 
1996/0218/sys/src/9/port/devtinyfs.c:670,7031996/0220/sys/src/9/port/devtinyfs.c:723,778
1996/0203    
	if(c->qid.path & CHDIR) 
1996/0217    
		return devdirread(c, a, n, 0, 0, tinyfsgen); 
1996/0203    
 
	fs = tinyfs.fs[c->dev]; 
1996/0220    
	fs = &tinyfs.fs[c->dev]; 
1996/0203    
	f = &fs->f[c->qid.path]; 
	if(offset >= f->length) 
		return 0; 
1996/0220    
 
	qlock(fs); 
	if(waserror()){ 
		qunlock(fs); 
		nexterror(); 
	} 
1996/0203    
	if(n + offset >= f->length) 
		n = f->length - offset; 
1996/0206    
 
1996/0217    
	/* walk to starting data block */ 
1996/0206    
	bno = f->dbno; 
1996/0217    
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){ 
1996/0220    
	if(f->finger < offset && f->fbno != Notabno){ 
		sofar = f->finger; 
		bno = f->fbno; 
	} else { 
		sofar = 0; 
		bno = f->dbno; 
	} 
	for(; sofar + Dlen < offset; sofar += Dlen){ 
1996/0217    
		md = readdata(fs, bno, buf, 0); 
1996/0220    
		if(md == 0) 
			error(Eio); 
1996/0206    
		bno = GETS(md->bno); 
	} 
 
	/* read data */ 
1996/0217    
	offset = offset%Blen; 
1996/0220    
	off = offset%Dlen; 
	offset -= off; 
1996/0217    
	for(sofar = 0; sofar < n; sofar += i){ 
		md = readdata(fs, bno, buf, &i); 
		i -= offset; 
1996/0220    
		if(md == 0) 
			error(Eio); 
 
		/* update finger for successful read */ 
		f->finger = offset + sofar; 
		f->fbno = bno; 
 
		i -= off; 
1996/0217    
		if(i > n) 
			i = n; 
		if(i < 0) 
			break; 
		memmove(p, md->data, i); 
		p += i; 
		bno = GETS(md->bno); 
		offset = 0; 
1996/0220    
		off = 0; 
1996/0217    
	} 
1996/0220    
	qunlock(fs); 
	poperror(); 
1996/0203    
 
1996/0217    
	return sofar; 
1996/0116    
} 
1996/0218/sys/src/9/port/devtinyfs.c:708,7201996/0220/sys/src/9/port/devtinyfs.c:783,799
1996/0116    
	return devbread(c, n, offset); 
} 
 
1996/0220    
/* 
 *  if we get a write error in this routine, blocks will 
 *  be lost.  They should be recovered next fsinit. 
 */ 
1996/0116    
long 
tinyfswrite(Chan *c, char *a, long n, ulong offset) 
1996/0220    
tinyfswrite(Chan *c, void *a, long n, ulong offset) 
1996/0116    
{ 
1996/0217    
	Tfs *fs; 
	Tfile *f; 
1996/0218    
	int sofar, i, x; 
1996/0217    
	ulong bno, tbno; 
1996/0220    
	int last, next, i, off, finger; 
	ulong bno, dbno, fbno; 
1996/0217    
	Mdata *md; 
	uchar buf[Blen]; 
	uchar *p = a; 
1996/0218/sys/src/9/port/devtinyfs.c:725,7311996/0220/sys/src/9/port/devtinyfs.c:804,810
1996/0218    
	if(n == 0) 
		return 0; 
 
1996/0217    
	fs = tinyfs.fs[c->dev]; 
1996/0220    
	fs = &tinyfs.fs[c->dev]; 
1996/0217    
	f = &fs->f[c->qid.path]; 
 
1996/0218    
	/* files are append only, anything else is illegal */ 
1996/0218/sys/src/9/port/devtinyfs.c:733,7891996/0220/sys/src/9/port/devtinyfs.c:812,889
1996/0218    
		error("append only"); 
 
	qlock(fs); 
1996/0220    
	dbno = Notabno; 
1996/0218    
	if(waserror()){ 
		f->flag |= Frmonclose; 
1996/0220    
		freeblocks(fs, dbno, Notabno); 
1996/0218    
		qunlock(fs); 
		nexterror(); 
	} 
 
1996/0220    
	/* write blocks backwards */ 
	p += n; 
	last = offset + n; 
	off = offset; 
	fbno = Notabno; 
	finger = 0; 
	for(next = (last/Dlen)*Dlen; next >= off; next -= Dlen){ 
		bno = mapalloc(fs); 
		if(bno == Notabno){ 
			error("out of space"); 
		} 
		i = last - next; 
		p -= i; 
		if(last == n+offset){ 
			writedata(fs, bno, dbno, p, i, 1); 
			finger = next;	/* remember for later */ 
			fbno = bno; 
		} else 
			writedata(fs, bno, dbno, p, i, 0); 
		dbno = bno; 
		last = next; 
	} 
 
1996/0218    
	/* walk to last data block */ 
1996/0217    
	bno = f->dbno; 
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){ 
1996/0220    
	md = (Mdata*)buf; 
	if(f->finger < offset && f->fbno != Notabno){ 
		next = f->finger; 
		bno = f->fbno; 
	} else { 
		next = 0; 
		bno = f->dbno; 
	} 
	for(; next < offset; next += Dlen){ 
1996/0217    
		md = readdata(fs, bno, buf, 0); 
1996/0220    
		if(md == 0) 
			error(Eio); 
1996/0218    
		if(md->type == Tagend) 
			break; 
1996/0217    
		bno = GETS(md->bno); 
1996/0116    
	} 
 
1996/0218    
	sofar = 0; 
	i = offset%Dlen; 
	if(i){ 
		x = n; 
		if(i + x > Dlen) 
			x = Dlen - i; 
		memmove(md->data + i, p, sofar); 
		f->length += x; 
		sofar += x; 
1996/0116    
	} 
1996/0218    
                 
	while(x = n - sofar) { 
		tbno = mapalloc(fs); 
		if(f->length == 0){ 
			f->dbno = tbno; 
			writedir(fs, f); 
		} else { 
			writedata(fs, bno, tbno, md->data, Dlen, 0); 
1996/0220    
	/* point to new blocks */ 
	if(offset == 0){ 
		f->dbno = dbno; 
		writedir(fs, f); 
	} else { 
		i = last - offset; 
		next = offset%Dlen; 
		if(i > 0){ 
			p -= i; 
			memmove(md->data + next, p, i); 
1996/0218    
		} 
		if(x > Dlen) 
			x = Dlen; 
		memmove(md->data, p + sofar, x); 
		sofar += x; 
		f->length += x; 
		bno = tbno; 
1996/0220    
		writedata(fs, bno, dbno, md->data, i+next, last == n+offset); 
1996/0218    
	} 
1996/0220    
	f->length += n; 
1996/0218    
 
	i = f->length%Dlen; 
	if(i == 0) 
		i = Dlen; 
	writedata(fs, bno, tbno, md->data, i, 1); 
                 
1996/0220    
	/* update finger */ 
	if(fbno != Notabno){ 
		f->finger = finger; 
		f->fbno =  fbno; 
	} 
1996/0218    
	poperror(); 
	qunlock(fs); 
1996/0217    
 
	return sofar; 
1996/0220    
	return n; 
1996/0116    
} 
 
long 
1996/0220/sys/src/9/port/devtinyfs.c:483,4901996/0221/sys/src/9/port/devtinyfs.c:483,496 (short | long)
1996/0220    
	char *p; 
1996/0120    
 
1996/0220    
	p = 0; 
	if(strcmp(spec, "hd0") == 0) 
1996/0221    
	if(strncmp(spec, "hd0") == 0) 
1996/0220    
		p = "#H/hd0nvram"; 
1996/0221    
	else if(strncmp(spec, "hd1") == 0) 
		p = "#H/hd1nvram"; 
	else if(strncmp(spec, "sd0") == 0) 
		p = "#H/sd0nvram"; 
	else if(strncmp(spec, "sd1") == 0) 
		p = "#H/sd1nvram"; 
1996/0220    
	else 
		error("bad spec"); 
 
1996/0221/sys/src/9/port/devtinyfs.c:9,151996/0223/sys/src/9/port/devtinyfs.c:9,14 (short | long)
1996/0116    
#include	"fns.h" 
#include	"../port/error.h" 
 
#include	"devtab.h" 
 
enum{ 
	Qdir, 
1996/0223/sys/src/9/port/devtinyfs.c:54,601996/0226/sys/src/9/port/devtinyfs.c:54,59 (short | long)
1996/0201    
 
typedef struct Tfile Tfile; 
struct Tfile { 
1996/0206    
	Lock; 
1996/0202    
	int	r; 
1996/0201    
	char	name[NAMELEN]; 
	ushort	bno; 
1996/0223/sys/src/9/port/devtinyfs.c:70,761996/0226/sys/src/9/port/devtinyfs.c:69,75
1996/0201    
 
typedef struct Tfs Tfs; 
struct Tfs { 
1996/0202    
	QLock; 
1996/0226    
	QLock	ql; 
1996/0201    
	int	r; 
1996/0116    
	Chan	*c; 
1996/0131    
	uchar	*map; 
1996/0223/sys/src/9/port/devtinyfs.c:81,871996/0226/sys/src/9/port/devtinyfs.c:80,85
1996/0122    
}; 
 
struct { 
	QLock; 
1996/0201    
	Tfs	fs[Maxfs]; 
1996/0116    
} tinyfs; 
 
1996/0223/sys/src/9/port/devtinyfs.c:482,4951996/0226/sys/src/9/port/devtinyfs.c:480,493
1996/0220    
	char *p; 
1996/0120    
 
1996/0220    
	p = 0; 
1996/0221    
	if(strncmp(spec, "hd0") == 0) 
1996/0220    
		p = "#H/hd0nvram"; 
1996/0221    
	else if(strncmp(spec, "hd1") == 0) 
		p = "#H/hd1nvram"; 
	else if(strncmp(spec, "sd0") == 0) 
		p = "#H/sd0nvram"; 
	else if(strncmp(spec, "sd1") == 0) 
		p = "#H/sd1nvram"; 
1996/0226    
	if(strncmp(spec, "hd0", 3) == 0) 
		p = "/dev/hd0nvram"; 
	else if(strncmp(spec, "hd1", 3) == 0) 
		p = "/dev/hd1nvram"; 
	else if(strncmp(spec, "sd0", 3) == 0) 
		p = "/dev/sd0nvram"; 
	else if(strncmp(spec, "sd1", 3) == 0) 
		p = "/dev/sd1nvram"; 
1996/0220    
	else 
		error("bad spec"); 
 
1996/0223/sys/src/9/port/devtinyfs.c:502,5221996/0226/sys/src/9/port/devtinyfs.c:500,520
1996/0218    
	fs = 0; 
1996/0220    
	for(i = 0; i < Maxfs; i++){ 
1996/0201    
		fs = &tinyfs.fs[i]; 
1996/0220    
		qlock(fs); 
1996/0226    
		qlock(&fs->ql); 
1996/0220    
		if(fs->r && eqchan(cc, fs->c, 0)) 
1996/0122    
			break; 
1996/0220    
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
	} 
1996/0220    
	if(i < Maxfs){ 
1996/0201    
		fs->r++; 
1996/0202    
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
		close(cc); 
	} else { 
1996/0220    
		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ 
			qlock(fs); 
1996/0226    
			qlock(&fs->ql); 
1996/0220    
			if(fs->r == 0) 
				break; 
			qunlock(fs); 
1996/0226    
			qunlock(&fs->ql); 
1996/0220    
		} 
		if(fs == &tinyfs.fs[Maxfs]) 
1996/0201    
			error("too many tinyfs's"); 
1996/0223/sys/src/9/port/devtinyfs.c:526,5321996/0226/sys/src/9/port/devtinyfs.c:524,530
1996/0220    
		fs->nf = 0; 
		fs->fsize = 0; 
1996/0201    
		fsinit(fs); 
1996/0220    
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
	} 
1996/0123    
	poperror(); 
1996/0122    
 
1996/0223/sys/src/9/port/devtinyfs.c:545,5531996/0226/sys/src/9/port/devtinyfs.c:543,551
1996/0218    
 
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0202    
	fs->r++; 
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0202    
 
1996/0116    
	return devclone(c, nc); 
} 
1996/0223/sys/src/9/port/devtinyfs.c:560,5721996/0226/sys/src/9/port/devtinyfs.c:558,570
1996/0202    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0202    
	n = devwalk(c, name, 0, 0, tinyfsgen); 
	if(n != 0 && c->qid.path != CHDIR){ 
		fs = &tinyfs.fs[c->dev]; 
		fs->f[c->qid.path].r++; 
	} 
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0202    
	return n; 
1996/0116    
} 
 
1996/0223/sys/src/9/port/devtinyfs.c:588,5961996/0226/sys/src/9/port/devtinyfs.c:586,594
1996/0201    
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
1996/0202    
		qlock(fs); 
1996/0226    
		qlock(&fs->ql); 
1996/0220    
		if(waserror()){ 
			qunlock(fs); 
1996/0226    
			qunlock(&fs->ql); 
1996/0220    
			nexterror(); 
		} 
		switch(omode){ 
1996/0223/sys/src/9/port/devtinyfs.c:605,6111996/0226/sys/src/9/port/devtinyfs.c:603,609
1996/0220    
		default: 
1996/0202    
			error(Eperm); 
1996/0201    
		} 
1996/0202    
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0220    
		poperror(); 
1996/0201    
	} 
 
1996/0223/sys/src/9/port/devtinyfs.c:622,6341996/0226/sys/src/9/port/devtinyfs.c:620,632
1996/0116    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
 
1996/0202    
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0220    
	if(waserror()){ 
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0220    
		nexterror(); 
	} 
1996/0202    
	f = newfile(fs, name); 
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0220    
	poperror(); 
1996/0201    
 
	c->qid.path = f - fs->f; 
1996/0223/sys/src/9/port/devtinyfs.c:646,6541996/0226/sys/src/9/port/devtinyfs.c:644,652
1996/0220    
		error(Eperm); 
	fs = &tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0220    
	freefile(fs, f, Notabno); 
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0116    
} 
 
void 
1996/0223/sys/src/9/port/devtinyfs.c:667,6731996/0226/sys/src/9/port/devtinyfs.c:665,671
1996/0201    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
1996/0201    
 
1996/0202    
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0201    
 
1996/0202    
	/* dereference file and remove old versions */ 
1996/0220    
	if(!waserror()){ 
1996/0223/sys/src/9/port/devtinyfs.c:711,7171996/0226/sys/src/9/port/devtinyfs.c:709,715
1996/0201    
		close(fs->c); 
1996/0220    
		fs->c = 0; 
1996/0201    
	} 
1996/0220    
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0116    
} 
 
long 
1996/0223/sys/src/9/port/devtinyfs.c:733,7411996/0226/sys/src/9/port/devtinyfs.c:731,739
1996/0203    
	if(offset >= f->length) 
		return 0; 
1996/0220    
 
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0220    
	if(waserror()){ 
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0220    
		nexterror(); 
	} 
1996/0203    
	if(n + offset >= f->length) 
1996/0223/sys/src/9/port/devtinyfs.c:776,7821996/0226/sys/src/9/port/devtinyfs.c:774,780
1996/0217    
		bno = GETS(md->bno); 
1996/0220    
		off = 0; 
1996/0217    
	} 
1996/0220    
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0220    
	poperror(); 
1996/0203    
 
1996/0217    
	return sofar; 
1996/0223/sys/src/9/port/devtinyfs.c:816,8261996/0226/sys/src/9/port/devtinyfs.c:814,824
1996/0218    
	if(offset != f->length) 
		error("append only"); 
 
	qlock(fs); 
1996/0226    
	qlock(&fs->ql); 
1996/0220    
	dbno = Notabno; 
1996/0218    
	if(waserror()){ 
1996/0220    
		freeblocks(fs, dbno, Notabno); 
1996/0218    
		qunlock(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0218    
		nexterror(); 
	} 
 
1996/0223/sys/src/9/port/devtinyfs.c:886,8921996/0226/sys/src/9/port/devtinyfs.c:884,890
1996/0220    
		f->fbno =  fbno; 
	} 
1996/0218    
	poperror(); 
	qunlock(fs); 
1996/0226    
	qunlock(&fs->ql); 
1996/0217    
 
1996/0220    
	return n; 
1996/0116    
} 
1996/0226/sys/src/9/port/devtinyfs.c:190,1961997/0327/sys/src/9/port/devtinyfs.c:190,196 (short | long)
1996/0206    
{ 
	if(bno >= fs->nblocks) 
		return 0; 
1996/0218    
	if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) 
1997/0327    
	if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) 
1996/0218    
		error(Eio); 
1996/0217    
	return validdata(fs, buf, lenp); 
1996/0206    
} 
1996/0226/sys/src/9/port/devtinyfs.c:217,2231997/0327/sys/src/9/port/devtinyfs.c:217,223
1996/0218    
	memmove(md.data, buf, len); 
	md.sum = 0 - checksum((uchar*)&md); 
	 
	if(devtab[fs->c->type].write(fs->c, &md, Blen, Blen*bno) != Blen) 
1997/0327    
	if(devtab[fs->c->type]->write(fs->c, &md, Blen, Blen*bno) != Blen) 
1996/0218    
		error(Eio); 
} 
 
1996/0226/sys/src/9/port/devtinyfs.c:238,2441997/0327/sys/src/9/port/devtinyfs.c:238,244
1996/0202    
	PUTS(md->pin, f->pin); 
1996/0218    
	md->sum = 0 - checksum(buf); 
1996/0202    
 
1996/0218    
	if(devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1997/0327    
	if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1996/0218    
		error(Eio); 
1996/0202    
} 
 
1996/0226/sys/src/9/port/devtinyfs.c:253,2591997/0327/sys/src/9/port/devtinyfs.c:253,259
1996/0220    
 
1996/0202    
	while(bno != bend && bno != Notabno){ 
1996/0201    
		mapclr(fs, bno); 
1996/0220    
		if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) 
1997/0327    
		if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) 
1996/0201    
			break; 
1996/0217    
		md = validdata(fs, buf, 0); 
1996/0201    
		if(md == 0) 
1996/0226/sys/src/9/port/devtinyfs.c:276,2851997/0327/sys/src/9/port/devtinyfs.c:276,285
1996/0220    
 
1996/0201    
	/* change file type to free on medium */ 
1996/0202    
	if(f->bno != Notabno){ 
1996/0220    
		if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1997/0327    
		if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1996/0202    
			return; 
		buf[0] = Tagfree; 
		devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
1997/0327    
		devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno); 
1996/0220    
		mapclr(fs, f->bno); 
1996/0202    
	} 
1996/0201    
 
1996/0226/sys/src/9/port/devtinyfs.c:364,3701997/0327/sys/src/9/port/devtinyfs.c:364,370
1996/0201    
	Mdir *mdir; 
1996/0218    
	Mdata *mdata; 
1996/0123    
 
1996/0218    
	devtab[fs->c->type].stat(fs->c, dbuf); 
1997/0327    
	devtab[fs->c->type]->stat(fs->c, dbuf); 
1996/0218    
	convM2D(dbuf, &d); 
1996/0131    
	fs->nblocks = d.length/Blen; 
	if(fs->nblocks < 3) 
1996/0226/sys/src/9/port/devtinyfs.c:379,3851997/0327/sys/src/9/port/devtinyfs.c:379,385
1996/0123    
 
1996/0201    
	/* find files */ 
1996/0131    
	for(bno = 0; bno < fs->nblocks; bno++){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
1997/0327    
		n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); 
1996/0131    
		if(n != Blen) 
			break; 
1996/0201    
 
1996/0226/sys/src/9/port/devtinyfs.c:408,4141997/0327/sys/src/9/port/devtinyfs.c:408,414
1996/0218    
				freefile(fs, f, bno); 
1996/0201    
				break; 
			} 
			n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
1997/0327    
			n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); 
1996/0201    
			if(n != Blen){ 
				freefile(fs, f, bno); 
				break; 
1996/0226/sys/src/9/port/devtinyfs.c:459,4651997/0327/sys/src/9/port/devtinyfs.c:459,465
1996/0201    
	return 1; 
1996/0123    
} 
 
1996/0201    
void 
1997/0327    
static void 
1996/0201    
tinyfsreset(void) 
{ 
	if(Nlen > NAMELEN) 
1996/0226/sys/src/9/port/devtinyfs.c:466,4771997/0327/sys/src/9/port/devtinyfs.c:466,472
1996/0201    
		panic("tinyfsreset"); 
} 
 
void 
tinyfsinit(void) 
{ 
} 
                 
1996/0116    
Chan * 
1997/0327    
static Chan* 
1996/0116    
tinyfsattach(char *spec) 
{ 
1996/0201    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:493,4991997/0327/sys/src/9/port/devtinyfs.c:488,494
1996/0220    
 
	cc = namec(p, Aopen, ORDWR, 0); 
1996/0123    
	if(waserror()){ 
		close(cc); 
1997/0327    
		cclose(cc); 
1996/0123    
		nexterror(); 
	} 
1996/0201    
 
1996/0226/sys/src/9/port/devtinyfs.c:508,5141997/0327/sys/src/9/port/devtinyfs.c:503,509
1996/0220    
	if(i < Maxfs){ 
1996/0201    
		fs->r++; 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
		close(cc); 
1997/0327    
		cclose(cc); 
1996/0122    
	} else { 
1996/0220    
		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ 
1996/0226    
			qlock(&fs->ql); 
1996/0226/sys/src/9/port/devtinyfs.c:536,5421997/0327/sys/src/9/port/devtinyfs.c:531,537
1996/0122    
	return c; 
1996/0116    
} 
 
Chan * 
1997/0327    
static Chan* 
1996/0116    
tinyfsclone(Chan *c, Chan *nc) 
{ 
1996/0218    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:550,5561997/0327/sys/src/9/port/devtinyfs.c:545,551
1996/0116    
	return devclone(c, nc); 
} 
 
int 
1997/0327    
static int 
1996/0116    
tinyfswalk(Chan *c, char *name) 
{ 
1996/0202    
	int n; 
1996/0226/sys/src/9/port/devtinyfs.c:568,5801997/0327/sys/src/9/port/devtinyfs.c:563,575
1996/0202    
	return n; 
1996/0116    
} 
 
void 
1997/0327    
static void 
1996/0116    
tinyfsstat(Chan *c, char *db) 
{ 
1996/0201    
	devstat(c, db, 0, 0, tinyfsgen); 
1996/0116    
} 
 
Chan * 
1997/0327    
static Chan* 
1996/0116    
tinyfsopen(Chan *c, int omode) 
{ 
1996/0201    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:610,6161997/0327/sys/src/9/port/devtinyfs.c:605,611
1996/0201    
	return devopen(c, omode, 0, 0, tinyfsgen); 
1996/0116    
} 
 
void 
1997/0327    
static void 
1996/0116    
tinyfscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1996/0201    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:634,6401997/0327/sys/src/9/port/devtinyfs.c:629,635
1996/0116    
	c->mode = openmode(omode); 
} 
 
void 
1997/0327    
static void 
1996/0116    
tinyfsremove(Chan *c) 
{ 
1996/0220    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:649,6621997/0327/sys/src/9/port/devtinyfs.c:644,650
1996/0226    
	qunlock(&fs->ql); 
1996/0116    
} 
 
void 
tinyfswstat(Chan *c, char *dp) 
{ 
	USED(c, dp); 
	error(Eperm); 
} 
                 
void 
1997/0327    
static void 
1996/0116    
tinyfsclose(Chan *c) 
{ 
1996/0220    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:706,7181997/0327/sys/src/9/port/devtinyfs.c:694,706
1996/0220    
		if(fs->map) 
			free(fs->map); 
		fs->map = 0; 
1996/0201    
		close(fs->c); 
1997/0327    
		cclose(fs->c); 
1996/0220    
		fs->c = 0; 
1996/0201    
	} 
1996/0226    
	qunlock(&fs->ql); 
1996/0116    
} 
 
long 
1997/0327    
static long 
1996/0116    
tinyfsread(Chan *c, void *a, long n, ulong offset) 
{ 
1996/0203    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:780,7961997/0327/sys/src/9/port/devtinyfs.c:768,778
1996/0217    
	return sofar; 
1996/0116    
} 
 
Block* 
tinyfsbread(Chan *c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
                 
1996/0220    
/* 
 *  if we get a write error in this routine, blocks will 
 *  be lost.  They should be recovered next fsinit. 
 */ 
1996/0116    
long 
1997/0327    
static long 
1996/0220    
tinyfswrite(Chan *c, void *a, long n, ulong offset) 
1996/0116    
{ 
1996/0217    
	Tfs *fs; 
1996/0226/sys/src/9/port/devtinyfs.c:889,8961997/0327/sys/src/9/port/devtinyfs.c:871,890
1996/0220    
	return n; 
1996/0116    
} 
 
long 
tinyfsbwrite(Chan *c, Block *bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
} 
1997/0327    
Dev tinyfsdevtab = { 
	tinyfsreset, 
	devinit, 
	tinyfsattach, 
	tinyfsclone, 
	tinyfswalk, 
	tinyfsstat, 
	tinyfsopen, 
	tinyfscreate, 
	tinyfsclose, 
	tinyfsread, 
	devbread, 
	tinyfswrite, 
	devbwrite, 
	tinyfsremove, 
	devwstat, 
}; 
1997/0327/sys/src/9/port/devtinyfs.c:872,8771997/0408/sys/src/9/port/devtinyfs.c:872,880 (short | long)
1996/0116    
} 
 
1997/0327    
Dev tinyfsdevtab = { 
1997/0408    
	'U', 
	"tinyfs", 
 
1997/0327    
	tinyfsreset, 
	devinit, 
	tinyfsattach, 
1997/0408/sys/src/9/port/devtinyfs.c:1,151999/0612/sys/src/9/port/devtinyfs.c:1,13 (short | long)
1996/0116    
/* 
1996/0202    
 *  a pity the code isn't also tiny... 
1996/0116    
 */ 
1999/0612    
#include "u.h" 
#include "../port/lib.h" 
#include "../port/error.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
1996/0116    
 
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
                 
                 
enum{ 
	Qdir, 
1996/0120    
	Qmedium, 
1997/0408/sys/src/9/port/devtinyfs.c:29,351999/0612/sys/src/9/port/devtinyfs.c:27,33
1996/0202    
	Notabno=		0xffff, 
1996/0203    
 
	Fcreating=	1, 
	Frmonclose=	2, 
1999/0612    
	Frmonclose=	2 
1996/0116    
}; 
 
1996/0202    
/* representation of a Tdir on medium */ 
1997/0408/sys/src/9/port/devtinyfs.c:181,1861999/0612/sys/src/9/port/devtinyfs.c:179,186
1996/0217    
		if(lenp) 
			*lenp = x; 
1996/0201    
		break; 
1999/0612    
	default: 
		return 0; 
1996/0201    
	} 
	return md; 
} 
1997/0408/sys/src/9/port/devtinyfs.c:237,2431999/0612/sys/src/9/port/devtinyfs.c:237,243
1996/0202    
	PUTS(md->bno, f->dbno); 
	PUTS(md->pin, f->pin); 
1996/0218    
	md->sum = 0 - checksum(buf); 
1996/0202    
                 
1999/0612    
	 
1997/0327    
	if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1996/0218    
		error(Eio); 
1996/0202    
} 
1997/0408/sys/src/9/port/devtinyfs.c:276,2841999/0612/sys/src/9/port/devtinyfs.c:276,282
1996/0220    
 
1996/0201    
	/* change file type to free on medium */ 
1996/0202    
	if(f->bno != Notabno){ 
1997/0327    
		if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1996/0202    
			return; 
		buf[0] = Tagfree; 
1999/0612    
		memset(buf, 0x55, Blen); 
1997/0327    
		devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno); 
1996/0220    
		mapclr(fs, f->bno); 
1996/0202    
	} 
1997/0408/sys/src/9/port/devtinyfs.c:293,2991999/0612/sys/src/9/port/devtinyfs.c:291,297
1996/0201    
	Tfile *f; 
 
	fs->fsize += 8; 
	f = smalloc(fs->fsize*sizeof(*f)); 
1999/0612    
	f = malloc(fs->fsize*sizeof(*f)); 
1996/0201    
 
1996/0220    
	if(fs->f){ 
		memmove(f, fs->f, fs->nf*sizeof(*f)); 
1997/0408/sys/src/9/port/devtinyfs.c:306,3501999/0612/sys/src/9/port/devtinyfs.c:304,353
1996/0202    
newfile(Tfs *fs, char *name) 
{ 
	int i; 
	Tfile *f; 
1999/0612    
	volatile struct { 
		Tfile *f; 
		Tfs *fs; 
	} rock; 
1996/0202    
 
	/* find free entry in file table */ 
1996/0218    
	f = 0; 
1999/0612    
	rock.f = 0; 
	rock.fs = fs; 
1996/0202    
	for(;;) { 
		for(i = 0; i < fs->fsize; i++){ 
			f = &fs->f[i]; 
			if(f->name[0] == 0){ 
				strncpy(f->name, name, sizeof(f->name)-1); 
1999/0612    
		for(i = 0; i < rock.fs->fsize; i++){ 
			rock.f = &rock.fs->f[i]; 
			if(rock.f->name[0] == 0){ 
				strncpy(rock.f->name, name, sizeof(rock.f->name)-1); 
1996/0202    
				break; 
			} 
		} 
 
1996/0220    
		if(i < fs->fsize){ 
			if(i >= fs->nf) 
				fs->nf = i+1; 
1999/0612    
		if(i < rock.fs->fsize){ 
			if(i >= rock.fs->nf) 
				rock.fs->nf = i+1; 
1996/0202    
			break; 
1996/0220    
		} 
1996/0202    
 
		expand(fs); 
1999/0612    
		expand(rock.fs); 
1996/0202    
	} 
 
1996/0203    
	f->flag = Fcreating; 
1996/0202    
	f->dbno = Notabno; 
	f->bno = mapalloc(fs); 
1996/0220    
	f->fbno = Notabno; 
	f->r = 1; 
1999/0612    
	rock.f->flag = Fcreating; 
	rock.f->dbno = Notabno; 
	rock.f->bno = mapalloc(rock.fs); 
	rock.f->fbno = Notabno; 
	rock.f->r = 1; 
	rock.f->pin = Notapin;  // what is a pin?? 
1996/0202    
 
	/* write directory block */ 
	if(waserror()){ 
1996/0218    
		freefile(fs, f, Notabno); 
1999/0612    
		freefile(rock.fs, rock.f, Notabno); 
1996/0202    
		nexterror(); 
	} 
1996/0218    
	if(f->bno == Notabno) 
1999/0612    
	if(rock.f->bno == Notabno) 
1996/0202    
		error("out of space"); 
	writedir(fs, f); 
1999/0612    
	writedir(rock.fs, rock.f); 
1996/0202    
	poperror(); 
	 
	return f; 
1999/0612    
	return rock.f; 
1996/0202    
} 
 
1996/0123    
/* 
1997/0408/sys/src/9/port/devtinyfs.c:353,3591999/0612/sys/src/9/port/devtinyfs.c:356,362
1996/0217    
 *  had better be small or this could take a while. 
1996/0123    
 */ 
1996/0201    
static void 
fsinit(Tfs *fs) 
1999/0612    
tfsinit(Tfs *fs) 
1996/0123    
{ 
1996/0218    
	char dbuf[DIRLEN]; 
1996/0123    
	Dir d; 
1997/0408/sys/src/9/port/devtinyfs.c:372,3781999/0612/sys/src/9/port/devtinyfs.c:375,381
1996/0123    
 
1996/0131    
	/* bitmap for block usage */ 
	x = (fs->nblocks + 8 - 1)/8; 
1996/0201    
	fs->map = smalloc(x); 
1999/0612    
	fs->map = malloc(x); 
1996/0131    
	memset(fs->map, 0x0, x); 
	for(bno = fs->nblocks; bno < x*8; bno++) 
		mapset(fs, bno); 
1997/0408/sys/src/9/port/devtinyfs.c:398,4031999/0612/sys/src/9/port/devtinyfs.c:401,407
1996/0201    
		f->pin = GETS(mdir->pin); 
		f->bno = bno; 
		f->dbno = x; 
1999/0612    
		f->fbno = Notabno; 
1996/0201    
	} 
 
	/* follow files */ 
1997/0408/sys/src/9/port/devtinyfs.c:445,4511999/0612/sys/src/9/port/devtinyfs.c:449,456
1996/0201    
	Tfile *f; 
	Qid qid; 
1996/0123    
 
1996/0218    
	USED(ntab, tab); 
1999/0612    
	USED(ntab); 
	USED(tab); 
1996/0218    
 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	if(i >= fs->nf) 
1997/0408/sys/src/9/port/devtinyfs.c:460,4941999/0612/sys/src/9/port/devtinyfs.c:465,494
1996/0123    
} 
 
1997/0327    
static void 
1996/0201    
tinyfsreset(void) 
1999/0612    
tinyfsinit(void) 
1996/0201    
{ 
	if(Nlen > NAMELEN) 
		panic("tinyfsreset"); 
1999/0612    
		panic("tinyfsinit"); 
1996/0201    
} 
 
1999/0612    
/* 
 *  specifier is an open file descriptor 
 */ 
1997/0327    
static Chan* 
1996/0116    
tinyfsattach(char *spec) 
1999/0612    
tinyfsattach(void *spec) 
1996/0116    
{ 
1996/0201    
	Tfs *fs; 
1996/0122    
	Chan *c, *cc; 
1996/0201    
	int i; 
1996/0220    
	char *p; 
1999/0612    
	Chan *c; 
	volatile struct { Chan *cc; } rock; 
	int i, fd; 
1996/0120    
 
1996/0220    
	p = 0; 
1996/0226    
	if(strncmp(spec, "hd0", 3) == 0) 
		p = "/dev/hd0nvram"; 
	else if(strncmp(spec, "hd1", 3) == 0) 
		p = "/dev/hd1nvram"; 
	else if(strncmp(spec, "sd0", 3) == 0) 
		p = "/dev/sd0nvram"; 
	else if(strncmp(spec, "sd1", 3) == 0) 
		p = "/dev/sd1nvram"; 
1996/0220    
	else 
		error("bad spec"); 
1999/0612    
	fd = atoi(spec); 
	if(fd < 0) 
		error("bad specifier"); 
1996/0220    
 
	cc = namec(p, Aopen, ORDWR, 0); 
1999/0612    
	rock.cc = fdtochan(fd, ORDWR, 0, 1); 
1996/0123    
	if(waserror()){ 
1997/0327    
		cclose(cc); 
1999/0612    
		cclose(rock.cc); 
1996/0123    
		nexterror(); 
	} 
1996/0201    
 
1997/0408/sys/src/9/port/devtinyfs.c:496,5021999/0612/sys/src/9/port/devtinyfs.c:496,502
1996/0220    
	for(i = 0; i < Maxfs; i++){ 
1996/0201    
		fs = &tinyfs.fs[i]; 
1996/0226    
		qlock(&fs->ql); 
1996/0220    
		if(fs->r && eqchan(cc, fs->c, 0)) 
1999/0612    
		if(fs->r && eqchan(rock.cc, fs->c, 1)) 
1996/0122    
			break; 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
	} 
1997/0408/sys/src/9/port/devtinyfs.c:503,5091999/0612/sys/src/9/port/devtinyfs.c:503,509
1996/0220    
	if(i < Maxfs){ 
1996/0201    
		fs->r++; 
1996/0226    
		qunlock(&fs->ql); 
1997/0327    
		cclose(cc); 
1999/0612    
		cclose(rock.cc); 
1996/0122    
	} else { 
1996/0220    
		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ 
1996/0226    
			qlock(&fs->ql); 
1997/0408/sys/src/9/port/devtinyfs.c:513,5291999/0612/sys/src/9/port/devtinyfs.c:513,529
1996/0220    
		} 
		if(fs == &tinyfs.fs[Maxfs]) 
1996/0201    
			error("too many tinyfs's"); 
1996/0122    
		fs->c = cc; 
1999/0612    
		fs->c = rock.cc; 
1996/0201    
		fs->r = 1; 
1996/0220    
		fs->f = 0; 
		fs->nf = 0; 
		fs->fsize = 0; 
1996/0201    
		fsinit(fs); 
1999/0612    
		tfsinit(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
	} 
1996/0123    
	poperror(); 
1996/0122    
 
1996/0201    
	c = devattach('U', spec); 
1999/0612    
	c = devattach('F', spec); 
1996/0201    
	c->dev = fs - tinyfs.fs; 
	c->qid.path = CHDIR; 
	c->qid.vers = 0; 
1997/0408/sys/src/9/port/devtinyfs.c:572,5971999/0612/sys/src/9/port/devtinyfs.c:572,597
1997/0327    
static Chan* 
1996/0116    
tinyfsopen(Chan *c, int omode) 
{ 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0201    
 
	fs = &tinyfs.fs[c->dev]; 
1999/0612    
	rock.fs = &tinyfs.fs[c->dev]; 
1996/0201    
 
1996/0218    
	if(c->qid.path & CHDIR){ 
1996/0201    
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
1996/0226    
		qlock(&fs->ql); 
1999/0612    
		qlock(&rock.fs->ql); 
1996/0220    
		if(waserror()){ 
1996/0226    
			qunlock(&fs->ql); 
1999/0612    
			qunlock(&rock.fs->ql); 
1996/0220    
			nexterror(); 
		} 
		switch(omode){ 
		case OTRUNC|ORDWR: 
		case OTRUNC|OWRITE: 
1996/0218    
			f = newfile(fs, fs->f[c->qid.path].name); 
1996/0220    
			fs->f[c->qid.path].r--; 
1996/0202    
			c->qid.path = f - fs->f; 
1999/0612    
			f = newfile(rock.fs, rock.fs->f[c->qid.path].name); 
			rock.fs->f[c->qid.path].r--; 
			c->qid.path = f - rock.fs->f; 
1996/0220    
			break; 
		case OREAD: 
			break; 
1997/0408/sys/src/9/port/devtinyfs.c:598,6041999/0612/sys/src/9/port/devtinyfs.c:598,604
1996/0220    
		default: 
1996/0202    
			error(Eperm); 
1996/0201    
		} 
1996/0226    
		qunlock(&fs->ql); 
1999/0612    
		qunlock(&rock.fs->ql); 
1996/0220    
		poperror(); 
1996/0201    
	} 
 
1997/0408/sys/src/9/port/devtinyfs.c:608,6301999/0612/sys/src/9/port/devtinyfs.c:608,630
1997/0327    
static void 
1996/0116    
tinyfscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1996/0201    
	Tfs *fs; 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0201    
	Tfile *f; 
1996/0116    
 
1996/0220    
	USED(perm); 
1996/0116    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
1999/0612    
	rock.fs = &tinyfs.fs[c->dev]; 
1996/0218    
 
1996/0226    
	qlock(&fs->ql); 
1999/0612    
	qlock(&rock.fs->ql); 
1996/0220    
	if(waserror()){ 
1996/0226    
		qunlock(&fs->ql); 
1999/0612    
		qunlock(&rock.fs->ql); 
1996/0220    
		nexterror(); 
	} 
1996/0202    
	f = newfile(fs, name); 
1996/0226    
	qunlock(&fs->ql); 
1999/0612    
	f = newfile(rock.fs, name); 
	qunlock(&rock.fs->ql); 
1996/0220    
	poperror(); 
1996/0201    
 
	c->qid.path = f - fs->f; 
1999/0612    
	c->qid.path = f - rock.fs->f; 
1996/0202    
	c->qid.vers = 0; 
1996/0116    
	c->mode = openmode(omode); 
} 
1997/0408/sys/src/9/port/devtinyfs.c:647,6721999/0612/sys/src/9/port/devtinyfs.c:647,672
1997/0327    
static void 
1996/0116    
tinyfsclose(Chan *c) 
{ 
1996/0220    
	Tfs *fs; 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0201    
	Tfile *f, *nf; 
1996/0202    
	int i; 
1996/0201    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
1999/0612    
	rock.fs = &tinyfs.fs[c->dev]; 
1996/0201    
 
1996/0226    
	qlock(&fs->ql); 
1999/0612    
	qlock(&rock.fs->ql); 
1996/0201    
 
1996/0202    
	/* dereference file and remove old versions */ 
1996/0220    
	if(!waserror()){ 
		if(c->qid.path != CHDIR){ 
			f = &fs->f[c->qid.path]; 
1999/0612    
			f = &rock.fs->f[c->qid.path]; 
1996/0220    
			f->r--; 
			if(f->r == 0){ 
				if(f->flag & Frmonclose) 
					freefile(fs, f, Notabno); 
1999/0612    
					freefile(rock.fs, f, Notabno); 
1996/0220    
				else if(f->flag & Fcreating){ 
					/* remove all other files with this name */ 
					for(i = 0; i < fs->fsize; i++){ 
						nf = &fs->f[i]; 
1999/0612    
					for(i = 0; i < rock.fs->fsize; i++){ 
						nf = &rock.fs->f[i]; 
1996/0220    
						if(f == nf) 
							continue; 
						if(strcmp(nf->name, f->name) == 0){ 
1997/0408/sys/src/9/port/devtinyfs.c:673,6791999/0612/sys/src/9/port/devtinyfs.c:673,679
1996/0220    
							if(nf->r) 
								nf->flag |= Frmonclose; 
							else 
								freefile(fs, nf, Notabno); 
1999/0612    
								freefile(rock.fs, nf, Notabno); 
1996/0220    
						} 
1996/0203    
					} 
1996/0220    
					f->flag &= ~Fcreating; 
1997/0408/sys/src/9/port/devtinyfs.c:683,7271999/0612/sys/src/9/port/devtinyfs.c:683,728
1996/0220    
		poperror(); 
1996/0202    
	} 
 
	/* dereference fs and remove on zero refs */ 
	fs->r--; 
1996/0218    
	if(fs->r == 0){ 
1996/0220    
		if(fs->f) 
			free(fs->f); 
		fs->f = 0; 
		fs->nf = 0; 
		fs->fsize = 0; 
		if(fs->map) 
			free(fs->map); 
		fs->map = 0; 
1997/0327    
		cclose(fs->c); 
1996/0220    
		fs->c = 0; 
1999/0612    
	/* dereference rock.fs and remove on zero refs */ 
	rock.fs->r--; 
	if(rock.fs->r == 0){ 
		if(rock.fs->f) 
			free(rock.fs->f); 
		rock.fs->f = 0; 
		rock.fs->nf = 0; 
		rock.fs->fsize = 0; 
		if(rock.fs->map) 
			free(rock.fs->map); 
		rock.fs->map = 0; 
		cclose(rock.fs->c); 
		rock.fs->c = 0; 
1996/0201    
	} 
1996/0226    
	qunlock(&fs->ql); 
1999/0612    
	qunlock(&rock.fs->ql); 
1996/0116    
} 
 
1997/0327    
static long 
1996/0116    
tinyfsread(Chan *c, void *a, long n, ulong offset) 
1999/0612    
tinyfsread(Chan *c, void *a, long n, vlong offset) 
1996/0116    
{ 
1996/0203    
	Tfs *fs; 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0203    
	Tfile *f; 
1996/0220    
	int sofar, i, off; 
1996/0218    
	ulong bno; 
1996/0206    
	Mdata *md; 
	uchar buf[Blen]; 
1996/0217    
	uchar *p = a; 
1999/0612    
	uchar *p; 
1996/0203    
 
	if(c->qid.path & CHDIR) 
1996/0217    
		return devdirread(c, a, n, 0, 0, tinyfsgen); 
1996/0203    
 
1996/0220    
	fs = &tinyfs.fs[c->dev]; 
1996/0203    
	f = &fs->f[c->qid.path]; 
1999/0612    
	p = a; 
	rock.fs = &tinyfs.fs[c->dev]; 
	f = &rock.fs->f[c->qid.path]; 
1996/0203    
	if(offset >= f->length) 
		return 0; 
1996/0220    
 
1996/0226    
	qlock(&fs->ql); 
1999/0612    
	qlock(&rock.fs->ql); 
1996/0220    
	if(waserror()){ 
1996/0226    
		qunlock(&fs->ql); 
1999/0612    
		qunlock(&rock.fs->ql); 
1996/0220    
		nexterror(); 
	} 
1996/0203    
	if(n + offset >= f->length) 
1997/0408/sys/src/9/port/devtinyfs.c:728,7341999/0612/sys/src/9/port/devtinyfs.c:729,735
1996/0203    
		n = f->length - offset; 
1996/0206    
 
1996/0217    
	/* walk to starting data block */ 
1996/0220    
	if(f->finger < offset && f->fbno != Notabno){ 
1999/0612    
	if(0 && f->finger <= offset && f->fbno != Notabno){ 
1996/0220    
		sofar = f->finger; 
		bno = f->fbno; 
	} else { 
1997/0408/sys/src/9/port/devtinyfs.c:735,7421999/0612/sys/src/9/port/devtinyfs.c:736,743
1996/0220    
		sofar = 0; 
		bno = f->dbno; 
	} 
	for(; sofar + Dlen < offset; sofar += Dlen){ 
1996/0217    
		md = readdata(fs, bno, buf, 0); 
1999/0612    
	for(; sofar + Dlen <= offset; sofar += Dlen){ 
		md = readdata(rock.fs, bno, buf, 0); 
1996/0220    
		if(md == 0) 
			error(Eio); 
1996/0206    
		bno = GETS(md->bno); 
1997/0408/sys/src/9/port/devtinyfs.c:746,7681999/0612/sys/src/9/port/devtinyfs.c:747,770
1996/0220    
	off = offset%Dlen; 
	offset -= off; 
1996/0217    
	for(sofar = 0; sofar < n; sofar += i){ 
		md = readdata(fs, bno, buf, &i); 
1999/0612    
		md = readdata(rock.fs, bno, buf, &i); 
1996/0220    
		if(md == 0) 
			error(Eio); 
 
		/* update finger for successful read */ 
		f->finger = offset + sofar; 
1999/0612    
		f->finger = offset; 
1996/0220    
		f->fbno = bno; 
1999/0612    
		offset += Dlen; 
1996/0220    
 
		i -= off; 
1996/0217    
		if(i > n) 
			i = n; 
		memmove(p, md->data, i); 
1999/0612    
		if(i > n - sofar) 
			i = n - sofar; 
		memmove(p, md->data+off, i); 
1996/0217    
		p += i; 
		bno = GETS(md->bno); 
1996/0220    
		off = 0; 
1996/0217    
	} 
1996/0226    
	qunlock(&fs->ql); 
1999/0612    
	qunlock(&rock.fs->ql); 
1996/0220    
	poperror(); 
1996/0203    
 
1996/0217    
	return sofar; 
1997/0408/sys/src/9/port/devtinyfs.c:773,7871999/0612/sys/src/9/port/devtinyfs.c:775,792
1996/0220    
 *  be lost.  They should be recovered next fsinit. 
 */ 
1997/0327    
static long 
1996/0220    
tinyfswrite(Chan *c, void *a, long n, ulong offset) 
1999/0612    
tinyfswrite(Chan *c, void *a, long n, vlong offset) 
1996/0116    
{ 
1996/0217    
	Tfs *fs; 
	Tfile *f; 
1996/0220    
	int last, next, i, off, finger; 
	ulong bno, dbno, fbno; 
1999/0612    
	int last, next, i, finger, off, used; 
	ulong bno, fbno; 
1996/0217    
	Mdata *md; 
	uchar buf[Blen]; 
	uchar *p = a; 
1999/0612    
	uchar *p; 
	volatile struct { 
		Tfs *fs; 
		ulong dbno; 
	} rock; 
1996/0217    
 
	if(c->qid.path & CHDIR) 
		error(Eperm); 
1997/0408/sys/src/9/port/devtinyfs.c:789,8351999/0612/sys/src/9/port/devtinyfs.c:794,841
1996/0218    
	if(n == 0) 
		return 0; 
 
1996/0220    
	fs = &tinyfs.fs[c->dev]; 
1996/0217    
	f = &fs->f[c->qid.path]; 
1999/0612    
	p = a; 
	rock.fs = &tinyfs.fs[c->dev]; 
	f = &rock.fs->f[c->qid.path]; 
1996/0217    
 
1996/0218    
	/* files are append only, anything else is illegal */ 
	if(offset != f->length) 
		error("append only"); 
                 
1996/0226    
	qlock(&fs->ql); 
1996/0220    
	dbno = Notabno; 
1999/0612    
	qlock(&rock.fs->ql); 
	rock.dbno = Notabno; 
1996/0218    
	if(waserror()){ 
1996/0220    
		freeblocks(fs, dbno, Notabno); 
1996/0226    
		qunlock(&fs->ql); 
1999/0612    
		freeblocks(rock.fs, rock.dbno, Notabno); 
		qunlock(&rock.fs->ql); 
1996/0218    
		nexterror(); 
	} 
 
1999/0612    
	/* files are append only, anything else is illegal */ 
	if(offset != f->length) 
		error("append only"); 
 
1996/0220    
	/* write blocks backwards */ 
	p += n; 
	last = offset + n; 
	off = offset; 
	fbno = Notabno; 
	finger = 0; 
	for(next = (last/Dlen)*Dlen; next >= off; next -= Dlen){ 
		bno = mapalloc(fs); 
		if(bno == Notabno){ 
1999/0612    
	off = offset; /* so we have something signed to compare against */ 
	for(next = ((last-1)/Dlen)*Dlen; next >= off; next -= Dlen){ 
		bno = mapalloc(rock.fs); 
		if(bno == Notabno) 
1996/0220    
			error("out of space"); 
		} 
		i = last - next; 
		p -= i; 
		if(last == n+offset){ 
			writedata(fs, bno, dbno, p, i, 1); 
1999/0612    
			writedata(rock.fs, bno, rock.dbno, p, i, 1); 
1996/0220    
			finger = next;	/* remember for later */ 
			fbno = bno; 
		} else 
			writedata(fs, bno, dbno, p, i, 0); 
		dbno = bno; 
1999/0612    
		} else { 
			writedata(rock.fs, bno, rock.dbno, p, i, 0); 
		} 
		rock.dbno = bno; 
1996/0220    
		last = next; 
	} 
 
1996/0218    
	/* walk to last data block */ 
1996/0220    
	md = (Mdata*)buf; 
	if(f->finger < offset && f->fbno != Notabno){ 
1999/0612    
	if(0 && f->finger < offset && f->fbno != Notabno){ 
1996/0220    
		next = f->finger; 
		bno = f->fbno; 
	} else { 
1997/0408/sys/src/9/port/devtinyfs.c:836,8621999/0612/sys/src/9/port/devtinyfs.c:842,878
1996/0220    
		next = 0; 
		bno = f->dbno; 
	} 
	for(; next < offset; next += Dlen){ 
1996/0217    
		md = readdata(fs, bno, buf, 0); 
1999/0612    
 
	used = 0; 
	while(bno != Notabno){ 
		md = readdata(rock.fs, bno, buf, &used); 
1996/0220    
		if(md == 0) 
			error(Eio); 
1996/0218    
		if(md->type == Tagend) 
1999/0612    
		if(md->type == Tagend){ 
			if(next + Dlen < offset) 
				panic("devtinyfs1"); 
1996/0218    
			break; 
1999/0612    
		} 
		next += Dlen; 
		if(next > offset) 
			panic("devtinyfs1"); 
1996/0217    
		bno = GETS(md->bno); 
1996/0116    
	} 
 
1996/0220    
	/* point to new blocks */ 
	if(offset == 0){ 
		f->dbno = dbno; 
		writedir(fs, f); 
1999/0612    
		/* first block in a file */ 
		f->dbno = rock.dbno; 
		writedir(rock.fs, f); 
1996/0220    
	} else { 
1999/0612    
		/* updating a current block */ 
1996/0220    
		i = last - offset; 
		next = offset%Dlen; 
		if(i > 0){ 
			p -= i; 
			memmove(md->data + next, p, i); 
1999/0612    
			memmove(md->data + used, p, i); 
			used += i; 
1996/0218    
		} 
1996/0220    
		writedata(fs, bno, dbno, md->data, i+next, last == n+offset); 
1999/0612    
		writedata(rock.fs, bno, rock.dbno, md->data, used, last == n+offset); 
1996/0218    
	} 
1996/0220    
	f->length += n; 
1996/0218    
 
1997/0408/sys/src/9/port/devtinyfs.c:866,8821999/0612/sys/src/9/port/devtinyfs.c:882,898
1996/0220    
		f->fbno =  fbno; 
	} 
1996/0218    
	poperror(); 
1996/0226    
	qunlock(&fs->ql); 
1999/0612    
	qunlock(&rock.fs->ql); 
1996/0217    
 
1996/0220    
	return n; 
1996/0116    
} 
 
1997/0327    
Dev tinyfsdevtab = { 
1997/0408    
	'U', 
1999/0612    
	'F', 
1997/0408    
	"tinyfs", 
 
1997/0327    
	tinyfsreset, 
	devinit, 
1999/0612    
	devreset, 
	tinyfsinit, 
1997/0327    
	tinyfsattach, 
	tinyfsclone, 
	tinyfswalk, 
1999/0612/sys/src/9/port/devtinyfs.c:460,4661999/0618/sys/src/9/port/devtinyfs.c:460,466 (short | long)
1996/0220    
		return 0; 
1996/0201    
	qid.path = i; 
	qid.vers = 0; 
1996/0202    
	devdir(c, qid, f->name, f->length, eve, 0664, dp); 
1999/0618    
	devdir(c, qid, f->name, f->length, eve, 0775, dp); 
1996/0201    
	return 1; 
1996/0123    
} 
 
1999/0612/sys/src/9/port/devtinyfs.c:480,4921999/0618/sys/src/9/port/devtinyfs.c:480,491
1996/0201    
	Tfs *fs; 
1999/0612    
	Chan *c; 
	volatile struct { Chan *cc; } rock; 
	int i, fd; 
1999/0618    
	int i; 
	char buf[NAMELEN*2]; 
1996/0120    
 
1999/0612    
	fd = atoi(spec); 
	if(fd < 0) 
		error("bad specifier"); 
1999/0618    
	snprint(buf, sizeof(buf), "/dev/%s", spec); 
	rock.cc = namec(buf, Aopen, ORDWR, 0); 
1996/0220    
 
1999/0612    
	rock.cc = fdtochan(fd, ORDWR, 0, 1); 
1996/0123    
	if(waserror()){ 
1999/0612    
		cclose(rock.cc); 
1996/0123    
		nexterror(); 
1999/0612/sys/src/9/port/devtinyfs.c:594,5991999/0618/sys/src/9/port/devtinyfs.c:593,599
1999/0612    
			c->qid.path = f - rock.fs->f; 
1996/0220    
			break; 
		case OREAD: 
1999/0618    
		case OEXEC: 
1996/0220    
			break; 
		default: 
1996/0202    
			error(Eperm); 
1999/0618/sys/src/9/port/devtinyfs.c:475,4811999/0623/sys/src/9/port/devtinyfs.c:475,481 (short | long)
1999/0612    
 *  specifier is an open file descriptor 
 */ 
1997/0327    
static Chan* 
1999/0612    
tinyfsattach(void *spec) 
1999/0623    
tinyfsattach(char *spec) 
1996/0116    
{ 
1996/0201    
	Tfs *fs; 
1999/0612    
	Chan *c; 
1999/0623/sys/src/9/port/devtinyfs.c:452,4651999/1230/sys/src/9/port/devtinyfs.c:452,470 (short | long)
1999/0612    
	USED(ntab); 
	USED(tab); 
1996/0218    
 
1999/1230    
	qid.vers = 0; 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	if(i >= fs->nf) 
		return -1; 
1999/1230    
	if(i == DEVDOTDOT){ 
		qid.path = CHDIR; 
		devdir(c, qid, ".", 0, eve, 0555, dp); 
		return 1; 
	} 
1996/0201    
	f = &fs->f[i]; 
1996/0220    
	if(f->name[0] == 0) 
		return 0; 
1996/0201    
	qid.path = i; 
	qid.vers = 0; 
1999/0618    
	devdir(c, qid, f->name, f->length, eve, 0775, dp); 
1996/0201    
	return 1; 
1996/0123    
} 


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