1371 lines · 22.0 KB · C
RawDownload
#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h" /* * The sys*() routines needn't poperror() as they return directly to syscall(). */ static voidunlockfgrp(Fgrp *f){	int ex; 	ex = f->exceed;	f->exceed = 0;	unlock(&f->ref.lk);	if(ex)		pprint("warning: process exceeds %d file descriptors\n", ex);} intgrowfd(Fgrp *f, int fd)	/* fd is always >= 0 */{	Chan **newfd, **oldfd; 	if(fd < f->nfd)		return 0;	if(fd >= f->nfd+DELTAFD)		return -1;	/* out of range */	/*	 * Unbounded allocation is unwise; besides, there are only 16 bits	 * of fid in 9P	 */	if(f->nfd >= 5000){    Exhausted:		print("no free file descriptors\n");		return -1;	}	newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));	if(newfd == 0)		goto Exhausted;	oldfd = f->fd;	memmove(newfd, oldfd, f->nfd*sizeof(Chan*));	f->fd = newfd;	free(oldfd);	f->nfd += DELTAFD;	if(fd > f->maxfd){		if(fd/100 > f->maxfd/100)			f->exceed = (fd/100)*100;		f->maxfd = fd;	}	return 1;} /* *  this assumes that the fgrp is locked */intfindfreefd(Fgrp *f, int start){	int fd; 	for(fd=start; fd<f->nfd; fd++)		if(f->fd[fd] == 0)			break;	if(fd >= f->nfd && growfd(f, fd) < 0)		return -1;	return fd;} intnewfd(Chan *c){	int fd;	Fgrp *f; 	f = up->fgrp;	lock(&f->ref.lk);	fd = findfreefd(f, 0);	if(fd < 0){		unlockfgrp(f);		return -1;	}	if(fd > f->maxfd)		f->maxfd = fd;	f->fd[fd] = c;	unlockfgrp(f);	return fd;} intnewfd2(int fd[2], Chan *c[2]){	Fgrp *f; 	f = up->fgrp;	lock(&f->ref.lk);	fd[0] = findfreefd(f, 0);	if(fd[0] < 0){		unlockfgrp(f);		return -1;	}	fd[1] = findfreefd(f, fd[0]+1);	if(fd[1] < 0){		unlockfgrp(f);		return -1;	}	if(fd[1] > f->maxfd)		f->maxfd = fd[1];	f->fd[fd[0]] = c[0];	f->fd[fd[1]] = c[1];	unlockfgrp(f); 	return 0;} Chan*fdtochan(int fd, int mode, int chkmnt, int iref){	Chan *c;	Fgrp *f; 	c = 0;	f = up->fgrp; 	lock(&f->ref.lk);	if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {		unlock(&f->ref.lk);		error(Ebadfd);	}	if(iref)		incref(&c->ref);	unlock(&f->ref.lk); 	if(chkmnt && (c->flag&CMSG)) {		if(iref)			cclose(c);		error(Ebadusefd);	} 	if(mode<0 || c->mode==ORDWR)		return c; 	if((mode&OTRUNC) && c->mode==OREAD) {		if(iref)			cclose(c);		error(Ebadusefd);	} 	if((mode&~OTRUNC) != c->mode) {		if(iref)			cclose(c);		error(Ebadusefd);	} 	return c;} intopenmode(ulong o){	o &= ~(OTRUNC|OCEXEC|ORCLOSE);	if(o > OEXEC)		error(Ebadarg);	if(o == OEXEC)		return OREAD;	return o;} longsysfd2path(uint32 *arg){	Chan *c;	char *buf; 	buf = uvalidaddr(arg[1], arg[2], 1); 	c = fdtochan(arg[0], -1, 0, 1);	snprint(buf, arg[2], "%s", chanpath(c));	cclose(c);	return 0;} longsyspipe(uint32 *arg){	int fd[2];	Chan *c[2];	Dev *d;	static char *datastr[] = {"data", "data1"};	int *ufd;		ufd = uvalidaddr(arg[0], 2*BY2WD, 1);	evenaddr(arg[0]);	d = devtab[devno('|', 0)];	c[0] = namec("#|", Atodir, 0, 0);	c[1] = 0;	fd[0] = -1;	fd[1] = -1; 	if(waserror()){		cclose(c[0]);		if(c[1])			cclose(c[1]);		nexterror();	}	c[1] = cclone(c[0]);	if(walk(&c[0], datastr+0, 1, 1, nil) < 0)		error(Egreg);	if(walk(&c[1], datastr+1, 1, 1, nil) < 0)		error(Egreg);	c[0] = d->open(c[0], ORDWR);	c[1] = d->open(c[1], ORDWR);	if(newfd2(fd, c) < 0)		error(Enofd);	poperror(); 	ufd[0] = fd[0];	ufd[1] = fd[1];	return 0;} longsysdup(uint32 *arg){	int fd;	Chan *c, *oc;	Fgrp *f = up->fgrp; 	/*	 * Close after dup'ing, so date > #d/1 works	 */	c = fdtochan(arg[0], -1, 0, 1);	fd = arg[1];	if(fd != -1){		lock(&f->ref.lk);		if(fd<0 || growfd(f, fd)<0) {			unlockfgrp(f);			cclose(c);			error(Ebadfd);		}		if(fd > f->maxfd)			f->maxfd = fd; 		oc = f->fd[fd];		f->fd[fd] = c;		unlockfgrp(f);		if(oc)			cclose(oc);	}else{		if(waserror()) {			cclose(c);			nexterror();		}		fd = newfd(c);		if(fd < 0)			error(Enofd);		poperror();	} 	return fd;} longsysopen(uint32 *arg){	int fd;	Chan *c = 0;	char *name; 	openmode(arg[1]);	/* error check only */	name = uvalidaddr(arg[0], 1, 0);	c = namec(name, Aopen, arg[1], 0);	if(waserror()){		cclose(c);		nexterror();	}	fd = newfd(c);	if(fd < 0)		error(Enofd);	poperror();	return fd;} voidfdclose(int fd, int flag){	int i;	Chan *c;	Fgrp *f = up->fgrp; 	lock(&f->ref.lk);	c = f->fd[fd];	if(c == 0){		/* can happen for users with shared fd tables */		unlock(&f->ref.lk);		return;	}	if(flag){		if(c==0 || !(c->flag&flag)){			unlock(&f->ref.lk);			return;		}	}	f->fd[fd] = 0;	if(fd == f->maxfd)		for(i=fd; --i>=0 && f->fd[i]==0; )			f->maxfd = i; 	unlock(&f->ref.lk);	cclose(c);} longsysclose(uint32 *arg){	fdtochan(arg[0], -1, 0, 0);	fdclose(arg[0], 0); 	return 0;} longunionread(Chan *c, void *va, long n){	int i;	long nr;	Mhead *m;	Mount *mount; 	qlock(&c->umqlock);	m = c->umh;	rlock(&m->lock);	mount = m->mount;	/* bring mount in sync with c->uri and c->umc */	for(i = 0; mount != nil && i < c->uri; i++)		mount = mount->next; 	nr = 0;	while(mount != nil){		/* Error causes component of union to be skipped */		if(mount->to && !waserror()){			if(c->umc == nil){				c->umc = cclone(mount->to);				c->umc = devtab[c->umc->type]->open(c->umc, OREAD);			}				nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);			c->umc->offset += nr;			poperror();		}		if(nr > 0)			break; 		/* Advance to next element */		c->uri++;		if(c->umc){			cclose(c->umc);			c->umc = nil;		}		mount = mount->next;	}	runlock(&m->lock);	qunlock(&c->umqlock);	return nr;} static voidunionrewind(Chan *c){	qlock(&c->umqlock);	c->uri = 0;	if(c->umc){		cclose(c->umc);		c->umc = nil;	}	qunlock(&c->umqlock);} static intdirfixed(uchar *p, uchar *e, Dir *d){	int len; 	len = GBIT16(p)+BIT16SZ;	if(p + len > e)		return -1; 	p += BIT16SZ;	/* ignore size */	d->type = devno(GBIT16(p), 1);	p += BIT16SZ;	d->dev = GBIT32(p);	p += BIT32SZ;	d->qid.type = GBIT8(p);	p += BIT8SZ;	d->qid.vers = GBIT32(p);	p += BIT32SZ;	d->qid.path = GBIT64(p);	p += BIT64SZ;	d->mode = GBIT32(p);	p += BIT32SZ;	d->atime = GBIT32(p);	p += BIT32SZ;	d->mtime = GBIT32(p);	p += BIT32SZ;	d->length = GBIT64(p); 	return len;} static char*dirname(uchar *p, int *n){	p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ		+ BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;	*n = GBIT16(p);	return (char*)p+BIT16SZ;} static longdirsetname(char *name, int len, uchar *p, long n, long maxn){	char *oname;	int olen;	long nn; 	if(n == BIT16SZ)		return BIT16SZ; 	oname = dirname(p, &olen); 	nn = n+len-olen;	PBIT16(p, nn-BIT16SZ);	if(nn > maxn)		return BIT16SZ; 	if(len != olen)		memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));	PBIT16((uchar*)(oname-2), len);	memmove(oname, name, len);	return nn;} /* * Mountfix might have caused the fixed results of the directory read * to overflow the buffer.  Catch the overflow in c->dirrock. */static voidmountrock(Chan *c, uchar *p, uchar **pe){	uchar *e, *r;	int len, n; 	e = *pe; 	/* find last directory entry */	for(;;){		len = BIT16SZ+GBIT16(p);		if(p+len >= e)			break;		p += len;	} 	/* save it away */	qlock(&c->rockqlock);	if(c->nrock+len > c->mrock){		n = ROUND(c->nrock+len, 1024);		r = smalloc(n);		memmove(r, c->dirrock, c->nrock);		free(c->dirrock);		c->dirrock = r;		c->mrock = n;	}	memmove(c->dirrock+c->nrock, p, len);	c->nrock += len;	qunlock(&c->rockqlock); 	/* drop it */	*pe = p;} /* * Satisfy a directory read with the results saved in c->dirrock. */static intmountrockread(Chan *c, uchar *op, long n, long *nn){	long dirlen;	uchar *rp, *erp, *ep, *p; 	/* common case */	if(c->nrock == 0)		return 0; 	/* copy out what we can */	qlock(&c->rockqlock);	rp = c->dirrock;

Lines 1–500 of 1371.