Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/mpc/devsac.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname mpc/devsac.c 1999/0608
## diff -e /dev/null /n/emeliedump/1999/0608/sys/src/brazil/mpc/devsac.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

/*
 * Rather than reading /adm/users, which is a lot of work for
 * a toy program, we assume all groups have the form
 *	NNN:user:user:
 * meaning that each user is the leader of his own group.
 */

enum
{
	OPERM	= 0x3,		/* mask of all permission types in open mode */
	Nram	= 512,
};

typedef struct SacPath SacPath;
typedef struct Sac Sac;
typedef struct SacHeader SacHeader;
typedef struct SacDir SacDir;

enum {
	Magic = 0x5acf5,
};

struct SacDir
{
	char	name[NAMELEN];
	char	uid[NAMELEN];
	char	gid[NAMELEN];
	uchar	qid[4];
	uchar	mode[4];
	uchar	atime[4];
	uchar	mtime[4];
	uchar	length[8];
	uchar	blocks[8];
};

struct SacHeader
{
	uchar	magic[4];
	uchar	length[8];
	uchar	blocksize[4];
	uchar	md5[16];
};


struct Sac
{
	SacDir;
	SacPath *path;
};

struct SacPath
{
	Ref;
	SacPath *up;
	vlong blocks;
	int entry;
};

enum
{
	Pexec =		1,
	Pwrite = 	2,
	Pread = 	4,
	Pother = 	1,
	Pgroup = 	8,
	Powner =	64,
};

uchar *data = SACMEM;
int blocksize;
Sac root;

void	sacstat(SacDir*, char*);
void	io(void);
void	usage(void);
ulong	getl(void *p);
vlong	getv(void *p);
void	init(char*);
Sac	*saccpy(Sac *s);
Sac *saclookup(Sac *s, char *name);
int sacdirread(Sac *s, char *p, long off, long cnt);
void loadblock(void *buf, uchar *offset, int blocksize);
void sacfree(Sac*);

void
devinit(void)
{
	SacHeader *hdr;
	hdr = (SacHeader*)data;
	if(getl(hdr->magic) != Magic) {
print("devsac: bad magic");
		return;
	}
	blocksize = getl(hdr->blocksize);
	root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
}

static Chan*
sacattach(char* spec)
{
	Chan *c;
	int dev;

	dev = atoi(spec);
	if(dev != 0)
		error("bad specification");

	// check if init found sac file system in memory
	if(blocksize == 0)
		error("devsac: bad magic");

	c = devattach('C', spec);
	c->qid = (Qid){getl(root.qid), 0};
	c->dev = dev;
	c->aux = saccpy(&root);
	return c;
}

Chan*
sacclone(Chan *c, Chan *nc)
{
	nc = devclone(c, nc);
	nc->aux = saccpy(c->aux);
	return nc;
}

int
devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen)
{
	Sac *sac;

	isdir(c);
	sac = c->aux;
	if(strcmp(name, ".") == 0)
		return 1;
	sac = saclookup(sac, name);
	if(sac == nil) {
		strncpy(up->error, Enonexist, NAMELEN);
		return 0;
	}
	c->aux = sac;
	c->qid = (Qid){getl(sac->qid), 0};
	op = c->path;
	c->path = ptenter(&syspt, op, name);
	decref(op);
	return 1;
}

char *
ropen(Fid *f)
{
	int mode, trunc;

	if(f->open)
		return Eisopen;
	if(f->busy == 0)
		return Enotexist;
	mode = rhdr.mode;
	if(f->qid.path & CHDIR){
		if(mode != OREAD)
			return Eperm;
		thdr.qid = f->qid;
		return 0;
	}
	if(mode & ORCLOSE)
		return Erdonly;
	trunc = mode & OTRUNC;
	mode &= OPERM;
	if(mode==OWRITE || mode==ORDWR || trunc)
		return Erdonly;
	if(mode==OREAD)
		if(!perm(f, f->sac, Pread))
			return Eperm;
	if(mode==OEXEC)
		if(!perm(f, f->sac, Pexec))
			return Eperm;
	thdr.qid = f->qid;
	f->open = 1;
	return 0;
}

