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

📄 9p2.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	else if(file->fs->dev->type == Devro){		error = Eronly;		goto out;	}	if ((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil ||	    (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 = toytime();		if(t->time < tim || t->file != file){			error = Ebroken;			goto out;		}		/* renew the lock */		t->time = tim + TLOCK;	}	accessdir(p, d, FWRITE, file->uid);	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(p == nil){				error = Ealloc;				goto out;			}			d = getdir(p, file->slot);			if(d == 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, file->uid);		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 && (file->qid.type & QTAUTH) == 0)		error = doremove(file, wok);	file->open = 0;	freewp(file->wpath);	authfree(file->auth);	freefp(file);	qunlock(file);	return error;}static intclunk(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 intremove(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 intstat(Chan* chan, Fcall* f, Fcall* r, uchar* data){	Dir dir;	Iobuf *p;	Dentry *d, dentry;	File *file;	int error, len;	error = 0;	p = nil;	if((file = filep(chan, f->fid, 0)) == nil)		return Efid;	if(file->qid.type & QTAUTH){		memset(&dentry, 0, sizeof dentry);		d = &dentry;		mkqid9p1(&d->qid, &file->qid);		strcpy(d->name, "#¿");		d->uid = authuid(file->auth);		d->gid = d->uid;		d->muid = d->uid;		d->atime = time();		d->mtime = d->atime;		d->size = 0;	} else {		p = getbuf(file->fs->dev, file->addr, Bread);		if(p == nil || checktag(p, Tdir, QPNONE)){			error = Edir1;			goto out;		}		d = getdir(p, file->slot);		if(d == 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();	}	len = mkdir9p2(&dir, d, data);	data += len;	if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)		error = Eedge;	r->stat = data;out:	if(p != nil)		putbuf(p);	if(file != nil)		qunlock(file);	return error;}static intwstat(Chan* chan, Fcall* f, Fcall*, char* strs){	Iobuf *p, *p1;	Dentry *d, *d1;	File *file;	int error, err, gid, gl, muid, op, slot, tsync, uid;	long addr;	Dir dir;	if(convM2D(f->stat, f->nstat, &dir, strs) == 0)		return Econvert;	/*	 * Get the file.	 * If user 'none' (uid == 0), can't do anything;	 * if filesystem is read-only, can't change anything.	 */	if((file = filep(chan, f->fid, 0)) == nil)		return Efid;	p = p1 = nil;	if(file->uid == 0){		error = Eaccess;		goto out;	}	if(file->fs->dev->type == Devro){		error = Eronly;		goto out;	}	if(file->qid.type & QTAUTH){		error = Emode;		goto out;	}	/*	 * Get the current entry and check it is still valid.	 */	p = getbuf(file->fs->dev, file->addr, Bread);	if(p == nil || checktag(p, Tdir, QPNONE)){		error = Ealloc;		goto out;	}	d = getdir(p, file->slot);	if(d == nil || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(error = mkqidcmp(&file->qid, d))		goto out;	/*	 * Run through each of the (sub-)fields in the provided Dir	 * checking for validity and whether it's a default:	 * .type, .dev and .atime are completely ignored and not checked;	 * .qid.path, .qid.vers and .muid are checked for validity but	 * any attempt to change them is an error.	 * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can	 * possibly be changed.	 *	 * 'Op' flags there are changed fields, i.e. it's not a no-op.	 * 'Tsync' flags all fields are defaulted.	 *	 * Wstatallow and writeallow are set to allow changes during the	 * fileserver bootstrap phase.	 */	tsync = 1;	if(dir.qid.path != ~0){		if(dir.qid.path != file->qid.path){			error = Ewstatp;			goto out;		}		tsync = 0;	}	if(dir.qid.vers != ~0){		if(dir.qid.vers != file->qid.vers){			error = Ewstatv;			goto out;		}		tsync = 0;	}	if(dir.muid != nil && *dir.muid != '\0'){		muid = strtouid(dir.muid);		if(muid != d->muid && !wstatallow){			error = Ewstatm;			goto out;		}		tsync = 0;	}	/*	 * .qid.type and .mode have some bits in common. Only .mode	 * is currently needed for comparisons with the old mode but	 * if there are changes to the bits also encoded in .qid.type	 * then file->qid must be updated appropriately later.	 */	if(dir.qid.type == (uchar)~0){		if(dir.mode == ~0)			dir.qid.type = mktype9p2(d->mode);		else			dir.qid.type = dir.mode>>24;	}	else		tsync = 0;	if(dir.mode == ~0)		dir.mode = mkmode9p2(d->mode);	else		tsync = 0;	/*	 * Check dir.qid.type and dir.mode agree, check for any unknown	 * type/mode bits, check for an attempt to change the directory bit.	 */	if(dir.qid.type != ((dir.mode>>24) & 0xFF)){		error = Ewstatq;		goto out;	}	if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){		error = Ewstatb;		goto out;	}	op = dir.mode^mkmode9p2(d->mode);	if(op & DMDIR){		error = Ewstatd;		goto out;	}	if(dir.mtime != ~0){		if(dir.mtime != d->mtime)			op = 1;		tsync = 0;	}	else		dir.mtime = d->mtime;	if(dir.length == ~(Off)0)		dir.length = d->size;	else {		if (dir.length < 0) {			error = Ewstatl;			goto out;		} else if(dir.length != d->size)			op = 1;		tsync = 0;	}	/*	 * Check for permission to change .mode, .mtime or .length,	 * must be owner or leader of either group, for which test gid	 * is needed; permission checks on gid will be done later.	 * 'Gl' counts whether neither, one or both groups are led.	 */	if(dir.gid != nil && *dir.gid != '\0'){		gid = strtouid(dir.gid);		tsync = 0;	}	else		gid = d->gid;	gl = leadgroup(file->uid, gid) != 0;	gl += leadgroup(file->uid, d->gid) != 0;	if(op && !wstatallow && d->uid != file->uid && !gl){		error = Ewstato;		goto out;	}	/*	 * Rename.	 * Check .name is valid and different to the current.	 */	if(dir.name != nil && *dir.name != '\0'){		if(error = checkname9p2(dir.name))			goto out;		if(strncmp(dir.name, d->name, NAMELEN))			op = 1;		else			dir.name = d->name;		tsync = 0;	}	else		dir.name = d->name;	/*	 * If the name is really to be changed check it's unique	 * and there is write permission in the parent.	 */	if(dir.name != d->name){		/*		 * First get parent.		 * Must drop current entry to prevent		 * deadlock when searching that new name		 * already exists below.		 */		putbuf(p);		p = nil;		if(file->wpath == nil){			error = Ephase;			goto out;		}		p1 = getbuf(file->fs->dev, file->wpath->addr, Bread);		if(p1 == nil || checktag(p1, Tdir, QPNONE)){			error = Ephase;			goto out;		}		d1 = getdir(p1, file->wpath->slot);		if(d1 == nil || !(d1->mode & DALLOC)){			error = Ephase;			goto out;		}		/*		 * Check entries in parent for new name.		 */		for(addr = 0; ; addr++){			if((p = dnodebuf(p1, d1, addr, 0, file->uid)) == 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) ||				   strncmp(dir.name, d->name, sizeof d->name))					continue;				error = Eexist;				goto out;			}			putbuf(p);		}		/*		 * Reacquire entry and check it's still OK.		 */		p = getbuf(file->fs->dev, file->addr, Bread);		if(p == nil || checktag(p, Tdir, QPNONE)){			error = Ephase;			goto out;		}		d = getdir(p, file->slot);		if(d == nil || !(d->mode & DALLOC)){			error = Ephase;			goto out;		}		/*		 * Check write permission in the parent.		 */		if(!wstatallow && !writeallow && iaccess(file, d1, DWRITE)){			error = Eaccess;			goto out;		}	}	/*	 * Check for permission to change owner - must be god.	 */	if(dir.uid != nil && *dir.uid != '\0'){		uid = strtouid(dir.uid);		if(uid != d->uid){			if(!wstatallow){				error = Ewstatu;				goto out;			}			op = 1;		}		tsync = 0;	}	else		uid = d->uid;	/*	 * Check for permission to change group, must be	 * either owner and in new group or leader of both groups.	 */	if(gid != d->gid){		if(!(wstatallow || writeallow)		&& !(d->uid == file->uid && ingroup(file->uid, gid))		&& !(gl == 2)){			error = Ewstatg;			goto out;		}		op = 1;	}	/*	 * Checks all done, update if necessary.	 */	if(op){		d->mode = mkmode9p1(dir.mode);		file->qid.type = mktype9p2(d->mode);		d->mtime = dir.mtime;		if (dir.length < d->size) {			err = dtrunclen(p, d, dir.length, uid);			if (error == 0)				error = err;		}		d->size = dir.length;		if(dir.name != d->name)			strncpy(d->name, dir.name, sizeof(d->name));		d->uid = uid;		d->gid = gid;	}	if(!tsync)		accessdir(p, d, FREAD, file->uid);out:	if(p != nil)		putbuf(p);	if(p1 != nil)		putbuf(p1);	qunlock(file);	return error;}intserve9p2(Msgbuf* mb){	Chan *chan;	Fcall f, r;	Msgbuf *data, *rmb;	char ename[64];	int error, n, type;	static int once;	if(once == 0){		fmtinstall('F', fcallfmt);		once = 1;	}	/*	 * 0 return means i don't understand this message,	 * 1 return means i dealt with it, including error	 * replies.	 */	if(convM2S(mb->data, mb->count, &f) != mb->count){print("didn't like %d byte message\n", mb->count);		return 0;}	type = f.type;	if(type < Tversion || type >= Tmax || (type & 1) || type == Terror)		return 0;	chan = mb->chan;	if(CHAT(chan))		print("9p2: f %F\n", &f);	r.type = type+1;	r.tag = f.tag;	error = 0;	data = nil;	switch(type){	default:		r.type = Rerror;		snprint(ename, sizeof(ename), "unknown message: %F", &f);		r.ename = ename;		break;	case Tversion:		error = version(chan, &f, &r);		break;	case Tauth:		error = auth(chan, &f, &r);		break;	case Tattach:		error = attach(chan, &f, &r);		break;	case Tflush:		error = flush(chan, &f, &r);		break;	case Twalk:		error = walk(chan, &f, &r);		break;	case Topen:		error = open(chan, &f, &r);		break;	case Tcreate:		error = create(chan, &f, &r);		break;	case Tread:		data = mballoc(chan->msize, chan, Mbreply1);		error = read(chan, &f, &r, data->data);		break;	case Twrite:		error = write(chan, &f, &r);		break;	case Tclunk:		error = clunk(chan, &f, &r);		break;	case Tremove:		error = remove(chan, &f, &r);		break;	case Tstat:		data = mballoc(chan->msize, chan, Mbreply1);		error = stat(chan, &f, &r, data->data);		break;	case Twstat:		data = mballoc(chan->msize, chan, Mbreply1);		error = wstat(chan, &f, &r, (char*)data->data);		break;	}	if(error != 0){		r.type = Rerror;		if(error >= MAXERR){			snprint(ename, sizeof(ename), "error %d", error);			r.ename = ename;		}		else			r.ename = errstr9p[error];	}	if(CHAT(chan))		print("9p2: r %F\n", &r);	rmb = mballoc(chan->msize, chan, Mbreply2);	n = convS2M(&r, rmb->data, chan->msize);	if(data != nil)		mbfree(data);	if(n == 0){		type = r.type;		r.type = Rerror;		/*		 * If a Tversion has not been seen on the chan then		 * chan->msize will be 0. In that case craft a special		 * Rerror message. It's fortunate that the mballoc above		 * for rmb will have returned a Msgbuf of MAXMSG size		 * when given a request with count of 0...		 */		if(chan->msize == 0){			r.ename = "Tversion not seen";			n = convS2M(&r, rmb->data, MAXMSG);		}		else{			snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type);			r.ename = ename;			n = convS2M(&r, rmb->data, chan->msize);		}		print("%s\n", r.ename);		if(n == 0){			/*			 * What to do here, the failure notification failed?			 */			mbfree(rmb);			return 1;		}	}	rmb->count = n;	rmb->param = mb->param;	send(chan->reply, rmb);	return 1;}

⌨️ 快捷键说明

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