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

📄 9p2.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#include	"all.h"#define MSIZE	(MAXDAT+128)static voidseterror(Fcall *ou, int err){	if(0 <= err && err < MAXERR)		ou->ename = errstring[err];	else		ou->ename = "unknown error";}static intfsversion(Chan* chan, Fcall* f, Fcall* r){	if(f->msize < MSIZE)		r->msize = f->msize;	else		r->msize = MSIZE;	/*	 * Should check the '.' stuff here.	 * What happens if Tversion has already been seen?	 */	if(strcmp(f->version, VERSION9P) == 0){		r->version = VERSION9P;		chan->msize = r->msize;	}else		r->version = "unknown";	fileinit(chan);	return 0;}char *keyspec = "proto=p9any role=server";static intfsauth(Chan *chan, Fcall *f, Fcall *r){	int err, fd;	char *aname;	File *file;	int afd;	AuthRpc *rpc;	err = 0;	if(chan == cons.srvchan)		return Eauthmsg;	file = filep(chan, f->afid, 1);	if(file == nil)		return Efidinuse;	/* forget any previous authentication */	file->cuid = 0;	if(access("/mnt/factotum", 0) < 0)		if((fd = open("/srv/factotum", ORDWR)) >= 0)			mount(fd, -1, "/mnt", MBEFORE, "");	afd = open("/mnt/factotum/rpc", ORDWR);	if(afd < 0){		err = Esystem;		goto out;	}	rpc = auth_allocrpc(afd);	if(rpc == nil){		close(afd);		err = Esystem;		goto out;	}	file->rpc = rpc;	if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){		err = Esystem;		goto out;	}	aname = f->aname;	if(!aname[0])		aname = "main";	file->fs = fsstr(aname);	if(file->fs == nil){		err = Ebadspc;		goto out;	}	file->uid = strtouid(f->uname);	if(file->uid < 0){		err = Ebadu;		goto out;	}	file->qid.path = 0;	file->qid.vers = 0;	file->qid.type = QTAUTH;	r->qid = file->qid;out:	if(file != nil){		qunlock(file);		if(err != 0)			freefp(file);	}	return err;}intauthread(File *file, uchar *data, int count){	AuthInfo *ai;	AuthRpc *rpc;	int rv;	rpc = file->rpc;	if(rpc == nil)		return -1;	rv = auth_rpc(rpc, "read", nil, 0);	switch(rv){	case ARdone:		ai = auth_getinfo(rpc);		if(ai == nil)			return -1;		if(chat)			print("authread identifies user as %s\n", ai->cuid);		file->cuid = strtouid(ai->cuid);		auth_freeAI(ai);		if(file->cuid == 0)			return -1;		if(chat)			print("%s is a known user\n", ai->cuid);		return 0;	case ARok:		if(count < rpc->narg)			return -1;		memmove(data, rpc->arg, rpc->narg);		return rpc->narg;	case ARphase:		return -1;	default:		return -1;	}}intauthwrite(File *file, uchar *data, int count){	int ret;	ret = auth_rpc(file->rpc, "write", data, count);	if(ret != ARok)		return -1;	return count;}voidmkqid9p1(Qid9p1* qid9p1, Qid* qid){	if(qid->path & 0xFFFFFFFF00000000LL)		panic("mkqid9p1: path %lluX\n", qid->path);	qid9p1->path = qid->path & 0xFFFFFFFF;	if(qid->type & QTDIR)		qid9p1->path |= QPDIR;	qid9p1->version = qid->vers;}voidauthfree(File *fp){	if(fp->rpc != nil){		close(fp->rpc->afd);		free(fp->rpc);		fp->rpc = nil;	}}voidmkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode){	qid->path = (ulong)(qid9p1->path & ~QPDIR);	qid->vers = qid9p1->version;	qid->type = 0;	if(mode & DDIR)		qid->type |= QTDIR;	if(mode & DAPND)		qid->type |= QTAPPEND;	if(mode & DLOCK)		qid->type |= QTEXCL;}static intcheckattach(Chan *chan, File *afile, File *file, Filsys *fs){	uchar buf[1];	if(chan == cons.srvchan || chan == cons.chan)		return 0;	/* if no afile, this had better be none */	if(afile == nil){		if(file->uid == 0){			if(!allownone && !chan->authed)				return Eauth;			return 0;		}		return Eauth;	}	/* otherwise, we'ld better have a usable cuid */	if(!(afile->qid.type&QTAUTH))		return Eauth;	if(afile->uid != file->uid || afile->fs != fs)		return Eauth;	if(afile->cuid <= 0){		if(authread(afile, buf, 0) != 0)			return Eauth;		if(afile->cuid <= 0)			return Eauth;	}	file->uid = afile->cuid;	/* once someone has authenticated on the channel, others can become none */	chan->authed = 1;	return 0;}		static intfsattach(Chan* chan, Fcall* f, Fcall* r){	char *aname;	Iobuf *p;	Dentry *d;	File *file;	File *afile;	Filsys *fs;	long raddr;	int error, u;	aname = f->aname;	if(!aname[0])	/* default */		aname = "main";	p = nil;	afile = filep(chan, f->afid, 0);	file = filep(chan, f->fid, 1);	if(file == nil){		error = Efidinuse;		goto out;	}	u = -1;	if(chan != cons.chan){		if(strcmp(f->uname, "adm") == 0){			error = Eauth;			goto out;		}		u = strtouid(f->uname);		if(u < 0){			error = Ebadu;			goto out;		}	}	file->uid = u;	fs = fsstr(aname);	if(fs == nil){		error = Ebadspc;		goto out;	}	if(error = checkattach(chan, afile, file, fs))		goto out;	raddr = getraddr(fs->dev);	p = getbuf(fs->dev, raddr, Bread);	d = getdir(p, 0);	if(d == nil || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(iaccess(file, d, DEXEC)){		error = Eaccess;		goto out;	}	if(file->uid == 0 && isro(fs->dev)) {		/*		 * 'none' not allowed on dump		 */		error = Eaccess;		goto out;	}	accessdir(p, d, FREAD);	mkqid(&file->qid, d, 1);	file->fs = fs;	file->addr = raddr;	file->slot = 0;	file->open = 0;	freewp(file->wpath);	file->wpath = 0;	r->qid = file->qid;//	if(cons.flags & attachflag)//		print("9p2: attach %s %T to \"%s\" C%d\n",//			chan->whoname, chan->whotime, fs->name, chan->chan);out://	if((cons.flags & attachflag) && error)//		print("9p2: attach %s %T SUCK EGGS --- %s\n",//			f->uname, time(), errstr[error]);	if(p != nil)		putbuf(p);	if(afile != nil)		qunlock(afile);	if(file != nil){		qunlock(file);		if(error)			freefp(file);	}	return error;}static intfsflush(Chan* chan, Fcall*, Fcall*){	runlock(&chan->reflock);	wlock(&chan->reflock);	wunlock(&chan->reflock);	rlock(&chan->reflock);	return 0;}static voidclone(File* nfile, File* file){	Wpath *wpath;	nfile->qid = file->qid;	lock(&wpathlock);	nfile->wpath = file->wpath;	for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up)		wpath->refs++;	unlock(&wpathlock);	nfile->fs = file->fs;	nfile->addr = file->addr;	nfile->slot = file->slot;	nfile->uid = file->uid;	nfile->cuid = 0;	nfile->open = file->open & ~FREMOV;}static intwalkname(File* file, char* wname, Qid* wqid){	Wpath *w;	Iobuf *p, *p1;	Dentry *d, *d1;	int error, slot;	long addr, qpath;	p = p1 = nil;	/*	 * File must not have been opened for I/O by an open	 * or create message and must represent a directory.	 */	if(file->open != 0){		error = Emode;		goto out;	}	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(!(d->mode & DDIR)){		error = Edir1;		goto out;	}	if(error = mkqidcmp(&file->qid, d))		goto out;	/*	 * For walked elements the implied user must	 * have permission to search the directory.	 */	if(file->cp != cons.chan && iaccess(file, d, DEXEC)){		error = Eaccess;		goto out;	}	accessdir(p, d, FREAD);	if(strcmp(wname, ".") == 0){setdot:		if(wqid != nil)			*wqid = file->qid;		goto out;	}	if(strcmp(wname, "..") == 0){		if(file->wpath == 0)			goto setdot;		putbuf(p);		p = nil;		addr = file->wpath->addr;		slot = file->wpath->slot;		p1 = getbuf(file->fs->dev, addr, Bread);		if(p1 == nil || checktag(p1, Tdir, QPNONE)){			error = Edir1;			goto out;		}		if((d1 = getdir(p1, slot)) == nil || !(d1->mode & DALLOC)){			error = Ephase;			goto out;		}		lock(&wpathlock);		file->wpath->refs--;		file->wpath = file->wpath->up;		unlock(&wpathlock);		goto found;	}	for(addr = 0; ; addr++){		if(p == nil){			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;			}		}		qpath = d->qid.path;		p1 = dnodebuf1(p, d, addr, 0);		p = nil;		if(p1 == nil || checktag(p1, Tdir, qpath)){			error = Eentry;			goto out;		}		for(slot = 0; slot < DIRPERBUF; slot++){			d1 = getdir(p1, slot);			if(!(d1->mode & DALLOC))				continue;			if(strncmp(wname, d1->name, NAMELEN) != 0)				continue;			/*			 * update walk path			 */			if((w = newwp()) == nil){				error = Ewalk;				goto out;			}			w->addr = file->addr;			w->slot = file->slot;			w->up = file->wpath;			file->wpath = w;			slot += DIRPERBUF*addr;			goto found;		}		putbuf(p1);		p1 = nil;	}found:	file->addr = p1->addr;	mkqid(&file->qid, d1, 1);	putbuf(p1);	p1 = nil;	file->slot = slot;	if(wqid != nil)		*wqid = file->qid;out:	if(p1 != nil)		putbuf(p1);	if(p != nil)		putbuf(p);	return error;}static intfswalk(Chan* chan, Fcall* f, Fcall* r){	int error, nwname;	File *file, *nfile, tfile;	/*	 * The file identified by f->fid must be valid in the	 * current session and must not have been opened for I/O	 * by an open or create message.	 */	if((file = filep(chan, f->fid, 0)) == nil)		return Efid;	if(file->open != 0){		qunlock(file);		return Emode;	}	/*	 * If newfid is not the same as fid, allocate a new file;	 * a side effect is checking newfid is not already in use (error);	 * if there are no names to walk this will be equivalent to a	 * simple 'clone' operation.	 * Otherwise, fid and newfid are the same and if there are names	 * to walk make a copy of 'file' to be used during the walk as	 * 'file' must only be updated on success.	 * Finally, it's a no-op if newfid is the same as fid and f->nwname	 * is 0.	 */	r->nwqid = 0;	if(f->newfid != f->fid){		if((nfile = filep(chan, f->newfid, 1)) == nil){			qunlock(file);			return Efidinuse;		}	}	else if(f->nwname != 0){		nfile = &tfile;		memset(nfile, 0, sizeof(File));		nfile->cp = chan;		nfile->fid = ~0;	}	else{		qunlock(file);		return 0;	}	clone(nfile, file);	/*	 * Should check name is not too long.	 */	error = 0;	for(nwname = 0; nwname < f->nwname; nwname++){		error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]);		if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid))			break;	}	if(f->nwname == 0){		/*		 * Newfid must be different to fid (see above)		 * so this is a simple 'clone' operation - there's		 * nothing to do except unlock unless there's		 * an error.		 */		if(error){			freewp(nfile->wpath);			qunlock(nfile);			freefp(nfile);		}		else			qunlock(nfile);	}	else if(r->nwqid < f->nwname){		/*		 * Didn't walk all elements, 'clunk' nfile		 * and leave 'file' alone.		 * Clear error if some of the elements were		 * walked OK.		 */		freewp(nfile->wpath);		if(nfile != &tfile){			qunlock(nfile);			freefp(nfile);		}		if(r->nwqid != 0)			error = 0;	}	else{		/*		 * Walked all elements. If newfid is the same		 * as fid must update 'file' from the temporary		 * copy used during the walk.		 * Otherwise just unlock (when using tfile there's		 * no need to unlock as it's a local).		 */		if(nfile == &tfile){			file->qid = nfile->qid;			freewp(file->wpath);			file->wpath = nfile->wpath;			file->addr = nfile->addr;			file->slot = nfile->slot;		}		else			qunlock(nfile);	}	qunlock(file);	return error;}static intfsopen(Chan* chan, Fcall* f, Fcall* r){	Iobuf *p;	Dentry *d;	File *file;	Tlock *t;	Qid qid;	int error, ro, fmod, wok;	wok = 0;	p = nil;	if(chan == cons.chan || writeallow)		wok = 1;	if((file = filep(chan, f->fid, 0)) == nil){		error = Efid;		goto out;	}

⌨️ 快捷键说明

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