char *
rcreate(Fid *f)
{
	if(f->open)
		return Eisopen;
	if(f->busy == 0)
		return Enotexist;
	return Erdonly;
}

char*
rread(Fid *f)
{
	Sac *sac;
	char *buf, *buf2;
	long off;
	int n, cnt, i, j;
	uchar *blocks;
	vlong length;

	if(f->busy == 0)
		return Enotexist;
	sac = f->sac;
	thdr.count = 0;
	off = rhdr.offset;
	buf = thdr.data;
	cnt = rhdr.count;
	if(f->qid.path & CHDIR){
		cnt = (rhdr.count/DIRLEN)*DIRLEN;
		if(off%DIRLEN)
			return "i/o error";
		thdr.count = sacdirread(sac, buf, off, cnt);
		return 0;
	}
	length = getv(sac->length);
	if(off >= length) {
		rhdr.count = 0;
		return 0;
	}
	if(cnt > length-off)
		cnt = length-off;
	thdr.count = cnt;
	if(cnt == 0)
		return 0;
	blocks = data + getv(sac->blocks);
	buf2 = malloc(blocksize);
	while(cnt > 0) {
		i = off/blocksize;
		loadblock(buf2, blocks+i*8, blocksize);
		j = off-i*blocksize;
		n = blocksize-j;
		if(n > cnt)
			n = cnt;
		memmove(buf, buf2+j, n);
		cnt -= n;
		off += n;
	}
	free(buf2);
	return 0;
}

char*
sacwrite(Fid *f)
{
	if(f->busy == 0)
		return Enotexist;
	return Erdonly;
}

char *
rclunk(Fid *f)
{
	f->busy = 0;
	f->open = 0;
	free(f->user);
	sacfree(f->sac);
	return 0;
}

char *
rremove(Fid *f)
{
	f->busy = 0;
	f->open = 0;
	free(f->user);
	sacfree(f->sac);
	return Erdonly;
}

char *
rstat(Fid *f)
{
	if(f->busy == 0)
		return Enotexist;
	sacstat(f->sac, thdr.stat);
	return 0;
}

char *
rwstat(Fid *f)
{
	if(f->busy == 0)
		return Enotexist;
	return Erdonly;
}

Sac*
saccpy(Sac *s)
{
	Sac *ss;
	
	ss = malloc(sizeof(Sac));
	*ss = *s;
	if(ss->path)
		incref(ss->path);
	return ss;
}

SacPath *
sacpathalloc(SacPath *p, vlong blocks, int entry)
{
	SacPath *pp = malloc(sizeof(SacPath));
	pp->ref = 1;
	pp->blocks = blocks;
	pp->entry = entry;
	pp->up = p;
	return pp;
}

static void
sacpathfree(SacPath *p)
{
	if(p == nil)
		return;
	if(decref(p) > 0)
		return;
	sacpathfree(p->up);
	free(p);
}


void
sacfree(Sac *s)
{
	sacpathfree(s->path);
	free(s);
}

void
sacstat(SacDir *s, char *buf)
{
	Dir dir;

	memmove(dir.name, s->name, NAMELEN);
	dir.qid = (Qid){getl(s->qid), 0};
	dir.mode = getl(s->mode);
	dir.length = getv(s->length);
	if(dir.mode &CHDIR)
		dir.length *= DIRLEN;
	strcpy(dir.uid, s->uid);
	strcpy(dir.gid, s->gid);
	dir.atime = getl(s->atime);
	dir.mtime = getl(s->mtime);
	convD2M(&dir, buf);
}

void
loadblock(void *buf, uchar *offset, int blocksize)
{
	vlong block, n;

	block = getv(offset);
	if(block < 0) {
		block = -block;
		n = getv(offset+8);
		if(n < 0)
			n = -n;
		n -= block;
//fprint(2, "blocksize = %d, block = %lld n = %lld\n", blocksize, block, n);
		if(unsac(buf, data+block, blocksize, n)<0)
			panic("unsac failed!");
	} else {
		memmove(buf, data+block, blocksize);
	}
}

