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

📄 9p2.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#include "all.h"/* * stuff from /sys/include/libc.h for 9P2000 */#define	STATMAX	65535U	/* max length of machine-independent stat structure */#define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */#define	ERRMAX	128	/* max length of error string *//* bits in Dir.mode */#define DMDIR		0x80000000	/* mode bit for directories */#define DMAPPEND	0x40000000	/* mode bit for append only files */#define DMEXCL		0x20000000	/* mode bit for exclusive use files */#define DMMOUNT		0x10000000	/* mode bit for mounted channel */#define DMREAD		0x4		/* mode bit for read permission */#define DMWRITE		0x2		/* mode bit for write permission */#define DMEXEC		0x1		/* mode bit for execute permission */typedefstruct Dir {	/* system-modified data */	ushort	type;	/* server type */	uint	dev;	/* server subtype */	/* file data */	Qid	qid;	/* unique id from server */	ulong	mode;	/* permissions */	ulong	atime;	/* last read time */	ulong	mtime;	/* last write time */	vlong	length;	/* file length: see <u.h> */	char	*name;	/* last element of path */	char	*uid;	/* owner name */	char	*gid;	/* group name */	char	*muid;	/* last modifier name */} Dir;#define MSIZE	(MAXDAT+MAXMSG)#include "fcall.h"static intmkmode9p1(ulong mode9p2){	int mode;	/*	 * Assume this is for an allocated entry.	 */	mode = DALLOC|(mode9p2 & 0777);	if(mode9p2 & DMEXCL)		mode |= DLOCK;	if(mode9p2 & DMAPPEND)		mode |= DAPND;	if(mode9p2 & DMDIR)		mode |= DDIR;	return mode;}voidmkqid9p1(Qid9p1* qid9p1, Qid* qid){	if(qid->path & 0xFFFFFFFF00000000LL)		panic("mkqid9p1: path %lluX\n", (Wideoff)qid->path);	qid9p1->path = qid->path & 0xFFFFFFFF;	if(qid->type & QTDIR)		qid9p1->path |= QPDIR;	qid9p1->version = qid->vers;}static intmktype9p2(int mode9p1){	int type;	type = 0;	if(mode9p1 & DLOCK)		type |= QTEXCL;	if(mode9p1 & DAPND)		type |= QTAPPEND;	if(mode9p1 & DDIR)		type |= QTDIR;	return type;}static ulongmkmode9p2(int mode9p1){	ulong mode;	mode = mode9p1 & 0777;	if(mode9p1 & DLOCK)		mode |= DMEXCL;	if(mode9p1 & DAPND)		mode |= DMAPPEND;	if(mode9p1 & DDIR)		mode |= DMDIR;	return mode;}voidmkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1){	qid->path = (ulong)(qid9p1->path & ~QPDIR);	qid->vers = qid9p1->version;	qid->type = mktype9p2(mode9p1);}static intmkdir9p2(Dir* dir, Dentry* dentry, void* strs){	char *op, *p;	memset(dir, 0, sizeof(Dir));	mkqid(&dir->qid, dentry, 1);	dir->mode = mkmode9p2(dentry->mode);	dir->atime = dentry->atime;	dir->mtime = dentry->mtime;	dir->length = dentry->size;	op = p = strs;	dir->name = p;	p += sprint(p, "%s", dentry->name)+1;	dir->uid = p;	uidtostr(p, dentry->uid, 1);	p += strlen(p)+1;	dir->gid = p;	uidtostr(p, dentry->gid, 1);	p += strlen(p)+1;	dir->muid = p;	uidtostr(p, dentry->muid, 1);	p += strlen(p)+1;	return p-op;}static intcheckname9p2(char* name){	char *p;	/*	 * Return error or 0 if OK.	 */	if(name == nil || *name == 0)		return Ename;	for(p = name; *p != 0; p++){		if(p-name >= NAMELEN-1)			return Etoolong;		if((*p & 0xFF) <= 040)			return Ename;	}	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)		return Edot;	return 0;}static intversion(Chan* chan, Fcall* f, Fcall* r){	if(chan->protocol != nil)		return Eversion;	if(f->msize < MSIZE)		r->msize = f->msize;	else		r->msize = MSIZE;	/*	 * Should check the '.' stuff here.	 */	if(strcmp(f->version, VERSION9P) == 0){		r->version = VERSION9P;		chan->protocol = serve9p2;		chan->msize = r->msize;	}	else		r->version = "unknown";	fileinit(chan);	return 0;}struct{	Lock;	ulong	hi;} authpath;static intauth(Chan* chan, Fcall* f, Fcall* r){	char *aname;	File *file;	Filsys *fs;	int error;	if(cons.flags & authdisableflag)		return Eauthdisabled;	error = 0;	aname = f->aname;	if(strcmp(f->uname, "none") == 0)		return Eauthnone;	if(!aname[0])	/* default */		aname = "main";	file = filep(chan, f->afid, 1);	if(file == nil){		error = Efidinuse;		goto out;	}	fs = fsstr(aname);	if(fs == nil){		error = Ebadspc;		goto out;	}	lock(&authpath);	file->qid.path = authpath.hi++;	unlock(&authpath);	file->qid.type = QTAUTH;	file->qid.vers = 0;	file->fs = fs;	file->open = FREAD+FWRITE;	freewp(file->wpath);	file->wpath = 0;	file->auth = authnew(f->uname, f->aname);	if(file->auth == nil){		error = Eauthfile;		goto out;	}	r->aqid = file->qid;out:	if((cons.flags & attachflag) && error)		print("9p2: auth %s %T SUCK EGGS --- %s\n",			f->uname, time(), errstr9p[error]);	if(file != nil){		qunlock(file);		if(error)			freefp(file);	}	return error;}intauthorize(Chan* chan, Fcall* f){	File* af;	int uid = -1;	int db;	db = cons.flags & authdebugflag;	if(strcmp(f->uname, "none") == 0){		uid = strtouid(f->uname);		if(db)			print("permission granted to none: uid %s = %d\n", f->uname, uid);		return uid;	}	if(cons.flags & authdisableflag){		uid = strtouid(f->uname);		if(db)			print("permission granted by authdisable uid %s = %d\n", f->uname, uid);		return uid;	}	af = filep(chan, f->afid, 0);	if(af == nil){		if(db)			print("authorize: af == nil\n");		return -1;	}	if(af->auth == nil){		if(db)			print("authorize: af->auth == nil\n");		goto out;	}	if(strcmp(f->uname, authuname(af->auth)) != 0){		if(db)			print("authorize: strcmp(f->uname, authuname(af->auth)) != 0\n");		goto out;	}	if(strcmp(f->aname, authaname(af->auth)) != 0){		if(db)			print("authorize: strcmp(f->aname, authaname(af->auth)) != 0\n");		goto out;	}	uid = authuid(af->auth);	if(db)		print("authorize: uid is %d\n", uid);out:	qunlock(af);	return uid;}static intattach(Chan* chan, Fcall* f, Fcall* r){	char *aname;	Iobuf *p;	Dentry *d;	File *file;	Filsys *fs;	Off raddr;	int error, u;	aname = f->aname;	if(!aname[0])	/* default */		aname = "main";	p = nil;	error = 0;	file = filep(chan, f->fid, 1);	if(file == nil){		error = Efidinuse;		goto out;	}	u = -1;	if(chan != cons.chan){		if(noattach && strcmp(f->uname, "none")) {			error = Enoattach;			goto out;		}		u = authorize(chan, f);		if(u < 0){			error = Ebadu;			goto out;		}	}	file->uid = u;	fs = fsstr(aname);	if(fs == nil){		error = Ebadspc;		goto out;	}	raddr = getraddr(fs->dev);	p = getbuf(fs->dev, raddr, Bread);	if(p == nil || checktag(p, Tdir, QPROOT)){		error = Ealloc;		goto out;	}	d = getdir(p, 0);	if(d == nil || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if (iaccess(file, d, DEXEC) ||	    file->uid == 0 && fs->dev->type == Devro) {		/*		 * 'none' not allowed on dump		 */		error = Eaccess;		goto out;	}	accessdir(p, d, FREAD, file->uid);	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;	strncpy(chan->whoname, f->uname, sizeof(chan->whoname));	chan->whotime = time();	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(), errstr9p[error]);	if(p != nil)		putbuf(p);	if(file != nil){		qunlock(file);		if(error)			freefp(file);	}	return error;}static intflush(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->open = file->open & ~FREMOV;}static intwalkname(File* file, char* wname, Qid* wqid){	Wpath *w;	Iobuf *p, *p1;	Dentry *d, *d1;	int error, slot;	Off 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;	}	d = getdir(p, file->slot);	if(d == 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, file->uid);	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;		}		d1 = getdir(p1, slot);		if(d == 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, file->uid);		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) ||			    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 intwalk(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);

⌨️ 快捷键说明

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