#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. Load more
#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 void unlockfgrp(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); } int growfd(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 */ int findfreefd(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; } int newfd(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; } int newfd2(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; } int openmode(ulong o) { o &= ~(OTRUNC|OCEXEC|ORCLOSE); if(o > OEXEC) error(Ebadarg); if(o == OEXEC) return OREAD; return o; } long sysfd2path(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; } long syspipe(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; } long sysdup(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; } long sysopen(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; } void fdclose(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(uint32 *arg) { fdtochan(arg[0], -1, 0, 0); fdclose(arg[0], 0); return 0; } long unionread(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 void unionrewind(Chan *c) { qlock(&c->umqlock); c->uri = 0; if(c->umc){ cclose(c->umc); c->umc = nil; } qunlock(&c->umqlock); } static int dirfixed(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 long dirsetname(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 void mountrock(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 int mountrockread(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;