Sac*
sacparent(Sac *s)
{
	uchar *blocks;
	SacDir *buf;
	int per, i;
	SacPath *p;

	p = s->path;
	if(p == nil || p->up == nil) {
		pathfree(p);
		*s = root;
		return s;
	}
	p = p->up;

//fprint(2, "sacparent = %lld %d\n", p->blocks, p->entry);
	blocks = data + p->blocks;
	per = blocksize/sizeof(SacDir);
	i = p->entry/per;
	buf = malloc(per*sizeof(SacDir));
	loadblock(buf, blocks + i*8, per*sizeof(SacDir));
	s->SacDir = buf[p->entry-i*per];
//fprint(2, "sacparent = %s\n", s->name);
	free(buf);
	incref(p);
	pathfree(s->path);
	s->path = p;
	return s;
}

int
sacdirread(Sac *s, char *p, long off, long cnt)
{
	uchar *blocks;
	SacDir *buf;
	int iblock, per, i, j, ndir;

	blocks = data + getv(s->blocks);
	per = blocksize/sizeof(SacDir);
	ndir = getv(s->length);
	off /= DIRLEN;
	cnt /= DIRLEN;
	if(off >= ndir)
		return 0;
	if(cnt > ndir-off)
		cnt = ndir-off;
	iblock = -1;
	buf = malloc(per*sizeof(SacDir));
	for(i=off; i<off+cnt; i++) {
		j = i/per;
		if(j != iblock) {
			loadblock(buf, blocks + j*8, per*sizeof(SacDir));
			iblock = j;
		}
		j *= per;
		sacstat(buf+i-j, p);
		p += DIRLEN;
	}
	free(buf);
	return cnt*DIRLEN;
}

Sac*
saclookup(Sac *s, char *name)
{
	int ndir;
	int top, bot, i, j, k, per;
	uchar *blocks;
	SacDir *buf;
	int iblock;
	SacDir *sd;
	
	if(strcmp(name, "..") == 0)
		return sacparent(s);
	blocks = data + getv(s->blocks);
	per = blocksize/sizeof(SacDir);
	ndir = getv(s->length);
	buf = malloc(per*sizeof(SacDir));
	iblock = -1;

	if(1) {
		// linear search
		for(i=0; i<ndir; i++) {
			j = i/per;
			if(j != iblock) {
				loadblock(buf, blocks + j*8, per*sizeof(SacDir));
				iblock = j;
			}
			j *= per;
			sd = buf+i-j;
			k = strcmp(name, sd->name);
			if(k == 0) {
//print("walk %s %lld %d\n", name, getv(s->blocks), i);
				s->path = sacpathalloc(s->path, getv(s->blocks), i);
				s->SacDir = *sd;
				free(buf);
				return s;
			}
		}
		free(buf);
		return 0;
	}

	// binary search
	top = ndir;
	bot = 0;
	while(bot != top){
if(bot>top)
sysfatal("binary serach failed: %d %d\n", bot, top);
		i = (bot+top)>>1;
		j = i/per;
		if(j != iblock) {
			loadblock(buf, blocks + j*8, per*sizeof(SacDir));
			iblock = j;
		}
		j *= per;
		sd = buf+i-j;
		k = strcmp(name, sd->name);
		if(k == 0) {
			s->path = sacpathalloc(s->path, getv(s->blocks), i);
			s->SacDir = *sd;
			free(buf);
		}
		if(k < 0) {
			top = i;
			sd = buf;
			if(strcmp(name, sd->name) < 0)
				top = j;
		} else {
			bot = i+1;
			if(ndir-j < per)
				i = ndir-j;
			else
				i = per;
			sd = buf+i-1;
			if(strcmp(name, sd->name) > 0)
				bot = j+i;
		}
	}
	return 0;
}

Fid *
newfid(int fid)
{
	Fid *f, *ff;

	ff = 0;
	for(f = fids; f; f = f->next)
		if(f->fid == fid)
			return f;
		else if(!ff && !f->busy)
			ff = f;
	if(ff){
		ff->fid = fid;
		return ff;
	}
	f = malloc(sizeof *f);
//fprint(2, "newfid\n");
	memset(f, 0 , sizeof(Fid));
	f->fid = fid;
	f->next = fids;
	fids = f;
	return f;
}

