The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/sysfile.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 /*
    9  * The sys*() routines needn't poperror() as they return directly to syscall().
   10  */
   11 
   12 static void
   13 unlockfgrp(Fgrp *f)
   14 {
   15         int ex;
   16 
   17         ex = f->exceed;
   18         f->exceed = 0;
   19         unlock(f);
   20         if(ex)
   21                 pprint("warning: process exceeds %d file descriptors\n", ex);
   22 }
   23 
   24 int
   25 growfd(Fgrp *f, int fd) /* fd is always >= 0 */
   26 {
   27         Chan **newfd, **oldfd;
   28 
   29         if(fd < f->nfd)
   30                 return 0;
   31         if(fd >= f->nfd+DELTAFD)
   32                 return -1;      /* out of range */
   33         /*
   34          * Unbounded allocation is unwise; besides, there are only 16 bits
   35          * of fid in 9P
   36          */
   37         if(f->nfd >= 5000){
   38     Exhausted:
   39                 print("no free file descriptors\n");
   40                 return -1;
   41         }
   42         newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
   43         if(newfd == 0)
   44                 goto Exhausted;
   45         oldfd = f->fd;
   46         memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
   47         f->fd = newfd;
   48         free(oldfd);
   49         f->nfd += DELTAFD;
   50         if(fd > f->maxfd){
   51                 if(fd/100 > f->maxfd/100)
   52                         f->exceed = (fd/100)*100;
   53                 f->maxfd = fd;
   54         }
   55         return 1;
   56 }
   57 
   58 /*
   59  *  this assumes that the fgrp is locked
   60  */
   61 int
   62 findfreefd(Fgrp *f, int start)
   63 {
   64         int fd;
   65 
   66         for(fd=start; fd<f->nfd; fd++)
   67                 if(f->fd[fd] == 0)
   68                         break;
   69         if(fd >= f->nfd && growfd(f, fd) < 0)
   70                 return -1;
   71         return fd;
   72 }
   73 
   74 int
   75 newfd(Chan *c)
   76 {
   77         int fd;
   78         Fgrp *f;
   79 
   80         f = up->fgrp;
   81         lock(f);
   82         fd = findfreefd(f, 0);
   83         if(fd < 0){
   84                 unlockfgrp(f);
   85                 return -1;
   86         }
   87         if(fd > f->maxfd)
   88                 f->maxfd = fd;
   89         f->fd[fd] = c;
   90         unlockfgrp(f);
   91         return fd;
   92 }
   93 
   94 int
   95 newfd2(int fd[2], Chan *c[2])
   96 {
   97         Fgrp *f;
   98 
   99         f = up->fgrp;
  100         lock(f);
  101         fd[0] = findfreefd(f, 0);
  102         if(fd[0] < 0){
  103                 unlockfgrp(f);
  104                 return -1;
  105         }
  106         fd[1] = findfreefd(f, fd[0]+1);
  107         if(fd[1] < 0){
  108                 unlockfgrp(f);
  109                 return -1;
  110         }
  111         if(fd[1] > f->maxfd)
  112                 f->maxfd = fd[1];
  113         f->fd[fd[0]] = c[0];
  114         f->fd[fd[1]] = c[1];
  115         unlockfgrp(f);
  116 
  117         return 0;
  118 }
  119 
  120 Chan*
  121 fdtochan(int fd, int mode, int chkmnt, int iref)
  122 {
  123         Chan *c;
  124         Fgrp *f;
  125 
  126         c = 0;
  127         f = up->fgrp;
  128 
  129         lock(f);
  130         if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
  131                 unlock(f);
  132                 error(Ebadfd);
  133         }
  134         if(iref)
  135                 incref(c);
  136         unlock(f);
  137 
  138         if(chkmnt && (c->flag&CMSG)) {
  139                 if(iref)
  140                         cclose(c);
  141                 error(Ebadusefd);
  142         }
  143 
  144         if(mode<0 || c->mode==ORDWR)
  145                 return c;
  146 
  147         if((mode&OTRUNC) && c->mode==OREAD) {
  148                 if(iref)
  149                         cclose(c);
  150                 error(Ebadusefd);
  151         }
  152 
  153         if((mode&~OTRUNC) != c->mode) {
  154                 if(iref)
  155                         cclose(c);
  156                 error(Ebadusefd);
  157         }
  158 
  159         return c;
  160 }
  161 
  162 int
  163 openmode(ulong o)
  164 {
  165         o &= ~(OTRUNC|OCEXEC|ORCLOSE);
  166         if(o > OEXEC)
  167                 error(Ebadarg);
  168         if(o == OEXEC)
  169                 return OREAD;
  170         return o;
  171 }
  172 
  173 long
  174 sysfd2path(ulong *arg)
  175 {
  176         Chan *c;
  177 
  178         validaddr(arg[1], arg[2], 1);
  179 
  180         c = fdtochan(arg[0], -1, 0, 1);
  181         snprint((char*)arg[1], arg[2], "%s", chanpath(c));
  182         cclose(c);
  183         return 0;
  184 }
  185 
  186 long
  187 syspipe(ulong *arg)
  188 {
  189         int fd[2];
  190         Chan *c[2];
  191         Dev *d;
  192         static char *datastr[] = {"data", "data1"};
  193 
  194         validaddr(arg[0], 2*BY2WD, 1);
  195         evenaddr(arg[0]);
  196         d = devtab[devno('|', 0)];
  197         c[0] = namec("#|", Atodir, 0, 0);
  198         c[1] = 0;
  199         fd[0] = -1;
  200         fd[1] = -1;
  201 
  202         if(waserror()){
  203                 cclose(c[0]);
  204                 if(c[1])
  205                         cclose(c[1]);
  206                 nexterror();
  207         }
  208         c[1] = cclone(c[0]);
  209         if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
  210                 error(Egreg);
  211         if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
  212                 error(Egreg);
  213         c[0] = d->open(c[0], ORDWR);
  214         c[1] = d->open(c[1], ORDWR);
  215         if(newfd2(fd, c) < 0)
  216                 error(Enofd);
  217         poperror();
  218 
  219         ((long*)arg[0])[0] = fd[0];
  220         ((long*)arg[0])[1] = fd[1];
  221         return 0;
  222 }
  223 
  224 long
  225 sysdup(ulong *arg)
  226 {
  227         int fd;
  228         Chan *c, *oc;
  229         Fgrp *f = up->fgrp;
  230 
  231         /*
  232          * Close after dup'ing, so date > #d/1 works
  233          */
  234         c = fdtochan(arg[0], -1, 0, 1);
  235         fd = arg[1];
  236         if(fd != -1){
  237                 lock(f);
  238                 if(fd<0 || growfd(f, fd)<0) {
  239                         unlockfgrp(f);
  240                         cclose(c);
  241                         error(Ebadfd);
  242                 }
  243                 if(fd > f->maxfd)
  244                         f->maxfd = fd;
  245 
  246                 oc = f->fd[fd];
  247                 f->fd[fd] = c;
  248                 unlockfgrp(f);
  249                 if(oc)
  250                         cclose(oc);
  251         }else{
  252                 if(waserror()) {
  253                         cclose(c);
  254                         nexterror();
  255                 }
  256                 fd = newfd(c);
  257                 if(fd < 0)
  258                         error(Enofd);
  259                 poperror();
  260         }
  261 
  262         return fd;
  263 }
  264 
  265 long
  266 sysopen(ulong *arg)
  267 {
  268         int fd;
  269         Chan *c = 0;
  270 
  271         openmode(arg[1]);       /* error check only */
  272         if(waserror()){
  273                 if(c)
  274                         cclose(c);
  275                 nexterror();
  276         }
  277         validaddr(arg[0], 1, 0);
  278         c = namec((char*)arg[0], Aopen, arg[1], 0);
  279         fd = newfd(c);
  280         if(fd < 0)
  281                 error(Enofd);
  282         poperror();
  283         return fd;
  284 }
  285 
  286 void
  287 fdclose(int fd, int flag)
  288 {
  289         int i;
  290         Chan *c;
  291         Fgrp *f = up->fgrp;
  292 
  293         lock(f);
  294         c = f->fd[fd];
  295         if(c == 0){
  296                 /* can happen for users with shared fd tables */
  297                 unlock(f);
  298                 return;
  299         }
  300         if(flag){
  301                 if(c==0 || !(c->flag&flag)){
  302                         unlock(f);
  303                         return;
  304                 }
  305         }
  306         f->fd[fd] = 0;
  307         if(fd == f->maxfd)
  308                 for(i=fd; --i>=0 && f->fd[i]==0; )
  309                         f->maxfd = i;
  310 
  311         unlock(f);
  312         cclose(c);
  313 }
  314 
  315 long
  316 sysclose(ulong *arg)
  317 {
  318         fdtochan(arg[0], -1, 0, 0);
  319         fdclose(arg[0], 0);
  320 
  321         return 0;
  322 }
  323 
  324 long
  325 unionread(Chan *c, void *va, long n)
  326 {
  327         int i;
  328         long nr;
  329         Mhead *m;
  330         Mount *mount;
  331 
  332         qlock(&c->umqlock);
  333         m = c->umh;
  334         rlock(&m->lock);
  335         mount = m->mount;
  336         /* bring mount in sync with c->uri and c->umc */
  337         for(i = 0; mount != nil && i < c->uri; i++)
  338                 mount = mount->next;
  339 
  340         nr = 0;
  341         while(mount != nil){
  342                 /* Error causes component of union to be skipped */
  343                 if(mount->to && !waserror()){
  344                         if(c->umc == nil){
  345                                 c->umc = cclone(mount->to);
  346                                 c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
  347                         }
  348         
  349                         nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
  350                         c->umc->offset += nr;
  351                         poperror();
  352                 }
  353                 if(nr > 0)
  354                         break;
  355 
  356                 /* Advance to next element */
  357                 c->uri++;
  358                 if(c->umc){
  359                         cclose(c->umc);
  360                         c->umc = nil;
  361                 }
  362                 mount = mount->next;
  363         }
  364         runlock(&m->lock);
  365         qunlock(&c->umqlock);
  366         return nr;
  367 }
  368 
  369 static void
  370 unionrewind(Chan *c)
  371 {
  372         qlock(&c->umqlock);
  373         c->uri = 0;
  374         if(c->umc){
  375                 cclose(c->umc);
  376                 c->umc = nil;
  377         }
  378         qunlock(&c->umqlock);
  379 }
  380 
  381 static int
  382 dirfixed(uchar *p, uchar *e, Dir *d)
  383 {
  384         int len;
  385 
  386         len = GBIT16(p)+BIT16SZ;
  387         if(p + len > e)
  388                 return -1;
  389 
  390         p += BIT16SZ;   /* ignore size */
  391         d->type = devno(GBIT16(p), 1);
  392         p += BIT16SZ;
  393         d->dev = GBIT32(p);
  394         p += BIT32SZ;
  395         d->qid.type = GBIT8(p);
  396         p += BIT8SZ;
  397         d->qid.vers = GBIT32(p);
  398         p += BIT32SZ;
  399         d->qid.path = GBIT64(p);
  400         p += BIT64SZ;
  401         d->mode = GBIT32(p);
  402         p += BIT32SZ;
  403         d->atime = GBIT32(p);
  404         p += BIT32SZ;
  405         d->mtime = GBIT32(p);
  406         p += BIT32SZ;
  407         d->length = GBIT64(p);
  408 
  409         return len;
  410 }
  411 
  412 static char*
  413 dirname(uchar *p, int *n)
  414 {
  415         p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
  416                 + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
  417         *n = GBIT16(p);
  418         return (char*)p+BIT16SZ;
  419 }
  420 
  421 static long
  422 dirsetname(char *name, int len, uchar *p, long n, long maxn)
  423 {
  424         char *oname;
  425         int olen;
  426         long nn;
  427 
  428         if(n == BIT16SZ)
  429                 return BIT16SZ;
  430 
  431         oname = dirname(p, &olen);
  432 
  433         nn = n+len-olen;
  434         PBIT16(p, nn-BIT16SZ);
  435         if(nn > maxn)
  436                 return BIT16SZ;
  437 
  438         if(len != olen)
  439                 memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
  440         PBIT16((uchar*)(oname-2), len);
  441         memmove(oname, name, len);
  442         return nn;
  443 }
  444 
  445 /*
  446  * Mountfix might have caused the fixed results of the directory read
  447  * to overflow the buffer.  Catch the overflow in c->dirrock.
  448  */
  449 static void
  450 mountrock(Chan *c, uchar *p, uchar **pe)
  451 {
  452         uchar *e, *r;
  453         int len, n;
  454 
  455         e = *pe;
  456 
  457         /* find last directory entry */
  458         for(;;){
  459                 len = BIT16SZ+GBIT16(p);
  460                 if(p+len >= e)
  461                         break;
  462                 p += len;
  463         }
  464 
  465         /* save it away */
  466         qlock(&c->rockqlock);
  467         if(c->nrock+len > c->mrock){
  468                 n = ROUND(c->nrock+len, 1024);
  469                 r = smalloc(n);
  470                 memmove(r, c->dirrock, c->nrock);
  471                 free(c->dirrock);
  472                 c->dirrock = r;
  473                 c->mrock = n;
  474         }
  475         memmove(c->dirrock+c->nrock, p, len);
  476         c->nrock += len;
  477         qunlock(&c->rockqlock);
  478 
  479         /* drop it */
  480         *pe = p;
  481 }
  482 
  483 /*
  484  * Satisfy a directory read with the results saved in c->dirrock.
  485  */
  486 static int
  487 mountrockread(Chan *c, uchar *op, long n, long *nn)
  488 {
  489         long dirlen;
  490         uchar *rp, *erp, *ep, *p;
  491 
  492         /* common case */
  493         if(c->nrock == 0)
  494                 return 0;
  495 
  496         /* copy out what we can */
  497         qlock(&c->rockqlock);
  498         rp = c->dirrock;
  499         erp = rp+c->nrock;
  500         p = op;
  501         ep = p+n;
  502         while(rp+BIT16SZ <= erp){
  503                 dirlen = BIT16SZ+GBIT16(rp);
  504                 if(p+dirlen > ep)
  505                         break;
  506                 memmove(p, rp, dirlen);
  507                 p += dirlen;
  508                 rp += dirlen;
  509         }
  510 
  511         if(p == op){
  512                 qunlock(&c->rockqlock);
  513                 return 0;
  514         }
  515 
  516         /* shift the rest */
  517         if(rp != erp)
  518                 memmove(c->dirrock, rp, erp-rp);
  519         c->nrock = erp - rp;
  520 
  521         *nn = p - op;
  522         qunlock(&c->rockqlock);
  523         return 1;
  524 }
  525 
  526 static void
  527 mountrewind(Chan *c)
  528 {
  529         c->nrock = 0;
  530 }
  531 
  532 /*
  533  * Rewrite the results of a directory read to reflect current 
  534  * name space bindings and mounts.  Specifically, replace
  535  * directory entries for bind and mount points with the results
  536  * of statting what is mounted there.  Except leave the old names.
  537  */
  538 static long
  539 mountfix(Chan *c, uchar *op, long n, long maxn)
  540 {
  541         char *name;
  542         int nbuf, nname;
  543         Chan *nc;
  544         Mhead *mh;
  545         Mount *m;
  546         uchar *p;
  547         int dirlen, rest;
  548         long l;
  549         uchar *buf, *e;
  550         Dir d;
  551 
  552         p = op;
  553         buf = nil;
  554         nbuf = 0;
  555         for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
  556                 dirlen = dirfixed(p, e, &d);
  557                 if(dirlen < 0)
  558                         break;
  559                 nc = nil;
  560                 mh = nil;
  561                 if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
  562                         /*
  563                          * If it's a union directory and the original is
  564                          * in the union, don't rewrite anything.
  565                          */
  566                         for(m=mh->mount; m; m=m->next)
  567                                 if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))
  568                                         goto Norewrite;
  569 
  570                         name = dirname(p, &nname);
  571                         /*
  572                          * Do the stat but fix the name.  If it fails, leave old entry.
  573                          * BUG: If it fails because there isn't room for the entry,
  574                          * what can we do?  Nothing, really.  Might as well skip it.
  575                          */
  576                         if(buf == nil){
  577                                 buf = smalloc(4096);
  578                                 nbuf = 4096;
  579                         }
  580                         if(waserror())
  581                                 goto Norewrite;
  582                         l = devtab[nc->type]->stat(nc, buf, nbuf);
  583                         l = dirsetname(name, nname, buf, l, nbuf);
  584                         if(l == BIT16SZ)
  585                                 error("dirsetname");
  586                         poperror();
  587 
  588                         /*
  589                          * Shift data in buffer to accomodate new entry,
  590                          * possibly overflowing into rock.
  591                          */
  592                         rest = e - (p+dirlen);
  593                         if(l > dirlen){
  594                                 while(p+l+rest > op+maxn){
  595                                         mountrock(c, p, &e);
  596                                         if(e == p){
  597                                                 dirlen = 0;
  598                                                 goto Norewrite;
  599                                         }
  600                                         rest = e - (p+dirlen);
  601                                 }
  602                         }
  603                         if(l != dirlen){
  604                                 memmove(p+l, p+dirlen, rest);
  605                                 dirlen = l;
  606                                 e = p+dirlen+rest;
  607                         }
  608 
  609                         /*
  610                          * Rewrite directory entry.
  611                          */
  612                         memmove(p, buf, l);
  613 
  614                     Norewrite:
  615                         cclose(nc);
  616                         putmhead(mh);
  617                 }
  618         }
  619         if(buf)
  620                 free(buf);
  621 
  622         if(p != e)
  623                 error("oops in rockfix");
  624 
  625         return e-op;
  626 }
  627 
  628 static long
  629 read(ulong *arg, vlong *offp)
  630 {
  631         int dir;
  632         long n, nn, nnn;
  633         uchar *p;
  634         Chan *c;
  635         vlong off;
  636 
  637         n = arg[2];
  638         validaddr(arg[1], n, 1);
  639         p = (void*)arg[1];
  640         c = fdtochan(arg[0], OREAD, 1, 1);
  641 
  642         if(waserror()){
  643                 cclose(c);
  644                 nexterror();
  645         }
  646 
  647         /*
  648          * The offset is passed through on directories, normally.
  649          * Sysseek complains, but pread is used by servers like exportfs,
  650          * that shouldn't need to worry about this issue.
  651          *
  652          * Notice that c->devoffset is the offset that c's dev is seeing.
  653          * The number of bytes read on this fd (c->offset) may be different
  654          * due to rewritings in rockfix.
  655          */
  656         if(offp == nil) /* use and maintain channel's offset */
  657                 off = c->offset;
  658         else
  659                 off = *offp;
  660         if(off < 0)
  661                 error(Enegoff);
  662 
  663         if(off == 0){   /* rewind to the beginning of the directory */
  664                 if(offp == nil){
  665                         c->offset = 0;
  666                         c->devoffset = 0;
  667                 }
  668                 mountrewind(c);
  669                 unionrewind(c);
  670         }
  671 
  672         dir = c->qid.type&QTDIR;
  673         if(dir && mountrockread(c, p, n, &nn)){
  674                 /* do nothing: mountrockread filled buffer */
  675         }else{
  676                 if(dir && c->umh)
  677                         nn = unionread(c, p, n);
  678                 else
  679                         nn = devtab[c->type]->read(c, p, n, off);
  680         }
  681         if(dir)
  682                 nnn = mountfix(c, p, nn, n);
  683         else
  684                 nnn = nn;
  685 
  686         lock(c);
  687         c->devoffset += nn;
  688         c->offset += nnn;
  689         unlock(c);
  690 
  691         poperror();
  692         cclose(c);
  693 
  694         return nnn;
  695 }
  696 
  697 long
  698 sys_read(ulong *arg)
  699 {
  700         return read(arg, nil);
  701 }
  702 
  703 long
  704 syspread(ulong *arg)
  705 {
  706         vlong v;
  707         va_list list;
  708 
  709         /* use varargs to guarantee alignment of vlong */
  710         va_start(list, arg[2]);
  711         v = va_arg(list, vlong);
  712         va_end(list);
  713 
  714         if(v == ~0ULL)
  715                 return read(arg, nil);
  716 
  717         return read(arg, &v);
  718 }
  719 
  720 static long
  721 write(ulong *arg, vlong *offp)
  722 {
  723         Chan *c;
  724         long m, n;
  725         vlong off;
  726 
  727         validaddr(arg[1], arg[2], 0);
  728         n = 0;
  729         c = fdtochan(arg[0], OWRITE, 1, 1);
  730         if(waserror()) {
  731                 if(offp == nil){
  732                         lock(c);
  733                         c->offset -= n;
  734                         unlock(c);
  735                 }
  736                 cclose(c);
  737                 nexterror();
  738         }
  739 
  740         if(c->qid.type & QTDIR)
  741                 error(Eisdir);
  742 
  743         n = arg[2];
  744 
  745         if(offp == nil){        /* use and maintain channel's offset */
  746                 lock(c);
  747                 off = c->offset;
  748                 c->offset += n;
  749                 unlock(c);
  750         }else
  751                 off = *offp;
  752 
  753         if(off < 0)
  754                 error(Enegoff);
  755 
  756         m = devtab[c->type]->write(c, (void*)arg[1], n, off);
  757 
  758         if(offp == nil && m < n){
  759                 lock(c);
  760                 c->offset -= n - m;
  761                 unlock(c);
  762         }
  763 
  764         poperror();
  765         cclose(c);
  766 
  767         return m;
  768 }
  769 
  770 long
  771 sys_write(ulong *arg)
  772 {
  773         return write(arg, nil);
  774 }
  775 
  776 long
  777 syspwrite(ulong *arg)
  778 {
  779         vlong v;
  780         va_list list;
  781 
  782         /* use varargs to guarantee alignment of vlong */
  783         va_start(list, arg[2]);
  784         v = va_arg(list, vlong);
  785         va_end(list);
  786 
  787         if(v == ~0ULL)
  788                 return write(arg, nil);
  789 
  790         return write(arg, &v);
  791 }
  792 
  793 static void
  794 sseek(ulong *arg)
  795 {
  796         Chan *c;
  797         uchar buf[sizeof(Dir)+100];
  798         Dir dir;
  799         int n;
  800         vlong off;
  801         union {
  802                 vlong v;
  803                 ulong u[2];
  804         } o;
  805 
  806         c = fdtochan(arg[1], -1, 1, 1);
  807         if(waserror()){
  808                 cclose(c);
  809                 nexterror();
  810         }
  811         if(devtab[c->type]->dc == '|')
  812                 error(Eisstream);
  813 
  814         off = 0;
  815         o.u[0] = arg[2];
  816         o.u[1] = arg[3];
  817         switch(arg[4]){
  818         case 0:
  819                 off = o.v;
  820                 if((c->qid.type & QTDIR) && off != 0)
  821                         error(Eisdir);
  822                 if(off < 0)
  823                         error(Enegoff);
  824                 c->offset = off;
  825                 break;
  826 
  827         case 1:
  828                 if(c->qid.type & QTDIR)
  829                         error(Eisdir);
  830                 lock(c);        /* lock for read/write update */
  831                 off = o.v + c->offset;
  832                 if(off < 0){
  833                         unlock(c);
  834                         error(Enegoff);
  835                 }
  836                 c->offset = off;
  837                 unlock(c);
  838                 break;
  839 
  840         case 2:
  841                 if(c->qid.type & QTDIR)
  842                         error(Eisdir);
  843                 n = devtab[c->type]->stat(c, buf, sizeof buf);
  844                 if(convM2D(buf, n, &dir, nil) == 0)
  845                         error("internal error: stat error in seek");
  846                 off = dir.length + o.v;
  847                 if(off < 0)
  848                         error(Enegoff);
  849                 c->offset = off;
  850                 break;
  851 
  852         default:
  853                 error(Ebadarg);
  854         }
  855         *(vlong*)arg[0] = off;
  856         c->uri = 0;
  857         c->dri = 0;
  858         cclose(c);
  859         poperror();
  860 }
  861 
  862 long
  863 sysseek(ulong *arg)
  864 {
  865         validaddr(arg[0], BY2V, 1);
  866         sseek(arg);
  867         return 0;
  868 }
  869 
  870 long
  871 sysoseek(ulong *arg)
  872 {
  873         union {
  874                 vlong v;
  875                 ulong u[2];
  876         } o;
  877         ulong a[5];
  878 
  879         o.v = (long)arg[1];
  880         a[0] = (ulong)&o.v;
  881         a[1] = arg[0];
  882         a[2] = o.u[0];
  883         a[3] = o.u[1];
  884         a[4] = arg[2];
  885         sseek(a);
  886         return o.v;
  887 }
  888 
  889 void
  890 validstat(uchar *s, int n)
  891 {
  892         int m;
  893         char buf[64];
  894 
  895         if(statcheck(s, n) < 0)
  896                 error(Ebadstat);
  897         /* verify that name entry is acceptable */
  898         s += STATFIXLEN - 4*BIT16SZ;    /* location of first string */
  899         /*
  900          * s now points at count for first string.
  901          * if it's too long, let the server decide; this is
  902          * only for his protection anyway. otherwise
  903          * we'd have to allocate and waserror.
  904          */
  905         m = GBIT16(s);
  906         s += BIT16SZ;
  907         if(m+1 > sizeof buf)
  908                 return;
  909         memmove(buf, s, m);
  910         buf[m] = '\0';
  911         /* name could be '/' */
  912         if(strcmp(buf, "/") != 0)
  913                 validname(buf, 0);
  914 }
  915 
  916 static char*
  917 pathlast(Path *p)
  918 {
  919         char *s;
  920 
  921         if(p == nil)
  922                 return nil;
  923         if(p->len == 0)
  924                 return nil;
  925         s = strrchr(p->s, '/');
  926         if(s)
  927                 return s+1;
  928         return p->s;
  929 }
  930 
  931 long
  932 sysfstat(ulong *arg)
  933 {
  934         Chan *c;
  935         uint l;
  936 
  937         l = arg[2];
  938         validaddr(arg[1], l, 1);
  939         c = fdtochan(arg[0], -1, 0, 1);
  940         if(waserror()) {
  941                 cclose(c);
  942                 nexterror();
  943         }
  944         l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
  945         poperror();
  946         cclose(c);
  947         return l;
  948 }
  949 
  950 long
  951 sysstat(ulong *arg)
  952 {
  953         char *name;
  954         Chan *c;
  955         uint l;
  956 
  957         l = arg[2];
  958         validaddr(arg[1], l, 1);
  959         validaddr(arg[0], 1, 0);
  960         c = namec((char*)arg[0], Aaccess, 0, 0);
  961         if(waserror()){
  962                 cclose(c);
  963                 nexterror();
  964         }
  965         l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
  966         name = pathlast(c->path);
  967         if(name)
  968                 l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]);
  969 
  970         poperror();
  971         cclose(c);
  972         return l;
  973 }
  974 
  975 long
  976 syschdir(ulong *arg)
  977 {
  978         Chan *c;
  979 
  980         validaddr(arg[0], 1, 0);
  981 
  982         c = namec((char*)arg[0], Atodir, 0, 0);
  983         cclose(up->dot);
  984         up->dot = c;
  985         return 0;
  986 }
  987 
  988 long
  989 bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
  990 {
  991         int ret;
  992         Chan *c0, *c1, *ac, *bc;
  993         struct{
  994                 Chan    *chan;
  995                 Chan    *authchan;
  996                 char    *spec;
  997                 int     flags;
  998         }bogus;
  999 
 1000         if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
 1001                 error(Ebadarg);
 1002 
 1003         bogus.flags = flag & MCACHE;
 1004 
 1005         if(ismount){
 1006                 if(up->pgrp->noattach)
 1007                         error(Enoattach);
 1008 
 1009                 ac = nil;
 1010                 bc = fdtochan(fd, ORDWR, 0, 1);
 1011                 if(waserror()) {
 1012                         if(ac)
 1013                                 cclose(ac);
 1014                         cclose(bc);
 1015                         nexterror();
 1016                 }
 1017 
 1018                 if(afd >= 0)
 1019                         ac = fdtochan(afd, ORDWR, 0, 1);
 1020 
 1021                 bogus.chan = bc;
 1022                 bogus.authchan = ac;
 1023 
 1024                 validaddr((ulong)spec, 1, 0);
 1025                 bogus.spec = spec;
 1026                 if(waserror())
 1027                         error(Ebadspec);
 1028                 spec = validnamedup(spec, 1);
 1029                 poperror();
 1030                 
 1031                 if(waserror()){
 1032                         free(spec);
 1033                         nexterror();
 1034                 }
 1035 
 1036                 ret = devno('M', 0);
 1037                 c0 = devtab[ret]->attach((char*)&bogus);
 1038 
 1039                 poperror();     /* spec */
 1040                 free(spec);
 1041                 poperror();     /* ac bc */
 1042                 if(ac)
 1043                         cclose(ac);
 1044                 cclose(bc);
 1045         }else{
 1046                 bogus.spec = 0;
 1047                 validaddr((ulong)arg0, 1, 0);
 1048                 c0 = namec(arg0, Abind, 0, 0);
 1049         }
 1050 
 1051         if(waserror()){
 1052                 cclose(c0);
 1053                 nexterror();
 1054         }
 1055 
 1056         validaddr((ulong)arg1, 1, 0);
 1057         c1 = namec(arg1, Amount, 0, 0);
 1058         if(waserror()){
 1059                 cclose(c1);
 1060                 nexterror();
 1061         }
 1062 
 1063         ret = cmount(&c0, c1, flag, bogus.spec);
 1064 
 1065         poperror();
 1066         cclose(c1);
 1067         poperror();
 1068         cclose(c0);
 1069         if(ismount)
 1070                 fdclose(fd, 0);
 1071 
 1072         return ret;
 1073 }
 1074 
 1075 long
 1076 sysbind(ulong *arg)
 1077 {
 1078         return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
 1079 }
 1080 
 1081 long
 1082 sysmount(ulong *arg)
 1083 {
 1084         return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
 1085 }
 1086 
 1087 long
 1088 sys_mount(ulong *arg)
 1089 {
 1090         return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
 1091 }
 1092 
 1093 long
 1094 sysunmount(ulong *arg)
 1095 {
 1096         Chan *cmount, *cmounted;
 1097 
 1098         cmounted = 0;
 1099 
 1100         validaddr(arg[1], 1, 0);
 1101         cmount = namec((char *)arg[1], Amount, 0, 0);
 1102 
 1103         if(arg[0]) {
 1104                 if(waserror()) {
 1105                         cclose(cmount);
 1106                         nexterror();
 1107                 }
 1108                 validaddr(arg[0], 1, 0);
 1109                 /*
 1110                  * This has to be namec(..., Aopen, ...) because
 1111                  * if arg[0] is something like /srv/cs or /fd/0,
 1112                  * opening it is the only way to get at the real
 1113                  * Chan underneath.
 1114                  */
 1115                 cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
 1116                 poperror();
 1117         }
 1118 
 1119         if(waserror()) {
 1120                 cclose(cmount);
 1121                 if(cmounted)
 1122                         cclose(cmounted);
 1123                 nexterror();
 1124         }
 1125 
 1126         cunmount(cmount, cmounted);
 1127         cclose(cmount);
 1128         if(cmounted)
 1129                 cclose(cmounted);
 1130         poperror();
 1131         return 0;
 1132 }
 1133 
 1134 long
 1135 syscreate(ulong *arg)
 1136 {
 1137         int fd;
 1138         Chan *c = 0;
 1139 
 1140         openmode(arg[1]&~OEXCL);        /* error check only; OEXCL okay here */
 1141         if(waserror()) {
 1142                 if(c)
 1143                         cclose(c);
 1144                 nexterror();
 1145         }
 1146         validaddr(arg[0], 1, 0);
 1147         c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
 1148         fd = newfd(c);
 1149         if(fd < 0)
 1150                 error(Enofd);
 1151         poperror();
 1152         return fd;
 1153 }
 1154 
 1155 long
 1156 sysremove(ulong *arg)
 1157 {
 1158         Chan *c;
 1159 
 1160         validaddr(arg[0], 1, 0);
 1161         c = namec((char*)arg[0], Aremove, 0, 0);
 1162         /*
 1163          * Removing mount points is disallowed to avoid surprises
 1164          * (which should be removed: the mount point or the mounted Chan?).
 1165          */
 1166         if(c->ismtpt){
 1167                 cclose(c);
 1168                 error(Eismtpt);
 1169         }
 1170         if(waserror()){
 1171                 c->type = 0;    /* see below */
 1172                 cclose(c);
 1173                 nexterror();
 1174         }
 1175         devtab[c->type]->remove(c);
 1176         /*
 1177          * Remove clunks the fid, but we need to recover the Chan
 1178          * so fake it up.  rootclose() is known to be a nop.
 1179          */
 1180         c->type = 0;
 1181         poperror();
 1182         cclose(c);
 1183         return 0;
 1184 }
 1185 
 1186 static long
 1187 wstat(Chan *c, uchar *d, int nd)
 1188 {
 1189         long l;
 1190         int namelen;
 1191 
 1192         if(waserror()){
 1193                 cclose(c);
 1194                 nexterror();
 1195         }
 1196         if(c->ismtpt){
 1197                 /*
 1198                  * Renaming mount points is disallowed to avoid surprises
 1199                  * (which should be renamed? the mount point or the mounted Chan?).
 1200                  */
 1201                 dirname(d, &namelen);
 1202                 if(namelen)
 1203                         nameerror(chanpath(c), Eismtpt);
 1204         }
 1205         l = devtab[c->type]->wstat(c, d, nd);
 1206         poperror();
 1207         cclose(c);
 1208         return l;
 1209 }
 1210 
 1211 long
 1212 syswstat(ulong *arg)
 1213 {
 1214         Chan *c;
 1215         uint l;
 1216 
 1217         l = arg[2];
 1218         validaddr(arg[1], l, 0);
 1219         validstat((uchar*)arg[1], l);
 1220         validaddr(arg[0], 1, 0);
 1221         c = namec((char*)arg[0], Aaccess, 0, 0);
 1222         return wstat(c, (uchar*)arg[1], l);
 1223 }
 1224 
 1225 long
 1226 sysfwstat(ulong *arg)
 1227 {
 1228         Chan *c;
 1229         uint l;
 1230 
 1231         l = arg[2];
 1232         validaddr(arg[1], l, 0);
 1233         validstat((uchar*)arg[1], l);
 1234         c = fdtochan(arg[0], -1, 1, 1);
 1235         return wstat(c, (uchar*)arg[1], l);
 1236 }
 1237 
 1238 static void
 1239 packoldstat(uchar *buf, Dir *d)
 1240 {
 1241         uchar *p;
 1242         ulong q;
 1243 
 1244         /* lay down old stat buffer - grotty code but it's temporary */
 1245         p = buf;
 1246         strncpy((char*)p, d->name, 28);
 1247         p += 28;
 1248         strncpy((char*)p, d->uid, 28);
 1249         p += 28;
 1250         strncpy((char*)p, d->gid, 28);
 1251         p += 28;
 1252         q = d->qid.path & ~DMDIR;       /* make sure doesn't accidentally look like directory */
 1253         if(d->qid.type & QTDIR) /* this is the real test of a new directory */
 1254                 q |= DMDIR;
 1255         PBIT32(p, q);
 1256         p += BIT32SZ;
 1257         PBIT32(p, d->qid.vers);
 1258         p += BIT32SZ;
 1259         PBIT32(p, d->mode);
 1260         p += BIT32SZ;
 1261         PBIT32(p, d->atime);
 1262         p += BIT32SZ;
 1263         PBIT32(p, d->mtime);
 1264         p += BIT32SZ;
 1265         PBIT64(p, d->length);
 1266         p += BIT64SZ;
 1267         PBIT16(p, d->type);
 1268         p += BIT16SZ;
 1269         PBIT16(p, d->dev);
 1270 }
 1271 
 1272 long
 1273 sys_stat(ulong *arg)
 1274 {
 1275         Chan *c;
 1276         uint l;
 1277         uchar buf[128]; /* old DIRLEN plus a little should be plenty */
 1278         char strs[128], *name;
 1279         Dir d;
 1280         char old[] = "old stat system call - recompile";
 1281 
 1282         validaddr(arg[1], 116, 1);
 1283         validaddr(arg[0], 1, 0);
 1284         c = namec((char*)arg[0], Aaccess, 0, 0);
 1285         if(waserror()){
 1286                 cclose(c);
 1287                 nexterror();
 1288         }
 1289         l = devtab[c->type]->stat(c, buf, sizeof buf);
 1290         /* buf contains a new stat buf; convert to old. yuck. */
 1291         if(l <= BIT16SZ)        /* buffer too small; time to face reality */
 1292                 error(old);
 1293         name = pathlast(c->path);
 1294         if(name)
 1295                 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
 1296         l = convM2D(buf, l, &d, strs);
 1297         if(l == 0)
 1298                 error(old);
 1299         packoldstat((uchar*)arg[1], &d);
 1300         
 1301         poperror();
 1302         cclose(c);
 1303         return 0;
 1304 }
 1305 
 1306 long
 1307 sys_fstat(ulong *arg)
 1308 {
 1309         Chan *c;
 1310         char *name;
 1311         uint l;
 1312         uchar buf[128]; /* old DIRLEN plus a little should be plenty */
 1313         char strs[128];
 1314         Dir d;
 1315         char old[] = "old fstat system call - recompile";
 1316 
 1317         validaddr(arg[1], 116, 1);
 1318         c = fdtochan(arg[0], -1, 0, 1);
 1319         if(waserror()){
 1320                 cclose(c);
 1321                 nexterror();
 1322         }
 1323         l = devtab[c->type]->stat(c, buf, sizeof buf);
 1324         /* buf contains a new stat buf; convert to old. yuck. */
 1325         if(l <= BIT16SZ)        /* buffer too small; time to face reality */
 1326                 error(old);
 1327         name = pathlast(c->path);
 1328         if(name)
 1329                 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
 1330         l = convM2D(buf, l, &d, strs);
 1331         if(l == 0)
 1332                 error(old);
 1333         packoldstat((uchar*)arg[1], &d);
 1334         
 1335         poperror();
 1336         cclose(c);
 1337         return 0;
 1338 }
 1339 
 1340 long
 1341 sys_wstat(ulong *)
 1342 {
 1343         error("old wstat system call - recompile");
 1344         return -1;
 1345 }
 1346 
 1347 long
 1348 sys_fwstat(ulong *)
 1349 {
 1350         error("old fwstat system call - recompile");
 1351         return -1;
 1352 }

Cache object: 886aba6ec3fddd1b91e8f9b633a3467e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.