#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. Load more
#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 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(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 void closefd(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; } 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 long kread(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 netbsd long _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 long kwrite(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; } long sys_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); }