void
io(void)
{
	char *err;
	int n;

	for(;;){
		/*
		 * reading from a pipe or a network device
		 * will give an error after a few eof reads
		 * however, we cannot tell the difference
		 * between a zero-length read and an interrupt
		 * on the processes writing to us,
		 * so we wait for the error
		 */
		n = read(mfd[0], mdata, sizeof mdata);
		if(n == 0)
			continue;
		if(n < 0)
			error("mount read");
		if(convM2S(mdata, &rhdr, n) == 0)
			continue;

		if(debug)
			fprint(2, "sacfs:<-%F\n", &rhdr);

		thdr.data = mdata + MAXMSG;
		if(!fcalls[rhdr.type])
			err = "bad fcall type";
		else
			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
		if(err){
			thdr.type = Rerror;
			strncpy(thdr.ename, err, ERRLEN);
		}else{
			thdr.type = rhdr.type + 1;
			thdr.fid = rhdr.fid;
		}
		thdr.tag = rhdr.tag;
		if(debug)
			fprint(2, "ramfs:->%F\n", &thdr);/**/
		n = convS2M(&thdr, mdata);
		if(write(mfd[1], mdata, n) != n)
			error("mount write");
	}
}

int
perm(Fid *f, Sac *s, int p)
{
	ulong perm = getl(s->mode);
	if((p*Pother) & perm)
		return 1;
	if(strcmp(f->user, s->gid)==0 && ((p*Pgroup) & perm))
		return 1;
	if(strcmp(f->user, s->uid)==0 && ((p*Powner) & perm))
		return 1;
	return 0;
}


ulong
getl(void *p)
{
	uchar *a = p;

	return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
}

