1550 lines · 24.3 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h"#include "io.h" enum {	Slop = 256,	/* room at the start of a message buf for proto hdrs */}; Filsys*fsstr(char *p){	Filsys *fs; 	for(fs=filsys; fs->name; fs++)		if(strcmp(fs->name, p) == 0)			return fs;	return 0;} Filsys*dev2fs(Device *dev){	Filsys *fs; 	for(fs=filsys; fs->name; fs++)		if(fs->dev == dev)			return fs;	return 0;} /* * allocate 'count' contiguous channels * of type 'type' and return pointer to base */Chan*fs_chaninit(int type, int count, int data){	uchar *p;	Chan *cp, *icp;	int i; 	p = malloc(count * (sizeof(Chan)+data));	icp = (Chan*)p;	for(i = 0; i < count; i++) {		cp = (Chan*)p;		cp->next = chans;		chans = cp;		cp->type = type;		cp->chan = cons.chano;		cons.chano++;		strncpy(cp->whoname, "<none>", sizeof cp->whoname);		wlock(&cp->reflock);		wunlock(&cp->reflock);		rlock(&cp->reflock);		runlock(&cp->reflock); 		p += sizeof(Chan);		if(data){			cp->pdata = p;			p += data;		}	}	return icp;} voidfileinit(Chan *cp){	File *f, *prev;	Tlock *t;	int h; loop:	lock(&flock);	for (h=0; h < nelem(flist); h++)		for (prev=0, f = flist[h]; f; prev=f, f=f->next) {			if(f->cp != cp)				continue;			if(prev) {				prev->next = f->next;				f->next = flist[h];				flist[h] = f;			}			flist[h] = f->next;			unlock(&flock); 			qlock(f);			if(t = f->tlock) {				if(t->file == f)					t->time = 0;	/* free the lock */				f->tlock = 0;			}			if(f->open & FREMOV)				doremove(f, 0);			freewp(f->wpath);			f->open = 0;			authfree(f->auth);			f->auth = 0;			f->cp = 0;			qunlock(f);			goto loop;		}	unlock(&flock);} enum { NOFID = (ulong)~0 }; /* * returns a locked file structure */File*filep(Chan *cp, ulong fid, int flag){	File *f;	int h; 	if(fid == NOFID)		return 0; 	h = (long)(uintptr)cp + fid;	if(h < 0)		h = ~h;	h %= nelem(flist); loop:	lock(&flock);	for(f=flist[h]; f; f=f->next)		if(f->fid == fid && f->cp == cp){			/*			 * Already in use is an error			 * when called from attach or clone (walk			 * in 9P2000). The console uses FID[12] and			 * never clunks them so catch that case.			 */			if(flag == 0 || cp == cons.chan)				goto out;			unlock(&flock);			return 0;		} 	if(flag) {		f = newfp();		if(f) {			f->fid = fid;			f->cp = cp;			f->wpath = 0;			f->tlock = 0;			f->doffset = 0;			f->dslot = 0;			f->auth = 0;			f->next = flist[h];			flist[h] = f;			goto out;		}	}	unlock(&flock);	return 0; out:	unlock(&flock);	qlock(f);	if(f->fid == fid && f->cp == cp)		return f;	qunlock(f);	goto loop;} /* * always called with flock locked */File*newfp(void){	static int first;	File *f;	int start, i; 	i = first;	start = i;	do {		f = &files[i];		i++;		if(i >= conf.nfile)			i = 0;		if(f->cp)			continue;		first = i;		return f;	} while(i != start); 	print("out of files\n");	return 0;} voidfreefp(File *fp){	Chan *cp;	File *f, *prev;	int h; 	if(!fp || !(cp = fp->cp))		return; 	h = (long)(uintptr)cp + fp->fid;	if(h < 0)		h = ~h;	h %= nelem(flist); 	lock(&flock);	for(prev=0,f=flist[h]; f; prev=f,f=f->next)		if(f == fp) {			if(prev)				prev->next = f->next;			else				flist[h] = f->next;			break;		}	fp->cp = 0;	unlock(&flock);} intiaccess(File *f, Dentry *d, int m){	/* uid none gets only other permissions */	if(f->uid != 0) {		/*		 * owner		 */		if(f->uid == d->uid)			if((m<<6) & d->mode)				return 0;		/*		 * group membership		 */		if(ingroup(f->uid, d->gid))			if((m<<3) & d->mode)				return 0;	} 	/*	 * other	 */	if(m & d->mode) {		if((d->mode & DDIR) && (m == DEXEC))			return 0;		if(!ingroup(f->uid, 9999))			return 0;	} 	/*	 * various forms of superuser	 */	if(wstatallow)		return 0;	if(duallow != 0 && duallow == f->uid)		if((d->mode & DDIR) && (m == DREAD || m == DEXEC))			return 0; 	return 1;} Tlock*tlocked(Iobuf *p, Dentry *d){	Tlock *t, *t1;	Off qpath;	Timet tim;	Device *dev; 	tim = toytime();	qpath = d->qid.path;	dev = p->dev; again:	t1 = 0;	for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {		if(t->qpath == qpath)		if(t->time >= tim)		if(t->dev == dev)			return nil;		/* its locked */		if(t1 != nil && t->time == 0)			t1 = t;			/* remember free lock */	}	if(t1 == 0) {		// reclaim old locks		lock(&tlocklock);		for(t=tlocks+NTLOCK-1; t>=tlocks; t--)			if(t->time < tim) {				t->time = 0;				t1 = t;			}		unlock(&tlocklock);	}	if(t1) {		lock(&tlocklock);		if(t1->time != 0) {			unlock(&tlocklock);			goto again;		}		t1->dev = dev;		t1->qpath = qpath;		t1->time = tim + TLOCK;		unlock(&tlocklock);	}	/* botch	 * out of tlock nodes simulates	 * a locked file	 */	return t1;} Wpath*newwp(void){	static int si = 0;	int i;	Wpath *w, *sw, *ew; 	i = si + 1;	if(i < 0 || i >= conf.nwpath)		i = 0;	si = i;	sw = &wpaths[i];	ew = &wpaths[conf.nwpath];	for(w=sw;;) {		w++;		if(w >= ew)			w = &wpaths[0];		if(w == sw) {			print("out of wpaths\n");			return 0;		}		if(w->refs)			continue;		lock(&wpathlock);		if(w->refs) {			unlock(&wpathlock);			continue;		}		w->refs = 1;		w->up = 0;		unlock(&wpathlock);		return w;	} } voidfreewp(Wpath *w){	lock(&wpathlock);	for(; w; w=w->up)		w->refs--;	unlock(&wpathlock);} Offqidpathgen(Device *dev){	Iobuf *p;	Superb *sb;	Off path; 	p = getbuf(dev, superaddr(dev), Brd|Bmod);	if(!p || checktag(p, Tsuper, QPSUPER))		panic("newqid: super block");	sb = (Superb*)p->iobuf;	sb->qidgen++;	path = sb->qidgen;	putbuf(p);	return path;} /* truncating to length > 0 */static voidtruncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i){	int pastlast;	Off a; 	pastlast = ts->pastlast;	a = ((Off *)p->iobuf)[i];	if (d > 0 || pastlast)		buffree(dev, a, d, ts);	if (pastlast) {		((Off *)p->iobuf)[i] = 0;		p->flags |= Bmod|Bimm;	} else if (d == 0 && ts->relblk == ts->lastblk)		ts->pastlast = 1;	if (d == 0)		ts->relblk++;} /* * free the block at `addr' on dev. * if it's an indirect block (d [depth] > 0), * first recursively free all the blocks it names. * * ts->relblk is the block number within the file of this * block (or the first data block eventually pointed to via * this indirect block). */voidbuffree(Device *dev, Off addr, int d, Truncstate *ts){	Iobuf *p;	Off a;	int i, pastlast; 	if(!addr)		return;	pastlast = (ts == nil? 1: ts->pastlast);	/*	 * if this is an indirect block, recurse and free any	 * suitable blocks within it (possibly via further indirect blocks).	 */	if(d > 0) {		d--;		p = getbuf(dev, addr, Brd);		if(p) {			if (ts == nil)		/* common case: create */				for(i=INDPERBUF-1; i>=0; i--) {					a = ((Off *)p->iobuf)[i];					buffree(dev, a, d, nil);				}			else			/* wstat truncation */				for (i = 0; i < INDPERBUF; i++)					truncfree(ts, dev, d, p, i);			putbuf(p);		}	}	if (!pastlast)		return;	/*	 * having zeroed the pointer to this block, add it to the free list.	 * stop outstanding i/o	 */	p = getbuf(dev, addr, Bprobe);	if(p) {		p->flags &= ~(Bmod|Bimm);		putbuf(p);	}	/*	 * dont put written worm	 * blocks into free list	 */	if(dev->type == Devcw) {		i = cwfree(dev, addr);		if(i)			return;	}	p = getbuf(dev, superaddr(dev), Brd|Bmod);	if(!p || checktag(p, Tsuper, QPSUPER))		panic("buffree: super block");	addfree(dev, addr, (Superb*)p->iobuf);	putbuf(p);} Offbufalloc(Device *dev, int tag, long qid, int uid){	Iobuf *bp, *p;	Superb *sb;	Off a, n; 	p = getbuf(dev, superaddr(dev), Brd|Bmod);	if(!p || checktag(p, Tsuper, QPSUPER)) {		print("bufalloc: super block\n");		if(p)			putbuf(p);		return 0;	}	sb = (Superb*)p->iobuf; loop:	n = --sb->fbuf.nfree;	sb->tfree--;	if(n < 0 || n >= FEPERBUF) {		print("bufalloc: %Z: bad freelist\n", dev);		n = 0;		sb->fbuf.free[0] = 0;	}	a = sb->fbuf.free[n];	if(n <= 0) {		if(a == 0) {			sb->tfree = 0;			sb->fbuf.nfree = 1;			if(dev->type == Devcw) {				n = uid;				if(n < 0 || n >= nelem(growacct))

Lines 1–500 of 1550.