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

📄 9p2.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	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 intopen(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;	}	if(file->open != 0){		error = Emode;		goto out;	}	/*	 * if remove on close, check access here	 */	ro = file->fs->dev->type == Devro;	if(f->mode & ORCLOSE){		if(ro){			error = Eronly;			goto out;		}		/*		 * check on parent directory of file to be deleted		 */		if(file->wpath == 0 || file->wpath->addr == file->addr){			error = Ephase;			goto out;		}		p = getbuf(file->fs->dev, file->wpath->addr, Bread);		if(p == nil || checktag(p, Tdir, QPNONE)){			error = Ephase;			goto out;		}		d = getdir(p, file->wpath->slot);		if(d == nil || !(d->mode & DALLOC)){			error = Ephase;			goto out;		}		if(iaccess(file, d, DWRITE)){			error = Eaccess;			goto out;		}		putbuf(p);	}	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;	mkqid(&qid, d, 1);	switch(f->mode & 7){	case OREAD:		if(iaccess(file, d, DREAD) && !wok)			goto badaccess;		fmod = FREAD;		break;	case OWRITE:		if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))			goto badaccess;		if(ro){			error = Eronly;			goto out;		}		fmod = FWRITE;		break;	case ORDWR:		if((d->mode & DDIR)		|| (iaccess(file, d, DREAD) && !wok)		|| (iaccess(file, d, DWRITE) && !wok))			goto badaccess;		if(ro){			error = Eronly;			goto out;		}		fmod = FREAD+FWRITE;		break;	case OEXEC:		if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok))			goto badaccess;		fmod = FREAD;		break;	default:		error = Emode;		goto out;	}	if(f->mode & OTRUNC){		if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))			goto badaccess;		if(ro){			error = Eronly;			goto out;		}	}	t = 0;	if(d->mode & DLOCK){		if((t = tlocked(p, d)) == nil){			error = Elocked;			goto out;		}	}	if(f->mode & ORCLOSE)		fmod |= FREMOV;	file->open = fmod;	if((f->mode & OTRUNC) && !(d->mode & DAPND)){		dtrunc(p, d, file->uid);		qid.vers = d->qid.version;	}	r->qid = qid;	file->tlock = t;	if(t != nil)		t->file = file;	file->lastra = 1;	goto out;badaccess:	error = Eaccess;	file->open = 0;out:	if(p != nil)		putbuf(p);	if(file != nil)		qunlock(file);	r->iounit = chan->msize-IOHDRSZ;	return error;}static intcreate(Chan* chan, Fcall* f, Fcall* r){	Iobuf *p, *p1;	Dentry *d, *d1;	File *file;	int error, slot, slot1, fmod, wok;	Off addr, addr1, path;	Tlock *t;	Wpath *w;	wok = 0;	p = nil;	if(chan == cons.chan || writeallow)		wok = 1;	if((file = filep(chan, f->fid, 0)) == nil){		error = Efid;		goto out;	}	if(file->fs->dev->type == Devro){		error = Eronly;		goto out;	}	if(file->qid.type & QTAUTH){		error = Emode;		goto out;	}	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;	if(!(d->mode & DDIR)){		error = Edir2;		goto out;	}	if(iaccess(file, d, DWRITE) && !wok) {		error = Eaccess;		goto out;	}	accessdir(p, d, FREAD, file->uid);	/*	 * Check the name is valid (and will fit in an old	 * directory entry for the moment).	 */	if(error = checkname9p2(f->name))		goto out;	addr1 = 0;	slot1 = 0;	/* set */	for(addr = 0; ; addr++){		if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){			if(addr1 != 0)				break;			p1 = dnodebuf(p, d, addr, Tdir, file->uid);		}		if(p1 == nil){			error = Efull;			goto out;		}		if(checktag(p1, Tdir, d->qid.path)){			putbuf(p1);			goto phase;		}		for(slot = 0; slot < DIRPERBUF; slot++){			d1 = getdir(p1, slot);			if(!(d1->mode & DALLOC)){				if(addr1 == 0){					addr1 = p1->addr;					slot1 = slot + addr*DIRPERBUF;				}				continue;			}			if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){				putbuf(p1);				error = Eexist;				goto out;			}		}		putbuf(p1);	}	switch(f->mode & 7){	case OEXEC:	case OREAD:		/* seems only useful to make directories */		fmod = FREAD;		break;	case OWRITE:		fmod = FWRITE;		break;	case ORDWR:		fmod = FREAD+FWRITE;		break;	default:		error = Emode;		goto out;	}	if(f->perm & PDIR)		if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE))			goto badaccess;	/*	 * do it	 */	path = qidpathgen(file->fs->dev);	if((p1 = getbuf(file->fs->dev, addr1, Bread|Bimm|Bmod)) == nil)		goto phase;	d1 = getdir(p1, slot1);	if(d1 == nil || checktag(p1, Tdir, d->qid.path)) {		putbuf(p1);		goto phase;	}	if(d1->mode & DALLOC){		putbuf(p1);		goto phase;	}	strncpy(d1->name, f->name, sizeof(d1->name));	if(chan == cons.chan){		d1->uid = cons.uid;		d1->gid = cons.gid;	}	else{		d1->uid = file->uid;		d1->gid = d->gid;		f->perm &= d->mode | ~0666;		if(f->perm & PDIR)			f->perm &= d->mode | ~0777;	}	d1->qid.path = path;	d1->qid.version = 0;	d1->mode = DALLOC | (f->perm & 0777);	if(f->perm & PDIR) {		d1->mode |= DDIR;		d1->qid.path |= QPDIR;	}	if(f->perm & PAPND)		d1->mode |= DAPND;	t = nil;	if(f->perm & PLOCK){		d1->mode |= DLOCK;		t = tlocked(p1, d1);		/* if nil, out of tlock structures */	}	accessdir(p1, d1, FWRITE, file->uid);	mkqid(&r->qid, d1, 0);	putbuf(p1);	accessdir(p, d, FWRITE, file->uid);	/*	 * do a walk to new directory entry	 */	if((w = newwp()) == nil){		error = Ewalk;		goto out;	}	w->addr = file->addr;	w->slot = file->slot;	w->up = file->wpath;	file->wpath = w;	file->qid = r->qid;	file->tlock = t;	if(t != nil)		t->file = file;	file->lastra = 1;	if(f->mode & ORCLOSE)		fmod |= FREMOV;	file->open = fmod;	file->addr = addr1;	file->slot = slot1;	goto out;badaccess:	error = Eaccess;	goto out;phase:	error = Ephase;out:	if(p != nil)		putbuf(p);	if(file != nil)		qunlock(file);	r->iounit = chan->msize-IOHDRSZ;	return error;}static intread(Chan* chan, Fcall* f, Fcall* r, uchar* data){	Iobuf *p, *p1;	File *file;	Dentry *d, *d1;	Tlock *t;	Off addr, offset, start;	Timet tim;	int error, iounit, nread, count, n, o, slot;	Msgbuf *dmb;	Dir dir;	p = nil;	error = 0;	count = f->count;	offset = f->offset;	nread = 0;	if((file = filep(chan, f->fid, 0)) == nil){		error = Efid;		goto out;	}	if(!(file->open & FREAD)){		error = Eopen;		goto out;	}	iounit = chan->msize-IOHDRSZ;	if(count < 0 || count > iounit){		error = Ecount;		goto out;	}	if(offset < 0){		error = Eoffset;		goto out;	}	if(file->qid.type & QTAUTH){		nread = authread(file, (uchar*)data, count);		if(nread < 0)			error = Eauth2;		goto out;	}	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;	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, FREAD, file->uid);	if(d->mode & DDIR)		goto dread;	if(offset+count > d->size)		count = d->size - offset;	while(count > 0){		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;			}		}		addr = offset / BUFSIZE;		file->lastra = dbufread(p, d, addr, file->lastra, file->uid);		o = offset % BUFSIZE;		n = BUFSIZE - o;		if(n > count)			n = count;		p1 = dnodebuf1(p, d, addr, 0, file->uid);		p = nil;		if(p1 != nil){			if(checktag(p1, Tfile, QPNONE)){				error = Ephase;				putbuf(p1);				goto out;			}			memmove(data+nread, p1->iobuf+o, n);			putbuf(p1);		}		else			memset(data+nread, 0, n);		count -= n;		nread += n;		offset += n;	}	goto out;dread:	/*	 * Pick up where we left off last time if nothing has changed,	 * otherwise must scan from the beginning.	 */	if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){		addr = file->dslot/DIRPERBUF;		slot = file->dslot%DIRPERBUF;		start = offset;	}	else{		addr = 0;		slot = 0;		start = 0;	}	dmb = mballoc(iounit, chan, Mbreply1);	for (;;) {		if(p == nil){			/*			 * This is just a check to ensure the entry hasn't			 * gone away during the read of each directory block.			 */			p = getbuf(file->fs->dev, file->addr, Bread);			if(p == nil || checktag(p, Tdir, QPNONE)){				error = Ealloc;				goto out1;			}			d = getdir(p, file->slot);			if(d == nil || !(d->mode & DALLOC)){				error = Ealloc;				goto out1;			}		}		p1 = dnodebuf1(p, d, addr, 0, file->uid);		p = nil;		if(p1 == nil)			goto out1;		if(checktag(p1, Tdir, QPNONE)){			error = Ephase;			putbuf(p1);			goto out1;		}		for(; slot < DIRPERBUF; slot++){			d1 = getdir(p1, slot);			if(!(d1->mode & DALLOC))				continue;			mkdir9p2(&dir, d1, dmb->data);			n = convD2M(&dir, data+nread, iounit - nread);			if(n <= BIT16SZ){				putbuf(p1);				goto out1;			}			start += n;			if(start < offset)				continue;			if(count < n){				putbuf(p1);				goto out1;			}			count -= n;			nread += n;			offset += n;		}		putbuf(p1);		slot = 0;		addr++;	}out1:	mbfree(dmb);	if(error == 0){		file->doffset = offset;		file->dvers = file->qid.vers;		file->dslot = slot+DIRPERBUF*addr;	}out:	/*	 * Do we need this any more?	count = f->count - nread;	if(count > 0)		memset(data+nread, 0, count);	 */	if(p != nil)		putbuf(p);	if(file != nil)		qunlock(file);	r->count = nread;	r->data = (char*)data;	return error;}static intwrite(Chan* chan, Fcall* f, Fcall* r){	Iobuf *p, *p1;	Dentry *d;	File *file;	Tlock *t;	Off offset, addr, qpath;	Timet tim;	int count, error, nwrite, o, n;	error = 0;	offset = f->offset;	count = f->count;	nwrite = 0;	p = nil;	if((file = filep(chan, f->fid, 0)) == nil){		error = Efid;		goto out;	}	if(!(file->open & FWRITE)){		error = Eopen;		goto out;	}	if(count < 0 || count > chan->msize-IOHDRSZ){		error = Ecount;		goto out;	}	if(offset < 0) {		error = Eoffset;		goto out;	}	if(file->qid.type & QTAUTH){		nwrite = authwrite(file, (uchar*)f->data, count);		if(nwrite < 0)			error = Eauth2;		goto out;

⌨️ 快捷键说明

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