vlong
getv(void *p)
{
	uchar *a = p;
	ulong l0, l1;
	vlong v;

	l0 = (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
	a += 4;
	l1 = (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
	
	v = l0;
	v <<= 32;
	v |= l1;
	return v;
}

Dev sacdevtab = {
	'C',
	"sac",

	devreset,
	sacinit,
	sacattach,
	sacclone,
	sacwalk,
	sacstat,
	sacopen,
	devcreate,
	sacclose,
	sacread,
	devbread,
	sacwrite,
	devbwrite,
	devremove,
	devwstat,
};
.
## diffname mpc/devsac.c 1999/0609
## diff -e /n/emeliedump/1999/0608/sys/src/brazil/mpc/devsac.c /n/emeliedump/1999/0609/sys/src/brazil/mpc/devsac.c
611c
static vlong
.
518,603c
static ulong
.
514a
	free(buf);
.
499,513d
497a
			return s;
.
495c
print("walk %s %lld %d\n", name, getv(s->blocks), i);
		s->path = sacpathalloc(s->path, getv(s->blocks), i);
.
456,485c
	// linear search
	for(i=0; i<ndir; i++) {
.
442c
	int i, j, k, per;
.
438c
static Sac*
.
431c
		sacdir(c, buf+i-j, p);
.
412a
print("sacdirread %d %d\n", off, cnt);
	s = c->aux;
.
411a
	Sac *s;
.
406,407c
static int
sacdirread(Chan *c, char *p, long off, long cnt)
.
401c
	sacpathfree(s->path);
.
398c
print("sacparent = %s\n", s->name);
.
391c
print("sacparent = %lld %d\n", p->blocks, p->entry);
.
385c
		sacpathfree(p);
.
375c
static Sac*
.
370a
print("memmove: blocksize = %d\n", blocksize);
.
367c
print("blocksize = %d, block = %lld n = %lld\n", blocksize, block, n);
.
355c
static void
.
351a
	dir.type = devtab[c->type]->dc;
	dir.dev = c->dev;
.
337,338c
static void
sacdir(Chan *c, SacDir *s, char *buf)
.
330c
static void
.
307c
static SacPath *
.
300a
print("saccpy = %ux\n", ss);
.
295c
static Sac*
.
290,292c
	sacdir(c, c->aux, db);
.
287,288c
static void
sacstat(Chan *c, char *db)
.
278,285d
271,275c
	Sac *sac = c->aux;
print("close %ux\n", sac);
	c->aux = nil;
	sacfree(sac);
.
268,269c
static void
sacclose(Chan* c)
.
253,264c
	error(Eperm);
.
250,251c
static long
sacwrite(Chan *, void *, long, vlong)
.
247c
	return n;
.
239,244c
		nn = blocksize-j;
		if(nn > cnt)
			nn = cnt;
		memmove(buf, buf2+j, nn);
		cnt -= nn;
		off += nn;
.
232a
	n = cnt;
.
230d
227d
224,225c
	if(off >= length)
.
222a
print("data read\n");
	sac = c->aux;
.
219,221c
			error("i/o error");
		return sacdirread(c, buf, off, cnt);
.
209,217c
	buf = a;
	cnt = n;
	if(c->qid.path & CHDIR){
		cnt = (cnt/DIRLEN)*DIRLEN;
.
204,205c
	int nn, cnt, i, j;
.
199,200c

static long
sacread(Chan *c, void *a, long n, vlong off)
.
189,196c
	t = access[omode&3];
	if((t & mode) != t)
			error(Eperm);
	c->offset = 0;
	c->mode = openmode(omode);
	c->flag |= COPEN;
	return c;
.
161,187c
	sac = c->aux;
	mode = getl(sac->mode);
	if(strcmp(up->user, sac->uid) == 0)
		mode = mode;
	else if(strcmp(up->user, sac->gid) == 0)
		mode = mode<<3;
	else
		mode = mode<<6;
.
159c
	ulong t, mode;
	Sac *sac;
	static int access[] = { 0400, 0200, 0600, 0100 };
.
156,157c
static Chan*
sacopen(Chan *c, int omode)
.
150a
print("op=%ux name = %s\n", op, name);
.
142a
	sac = c->aux;
.
140,141c
	if(name[0]=='.' && name[1]==0)
.
138a
print("sacwalk\n");
.
137a
	Path *op;
.
134,135c
static int
sacwalk(Chan *c, char *name)
.
126c
static Chan*
.
101a
print("blocksize = %d\n", blocksize);
.
98c
print("devsac: bad magic\n");
.
95a
print("sacinit\n");
.
92,93c
static void
sacinit(void)
.
80,90c
static void	sacdir(Chan *, SacDir*, char*);
static ulong	getl(void *p);
static vlong	getv(void *p);
static Sac	*saccpy(Sac *s);
static Sac *saclookup(Sac *s, char *name);
static int sacdirread(Chan *, char *p, long off, long cnt);
static void loadblock(void *buf, uchar *offset, int blocksize);
static void sacfree(Sac*);
.
76,78c
static uchar *data = SACMEM;
static int blocksize;
static Sac root;
.
6a
#include "../port/error.h"
.
## diffname mpc/devsac.c 1999/0610
## diff -e /n/emeliedump/1999/0609/sys/src/brazil/mpc/devsac.c /n/emeliedump/1999/0610/sys/src/brazil/mpc/devsac.c
431d
375d
359d
352d
331d
327d
258d
240d
223a
		buf += nn;
.
203a
//print("sacread: %s %llx %d\n", sac->name, off, n);
.
202d
153d
140c
//print("walk %s\n", name);

.
101d
## diffname mpc/devsac.c 1999/0727
## diff -e /n/emeliedump/1999/0610/sys/src/brazil/mpc/devsac.c /n/emeliedump/1999/0727/sys/src/brazil/mpc/devsac.c
152,154d
137d
## diffname mpc/devsac.c 1999/0806
## diff -e /n/emeliedump/1999/0727/sys/src/brazil/mpc/devsac.c /n/emeliedump/1999/0806/sys/src/brazil/mpc/devsac.c
322a
		memmove(cache[j].data, buf, blocksize);
		cache[j].age = cacheage;
		cache[j].block = block;
.
316a
		cacheage++;
		// age has wraped
		if(cacheage == 0) {
			for(i=0; i<CacheSize; i++)
				cache[i].age = 0;
		}
		j = 0;
		age = cache[0].age;
		for(i=0; i<CacheSize; i++) {
			if(cache[i].age < age) {
				age = cache[i].age;
				j = i;
			}
			if(cache[i].block != block)
				continue;
			memmove(buf, cache[i].data, blocksize);
			cache[i].age = cacheage;
			return;
		}

.
312a
	ulong age;
	int i, j;
.
101a
	p = malloc(CacheSize*blocksize);
	if(p == nil)
		error("allocating cache");
	for(i=0; i<CacheSize; i++) {
		cache[i].data = p;
		p += blocksize;
	}
.
93a
	uchar *p;
	int i;

.
79a
static Cache cache[CacheSize];
static ulong cacheage;
.
66a
struct Cache
{
	long block;
	ulong age;
	uchar *data;
};

.
25a
typedef struct Cache Cache;
.
19a
	CacheSize = 20,
.
## diffname mpc/devsac.c 1999/0807
## diff -e /n/emeliedump/1999/0806/sys/src/brazil/mpc/devsac.c /n/emeliedump/1999/0807/sys/src/brazil/mpc/devsac.c
482,498d
466c
		s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir);
.
459c
			n = per;
			if(n > ndir-j*per)
				n = ndir-j*per;
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
.
451c
	ndir = getl(s->length);
.
449c
	blocks = data + getl(s->blocks);
.
441c
	int i, j, k, n, per;
.
426c
			n = per;
			if(n > ndir-j*per)
				n = ndir-j*per;
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
.
414c
	ndir = getl(s->length);
.
412c
	blocks = data + getl(s->blocks);
.
408c
	int iblock, per, i, j, n, ndir;
.
394c
	loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir));
.
392a
	n = per;
	if(n > p->nentry-i*per)
		n = p->nentry-i*per;
.
379c
	int per, i, n;
.
360c
		n = getl(offset+OffsetSize);
.
337c
	block = getl(offset);
.
333c
	long block, n;
.
321,322c
	memmove(dir.uid, s->uid, NAMELEN);
	memmove(dir.gid, s->gid, NAMELEN);
.
318c
	dir.length = getl(s->length);
.
286a
	pp->nentry = nentry;
.
281c
sacpathalloc(SacPath *p, long blocks, int entry, int nentry)
.
234c
		nn -= j;
.
232c
		nn = blocksize;
		if(nn > length-i*blocksize)
			nn = length-i*blocksize;
		loadblock(buf2, blocks+i*OffsetSize, nn);
.
228c
	blocks = data + getl(sac->blocks);
.
219,220c
	length = getl(sac->length);
.
208c
	long length;
	long off = voff;
.
202c
sacread(Chan *c, void *a, long n, vlong voff)
.
94d
66a
	int nentry;
.
65c
	long blocks;
.
20a
	OffsetSize = 4,		/* size in bytes of an offset */
.
## diffname mpc/devsac.c 1999/1231
## diff -e /n/emeliedump/1999/0807/sys/src/brazil/mpc/devsac.c /n/emeliedump/1999/1231/sys/src/9/mpc/devsac.c
164a
	if(name[0]=='.' && name[1]=='.' && name[2]==0)
		return 1;
.
## diffname mpc/devsac.c 2000/0516
## diff -e /n/emeliedump/1999/1231/sys/src/9/mpc/devsac.c /n/emeliedump/2000/0516/sys/src/9/mpc/devsac.c
109a
	s = getconf("flash");
	if(s == nil) {
		print("devsac: no flash file system\n");
		return;
	}

	p = (uchar*)strtoul(s, 0, 0);
	if(p == 0) {
		print("devsac: bad address for flash file system\n");
		return;
	}
	data = tarlookup(p, sacfs, &i);
	if(data == 0) {
		print("devsac: could not find file: %s\n", sacfs);
		return;
	}
.
106a
	char *s;
.
88c
static char *sacfs = "fs.sac";
static uchar *data;
.
9,15d
## diffname mpc/devsac.c 2000/1208
## diff -e /n/emeliedump/2000/0516/sys/src/9/mpc/devsac.c /n/emeliedump/2000/1208/sys/src/9/mpc/devsac.c
176,177d
## diffname mpc/devsac.c 2001/0527 # deleted
## diff -e /n/emeliedump/2000/1208/sys/src/9/mpc/devsac.c /n/emeliedump/2001/0527/sys/src/9/mpc/devsac.c
1,528d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.