1261 lines · 17.8 KB · C
RawDownload
#include	"u.h"#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h" #include	"user.h"#undef open#undef mount#undef read#undef write#undef seek#undef stat#undef wstat#undef remove#undef close#undef fstat#undef fwstat#undef iounit /* * 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;} long_sysfd2path(int fd, char *buf, uint nbuf){	Chan *c; 	c = fdtochan(fd, -1, 0, 1); 	if(c->path == nil)		snprint(buf, nbuf, "<null>");	else		snprint(buf, nbuf, "%s", c->path->s);	cclose(c);	return 0;} long_syspipe(int fd[2]){	Chan *c[2];	Dev *d;	static char *datastr[] = {"data", "data1"}; 	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(); 	return 0;} long_sysdup(int fd0, int fd1){	int fd;	Chan *c, *oc;	Fgrp *f = up->fgrp; 	/*	 * Close after dup'ing, so date > #d/1 works	 */	c = fdtochan(fd0, -1, 0, 1);	fd = fd1;	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;} long_sysopen(char *name, int mode){	int fd;	Chan *c = 0; 	openmode(mode);	/* error check only */	if(waserror()){		if(c)			cclose(c);		nexterror();	}	c = namec(name, Aopen, mode, 0);	fd = newfd(c);	if(fd < 0)		error(Enofd);	poperror();	return fd;} static voidclosefd(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);} long_sysclose(int fd){	fdtochan(fd, -1, 0, 0);	closefd(fd, 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 longkread(int fd, void *buf, long n, vlong *offp){	int dir;	Chan *c;	vlong off; 	c = fdtochan(fd, OREAD, 1, 1); 	if(waserror()) {		cclose(c);		nexterror();	} 	dir = c->qid.type&QTDIR;	/*	 * The offset is passed through on directories, normally. sysseek complains but	 * pread is used by servers and e.g. exportfs that shouldn't need to worry about this issue.	 */ 	if(offp == nil)	/* use and maintain channel's offset */		off = c->offset;	else		off = *offp; 	if(off < 0)		error(Enegoff); 	if(dir && c->umh)		n = unionread(c, buf, n);	else		n = devtab[c->type]->read(c, buf, n, off); 	if(offp == nil){		lock(&c->ref.lk);		c->offset += n;		unlock(&c->ref.lk);	} 	poperror();	cclose(c); 	return n;} /* name conflicts with netbsdlong_sys_read(int fd, void *buf, long n){	return kread(fd, buf, n, nil);}*/ long_syspread(int fd, void *buf, long n, vlong off){	if(off == ((uvlong) ~0))		return kread(fd, buf, n, nil);	return kread(fd, buf, n, &off);} static longkwrite(int fd, void *buf, long nn, vlong *offp){	Chan *c;	long m, n;	vlong off; 	n = 0;	c = fdtochan(fd, OWRITE, 1, 1);	if(waserror()) {		if(offp == nil){			lock(&c->ref.lk);			c->offset -= n;			unlock(&c->ref.lk);		}		cclose(c);		nexterror();	} 	if(c->qid.type & QTDIR)		error(Eisdir); 	n = nn; 	if(offp == nil){	/* use and maintain channel's offset */		lock(&c->ref.lk);		off = c->offset;		c->offset += n;		unlock(&c->ref.lk);	}else		off = *offp; 	if(off < 0)		error(Enegoff); 	m = devtab[c->type]->write(c, buf, n, off); 	if(offp == nil && m < n){		lock(&c->ref.lk);		c->offset -= n - m;		unlock(&c->ref.lk);	} 	poperror();	cclose(c); 	return m;} longsys_write(int fd, void *buf, long n){	return kwrite(fd, buf, n, nil);} long_syspwrite(int fd, void *buf, long n, vlong off){	if(off == ((uvlong) ~0))		return kwrite(fd, buf, n, nil);	return kwrite(fd, buf, n, &off);}

Lines 1–500 of 1261.