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

📄 9p2.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		goto out;	}	if((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil){		error = Ealloc;		goto out;	}	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(error = mkqidcmp(&file->qid, d))		goto out;	if(t = file->tlock) {		tim = time(0);		if(t->time < tim || t->file != file){			error = Ebroken;			goto out;		}		/* renew the lock */		t->time = tim + TLOCK;	}	accessdir(p, d, FWRITE);	if(d->mode & DAPND)		offset = d->size;	if(offset+count > d->size)		d->size = offset+count;	while(count > 0){		if(p == nil){			p = getbuf(file->fs->dev, file->addr, Bread|Bmod);			if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){				error = Ealloc;				goto out;			}		}		addr = offset / BUFSIZE;		o = offset % BUFSIZE;		n = BUFSIZE - o;		if(n > count)			n = count;		qpath = d->qid.path;		p1 = dnodebuf1(p, d, addr, Tfile);		p = nil;		if(p1 == nil) {			error = Efull;			goto out;		}		if(checktag(p1, Tfile, qpath)){			putbuf(p1);			error = Ephase;			goto out;		}		memmove(p1->iobuf+o, f->data+nwrite, n);		p1->flags |= Bmod;		putbuf(p1);		count -= n;		nwrite += n;		offset += n;	}out:	if(p != nil)		putbuf(p);	if(file != nil)		qunlock(file);	r->count = nwrite;	return error;}static int_clunk(File* file, int remove, int wok){	Tlock *t;	int error;	error = 0;	if(t = file->tlock){		if(t->file == file)			t->time = 0;		/* free the lock */		file->tlock = 0;	}	if(remove)		error = doremove(file, wok);	file->open = 0;	freewp(file->wpath);	freefp(file);	qunlock(file);	return error;}static intfsclunk(Chan* chan, Fcall* f, Fcall*){	File *file;	if((file = filep(chan, f->fid, 0)) == nil)		return Efid;	_clunk(file, file->open & FREMOV, 0);	return 0;}static intfsremove(Chan* chan, Fcall* f, Fcall*){	File *file;	if((file = filep(chan, f->fid, 0)) == nil)		return Efid;	return _clunk(file, 1, chan == cons.chan);}static intfsstat(Chan* chan, Fcall* f, Fcall* r, uchar* data){	Dir dir;	Iobuf *p;	Dentry *d;	File *file;	int error, len;	if((file = filep(chan, f->fid, 0)) == nil)		return Efid;	p = getbuf(file->fs->dev, file->addr, Bread);	if(p == nil || checktag(p, Tdir, QPNONE)){		error = Edir1;		goto out;	}	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(error = mkqidcmp(&file->qid, d))		goto out;	if(d->qid.path == QPROOT)	/* stat of root gives time */		d->atime = time(0);	len = dir9p2(&dir, d, data);	data += len;	if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)		error = Ersc;	else		r->stat = data;out:	if(p != nil)		putbuf(p);	if(file != nil)		qunlock(file);	return error;}static intfswstat(Chan* chan, Fcall* f, Fcall*, char *strs){	Iobuf *p, *p1;	Dentry *d, *d1, xd;	File *file;	int error, slot, uid, gid, l;	long addr;	Dir dir;	ulong mode;	p = p1 = nil;	d1 = nil;	if((file = filep(chan, f->fid, 0)) == nil){		error = Efid;		goto out;	}	/*	 * if user none,	 * can't do anything	 * unless allow.	 */	if(file->uid == 0 && !wstatallow){		error = Eaccess;		goto out;	}	if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){		error = Eronly;		goto out;	}	/*	 * first get parent	 */	if(file->wpath){		p1 = getbuf(file->fs->dev, file->wpath->addr, Bread);		if(p1 == nil){			error = Ephase;			goto out;		}		d1 = getdir(p1, file->wpath->slot);		if(d1 == nil || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)){			error = Ephase;			goto out;		}	}	if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){		error = Ealloc;		goto out;	}	d = getdir(p, file->slot);	if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(error = mkqidcmp(&file->qid, d))		goto out;	/*	 * Convert the message and fix up	 * fields not to be changed.	 */	if(convM2D(f->stat, f->nstat, &dir, strs) == 0){		print("9p2: convM2D returns 0\n");		error = Econvert;		goto out;	}	if(dir.uid == nil || strlen(dir.uid) == 0)		uid = d->uid;	else		uid = strtouid(dir.uid);	if(dir.gid == nil || strlen(dir.gid) == 0)		gid = d->gid;	else		gid = strtouid(dir.gid);	if(dir.name == nil || strlen(dir.name) == 0)		dir.name = d->name;	else{		if((l = checkname9p2(dir.name)) == 0){			error = Ename;			goto out;		}		if(l > NAMELEN){			error = Etoolong;			goto out;		}	}	/*	 * Before doing sanity checks, find out what the	 * new 'mode' should be:	 * if 'type' and 'mode' are both defaults, take the	 * new mode from the old directory entry;	 * else if 'type' is the default, use the new mode entry;	 * else if 'mode' is the default, create the new mode from	 * 'type' or'ed with the old directory mode;	 * else neither are defaults, use the new mode but check	 * it agrees with 'type'.	 */	if(dir.qid.type == 0xFF && dir.mode == ~0){		dir.mode = d->mode & 0777;		if(d->mode & DLOCK)			dir.mode |= DMEXCL;		if(d->mode & DAPND)			dir.mode |= DMAPPEND;		if(d->mode & DDIR)			dir.mode |= DMDIR;	}	else if(dir.qid.type == 0xFF){		/* nothing to do */	}	else if(dir.mode == ~0)		dir.mode = (dir.qid.type<<24)|(d->mode & 0777);	else if(dir.qid.type != ((dir.mode>>24) & 0xFF)){		error = Eqidmode;		goto out;	}	/*	 * Check for unknown type/mode bits	 * and an attempt to change the directory bit.	 */	if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){		error = Enotm;		goto out;	}	if(d->mode & DDIR)		mode = DMDIR;	else		mode = 0;	if((dir.mode^mode) & DMDIR){		error = Enotd;		goto out;	}	if(dir.mtime == ~0)		dir.mtime = d->mtime;	if(dir.length == ~0)		dir.length = d->size;	/*	 * Currently, can't change length.	 */	if(dir.length != d->size){		error = Enotl;		goto out;	}	/*	 * if chown,	 * must be god	 * wstatallow set to allow chown during boot	 */	if(uid != d->uid && !wstatallow) {		error = Enotu;		goto out;	}	/*	 * if chgroup,	 * must be either	 *	a) owner and in new group	 *	b) leader of both groups	 * wstatallow and writeallow are set to allow chgrp during boot	 */	while(gid != d->gid) {		if(wstatallow || writeallow)			break;		if(d->uid == file->uid && ingroup(file->uid, gid))			break;		if(leadgroup(file->uid, gid))			if(leadgroup(file->uid, d->gid))				break;		error = Enotg;		goto out;	}	/*	 * if rename,	 * must have write permission in parent	 */	while(strncmp(d->name, dir.name, sizeof(d->name)) != 0) {		if(checkname(dir.name) || d1 == nil) {			error = Ename;			goto out;		}		if(strcmp(dir.name, ".") == 0 || strcmp(xd.name, "..") == 0) {			error = Ename;			goto out;		}		/*		 * drop entry to prevent lock, then		 * check that destination name is unique,		 */		putbuf(p);		for(addr = 0; ; addr++) {			if((p = dnodebuf(p1, d1, addr, 0)) == nil)				break;			if(checktag(p, Tdir, d1->qid.path)) {				putbuf(p);				continue;			}			for(slot = 0; slot < DIRPERBUF; slot++) {				d = getdir(p, slot);				if(!(d->mode & DALLOC))					continue;				if(strncmp(dir.name, d->name, sizeof(d->name)) == 0) {					error = Eexist;					goto out;				}			}			putbuf(p);		}		/*		 * reacquire entry		 */		if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){			error = Ephase;			goto out;		}		d = getdir(p, file->slot);		if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {			error = Ephase;			goto out;		}		if(wstatallow || writeallow) /* set to allow rename during boot */			break;		if(d1 == nil || iaccess(file, d1, DWRITE)) {			error = Eaccess;			goto out;		}		break;	}	/*	 * if mode/time, either	 *	a) owner	 *	b) leader of either group	 */	mode = dir.mode & 0777;	if(dir.mode & DMAPPEND)		mode |= DAPND;	if(dir.mode & DMEXCL)		mode |= DLOCK;	while(d->mtime != dir.mtime || ((d->mode^mode) & (DAPND|DLOCK|0777))) {		if(wstatallow)			/* set to allow chmod during boot */			break;		if(d->uid == file->uid)			break;		if(leadgroup(file->uid, gid))			break;		if(leadgroup(file->uid, d->gid))			break;		error = Enotu;		goto out;	}	d->mtime = dir.mtime;	d->uid = uid;	d->gid = gid;	d->mode = (mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));	strncpy(d->name, dir.name, sizeof(d->name));	accessdir(p, d, FWSTAT);out:	if(p != nil)		putbuf(p);	if(p1 != nil)		putbuf(p1);	if(file != nil)		qunlock(file);	return error;}static intrecv(Chan *c, uchar *buf, int n){	int fd, m, len;	fd = c->chan;	/* read count */	qlock(&c->rlock);	m = readn(fd, buf, BIT32SZ);	if(m != BIT32SZ){		qunlock(&c->rlock);		if(m < 0){			print("readn(BIT32SZ) fails: %r\n");			return -1;		}		print("readn(BIT32SZ) returns %d: %r\n", m);		return 0;	}	len = GBIT32(buf);	if(len <= BIT32SZ || len > n){		print("recv bad length %d\n", len);		werrstr("bad length in 9P2000 message header");		qunlock(&c->rlock);		return -1;	}	len -= BIT32SZ;	m = readn(fd, buf+BIT32SZ, len);	qunlock(&c->rlock);	if(m < len){		print("recv wanted %d got %d\n", len, m);		return 0;	}	return BIT32SZ+m;}static voidsend(Chan *c, uchar *buf, int n){	int fd, m;	fd = c->chan;	qlock(&c->wlock);	m = write(fd, buf, n);	qunlock(&c->wlock);	if(m == n)		return;	panic("write failed");}voidserve9p2(Chan *chan, uchar *ib, int nib){	uchar inbuf[MSIZE+IOHDRSZ], outbuf[MSIZE+IOHDRSZ];	Fcall f, r;	char ename[64];	int error, n, type;	chan->msize = MSIZE;	fmtinstall('F', fcallfmt);	for(;;){		if(nib){			memmove(inbuf, ib, nib);			n = nib;			nib = 0;		}else			n = recv(chan, inbuf, sizeof inbuf);		if(chat){			print("read msg %d (fd %d)\n", n, chan->chan);			if(n <= 0)				print("\terr: %r\n");		}		if(n == 0 && (chan == cons.srvchan || chan == cons.chan))			continue;		if(n <= 0)			break;		if(convM2S(inbuf, n, &f) != n){			print("9p2: cannot decode\n");			continue;		}		type = f.type;		if(type < Tversion || type >= Tmax || (type&1) || type == Terror){			print("9p2: bad message type %d\n", type);			continue;		}		if(CHAT(chan))			print("9p2: f %F\n", &f);		r.type = type+1;		r.tag = f.tag;		error = 0;		rlock(&mainlock);		rlock(&chan->reflock);		switch(type){		default:			r.type = Rerror;			snprint(ename, sizeof ename, "unknown message: %F", &f);			r.ename = ename;			break;		case Tversion:			error = fsversion(chan, &f, &r);			break;		case Tauth:			error = fsauth(chan, &f, &r);			break;		case Tattach:			error = fsattach(chan, &f, &r);			break;		case Tflush:			error = fsflush(chan, &f, &r);			break;		case Twalk:			error = fswalk(chan, &f, &r);			break;		case Topen:			error = fsopen(chan, &f, &r);			break;		case Tcreate:			error = fscreate(chan, &f, &r);			break;		case Tread:			r.data = (char*)inbuf;			error = fsread(chan, &f, &r);			break;		case Twrite:			error = fswrite(chan, &f, &r);			break;		case Tclunk:			error = fsclunk(chan, &f, &r);			break;		case Tremove:			error = fsremove(chan, &f, &r);			break;		case Tstat:			error = fsstat(chan, &f, &r, inbuf);			break;		case Twstat:			error = fswstat(chan, &f, &r, (char*)outbuf);			break;		}		runlock(&chan->reflock);		runlock(&mainlock);		if(error != 0){			r.type = Rerror;			if(error >= MAXERR){				snprint(ename, sizeof(ename), "error %d", error);				r.ename = ename;			}			else				r.ename = errstring[error];		}		if(CHAT(chan))			print("9p2: r %F\n", &r);			n = convS2M(&r, outbuf, sizeof outbuf);		if(n == 0){			type = r.type;			r.type = Rerror;			snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type);			r.ename = ename;			print(ename);			n = convS2M(&r, outbuf, sizeof outbuf);			if(n == 0){				/*				 * What to do here, the failure notification failed?				 */				panic("can't write anything at all");			}		}		send(chan, outbuf, n);	}	fileinit(chan);	close(chan->chan);	if(chan == cons.srvchan || chan == cons.chan)		print("console chan read error");}

⌨️ 快捷键说明

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