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

📄 u9fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		b |= QTDIR;	/* no way to test append-only */	/* no real way to test exclusive use, but mark devices as such */	if(S_ISSPECIAL(st->st_mode))		b |= QTEXCL;	return b;}ulongplan9mode(struct stat *st){	return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777);}/*  * this is for chmod, so don't worry about S_IFDIR */mode_tunixmode(Dir *d){	return (mode_t)(d->mode&0777);}Qidstat2qid(struct stat *st){	uchar *p, *ep, *q;	Qid qid;	/*	 * For now, ignore the device number.	 */	qid.path = 0;	p = (uchar*)&qid.path;	ep = p+sizeof(qid.path);	q = p+sizeof(ino_t);	if(q > ep){		fprint(2, "warning: inode number too big\n");		q = ep;	}	memmove(p, &st->st_ino, q-p);	q = q+sizeof(dev_t);	if(q > ep){/*		fprint(2, "warning: inode number + device number too big %d+%d\n", sizeof(ino_t), sizeof(dev_t)); */		q = ep - sizeof(dev_t);		if(q < p)			fprint(2, "warning: device number too big by itself\n");		else			*(dev_t*)q ^= st->st_dev;	}	qid.vers = st->st_mtime ^ (st->st_size << 8);	qid.type = modebyte(st);	return qid;}voidstat2dir(char *path, struct stat *st, Dir *d){	User *u;	char *q;	memset(d, 0, sizeof(*d));	d->qid = stat2qid(st);	d->mode = plan9mode(st);	d->atime = st->st_atime;	d->mtime = st->st_mtime;	d->length = st->st_size;	d->uid = (u = uid2user(st->st_uid)) ? u->name : "???";	d->gid = (u = gid2user(st->st_gid)) ? u->name : "???";	d->muid = "";	if((q = strrchr(path, '/')) != nil)		d->name = q+1;	else		d->name = path;}voidrread(Fcall *rx, Fcall *tx){	char *e, *path;	uchar *p, *ep;	int n;	Fid *fid;	Dir d;	struct stat st;	if(rx->count > msize-IOHDRSZ){		seterror(tx, Etoolarge);		return;	}	if((fid = oldfidex(rx->fid, -1, &e)) == nil){		seterror(tx, e);		return;	}	if (fid->auth) {		char *e;		e = auth->read(rx, tx);		if (e)			seterror(tx, e);		return;	}	if(fid->omode == -1 || (fid->omode&3) == OWRITE){		seterror(tx, Ebadusefid);		return;	}	if(fid->dir){		if(rx->offset != fid->diroffset){			if(rx->offset != 0){				seterror(tx, Ebadoffset);				return;			}			rewinddir(fid->dir);			fid->diroffset = 0;		}		p = (uchar*)tx->data;		ep = (uchar*)tx->data+rx->count;		for(;;){			if(p+BIT16SZ >= ep)				break;			if(fid->dirent == nil)	/* one entry cache for when convD2M fails */				if((fid->dirent = readdir(fid->dir)) == nil)					break;			if(strcmp(fid->dirent->d_name, ".") == 0			|| strcmp(fid->dirent->d_name, "..") == 0){				fid->dirent = nil;				continue;			}			path = estrpath(fid->path, fid->dirent->d_name);			memset(&st, 0, sizeof st);			if(stat(path, &st) < 0){				fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno));				fid->dirent = nil;				free(path);				continue;			}			free(path);			stat2dir(fid->dirent->d_name, &st, &d);			if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ)				break;			p += n;			fid->dirent = nil;		}		tx->count = p - (uchar*)tx->data;		fid->diroffset += tx->count;	}else{		if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){			seterror(tx, strerror(errno));			return;		}		tx->count = n;	}}voidrwrite(Fcall *rx, Fcall *tx){	char *e;	Fid *fid;	int n;	if(rx->count > msize-IOHDRSZ){		seterror(tx, Etoolarge);		return;	}	if((fid = oldfidex(rx->fid, -1, &e)) == nil){		seterror(tx, e);		return;	}	if (fid->auth) {		char *e;		e = auth->write(rx, tx);		if (e)			seterror(tx, e);		return;	}	if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){		seterror(tx, Ebadusefid);		return;	}	if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){		seterror(tx, strerror(errno));		return;	}	tx->count = n;}voidrclunk(Fcall *rx, Fcall *tx){	char *e;	Fid *fid;	if((fid = oldfidex(rx->fid, -1, &e)) == nil){		seterror(tx, e);		return;	}	if (fid->auth) {		if (auth->clunk) {			e = (*auth->clunk)(rx, tx);			if (e) {				seterror(tx, e);				return;			}		}	}	else if(fid->omode != -1 && fid->omode&ORCLOSE)		remove(fid->path);	freefid(fid);}voidrremove(Fcall *rx, Fcall *tx){	char *e;	Fid *fid;	if((fid = oldfid(rx->fid, &e)) == nil){		seterror(tx, e);		return;	}	if(userremove(fid, &e) < 0)		seterror(tx, e);	freefid(fid);}voidrstat(Fcall *rx, Fcall *tx){	char *e;	Fid *fid;	Dir d;	if((fid = oldfid(rx->fid, &e)) == nil){		seterror(tx, e);		return;	}	if(fidstat(fid, &e) < 0){		seterror(tx, e);		return;	}	stat2dir(fid->path, &fid->st, &d);	if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ)		seterror(tx, "convD2M fails");}voidrwstat(Fcall *rx, Fcall *tx){	char *e;	char *p, *old, *new, *dir;	gid_t gid;	Dir d;	Fid *fid;	if((fid = oldfid(rx->fid, &e)) == nil){		seterror(tx, e);		return;	}	/*	 * wstat is supposed to be atomic.	 * we check all the things we can before trying anything.	 * still, if we are told to truncate a file and rename it and only	 * one works, we're screwed.  in such cases we leave things	 * half broken and return an error.  it's hardly perfect.	 */	if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){		seterror(tx, Ewstatbuffer);		return;	}	if(fidstat(fid, &e) < 0){		seterror(tx, e);		return;	}	/*	 * The casting is necessary because d.mode is ulong and might,	 * on some systems, be 64 bits.  We only want to compare the	 * bottom 32 bits, since that's all that gets sent in the protocol.	 * 	 * Same situation for d.mtime and d.length (although that last check	 * is admittedly superfluous, given the current lack of 128-bit machines).	 */	gid = (gid_t)-1;	if(d.gid[0] != '\0'){		User *g;		g = gname2user(d.gid);		if(g == nil){			seterror(tx, Eunknowngroup);			return;		}		gid = (gid_t)g->id;		if(groupchange(fid->u, gid2user(gid), &e) < 0){			seterror(tx, e);			return;		}			}	if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){		seterror(tx, Edirchange);		return;	}	if(strcmp(fid->path, "/") == 0){		seterror(tx, "no wstat of root");		return;	}	/*	 * try things in increasing order of harm to the file.	 * mtime should come after truncate so that if you	 * do both the mtime actually takes effect, but i'd rather	 * leave truncate until last.	 * (see above comment about atomicity).	 */	if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){		if(chatty9p)			fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d));		seterror(tx, strerror(errno));		return;	}	if((u32int)d.mtime != (u32int)~0){		struct utimbuf t;		t.actime = 0;		t.modtime = d.mtime;		if(utime(fid->path, &t) < 0){			if(chatty9p)				fprint(2, "utime(%s) failed\n", fid->path);			seterror(tx, strerror(errno));			return;		}	}	if(gid != (gid_t)-1 && gid != fid->st.st_gid){		if(chown(fid->path, (uid_t)-1, gid) < 0){			if(chatty9p)				fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid);			seterror(tx, strerror(errno));			return;		}	}	if(d.name[0]){		old = fid->path;		dir = estrdup(fid->path);		if((p = strrchr(dir, '/')) > dir)			*p = '\0';		else{			seterror(tx, "whoops: can't happen in u9fs");			return;		}			new = estrpath(dir, d.name);		if(strcmp(old, new) != 0 && rename(old, new) < 0){			if(chatty9p)				fprint(2, "rename(%s, %s) failed\n", old, new);			seterror(tx, strerror(errno));			free(new);			free(dir);			return;		}		fid->path = new;		free(old);		free(dir);	}	if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){		fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length);		seterror(tx, strerror(errno));		return;	}}/* * we keep a table by numeric id.  by name lookups happen infrequently * while by-number lookups happen once for every directory entry read * and every stat request. */User *utab[64];User *gtab[64];User*adduser(struct passwd *p){	User *u;	u = emalloc(sizeof(*u));	u->id = p->pw_uid;	u->name = estrdup(p->pw_name);	u->next = utab[p->pw_uid%nelem(utab)];	u->defaultgid = p->pw_gid;	utab[p->pw_uid%nelem(utab)] = u;	return u;}intuseringroup(User *u, User *g){	int i;	for(i=0; i<g->nmem; i++)		if(strcmp(g->mem[i], u->name) == 0)			return 1;	/*	 * Hack around common Unix problem that everyone has	 * default group "user" but /etc/group lists no members.	 */	if(u->defaultgid == g->id)		return 1;	return 0;}User*addgroup(struct group *g){	User *u;	char **p;	int n;	u = emalloc(sizeof(*u));	n = 0;	for(p=g->gr_mem; *p; p++)		n++;	u->mem = emalloc(sizeof(u->mem[0])*n);	n = 0;	for(p=g->gr_mem; *p; p++)		u->mem[n++] = estrdup(*p);	u->nmem = n;	u->id = g->gr_gid;	u->name = estrdup(g->gr_name);	u->next = gtab[g->gr_gid%nelem(gtab)];	gtab[g->gr_gid%nelem(gtab)] = u;	return u;}User*uname2user(char *name){	int i;	User *u;	struct passwd *p;	for(i=0; i<nelem(utab); i++)		for(u=utab[i]; u; u=u->next)			if(strcmp(u->name, name) == 0)				return u;	if((p = getpwnam(name)) == nil)		return nil;	return adduser(p);}User*uid2user(int id){	User *u;	struct passwd *p;	for(u=utab[id%nelem(utab)]; u; u=u->next)		if(u->id == id)			return u;	if((p = getpwuid(id)) == nil)		return nil;	return adduser(p);}User*gname2user(char *name){	int i;	User *u;	struct group *g;	for(i=0; i<nelem(gtab); i++)		for(u=gtab[i]; u; u=u->next)			if(strcmp(u->name, name) == 0)				return u;	if((g = getgrnam(name)) == nil)		return nil;	return addgroup(g);}User*gid2user(int id){	User *u;	struct group *g;	for(u=gtab[id%nelem(gtab)]; u; u=u->next)		if(u->id == id)			return u;	if((g = getgrgid(id)) == nil)		return nil;	return addgroup(g);}voidsysfatal(char *fmt, ...){	char buf[1024];	va_list va, temp;	va_start(va, fmt);	va_copy(temp, va);	doprint(buf, buf+sizeof buf, fmt, &temp);	va_end(temp);	va_end(va);	fprint(2, "u9fs: %s\n", buf);	fprint(2, "last unix error: %s\n", strerror(errno));	exit(1);}void*emalloc(size_t n){	void *p;	if(n == 0)		n = 1;	p = malloc(n);	if(p == 0)		sysfatal("malloc(%ld) fails", (long)n);	memset(p, 0, n);	return p;}void*erealloc(void *p, size_t n){	if(p == 0)		p = malloc(n);	else		p = realloc(p, n);	if(p == 0)		sysfatal("realloc(..., %ld) fails", (long)n);	return p;}char*estrdup(char *p){	p = strdup(p);	if(p == 0)

⌨️ 快捷键说明

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