home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mint095s / dosfile.c < prev    next >
C/C++ Source or Header  |  1993-08-03  |  24KB  |  1,094 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /* DOS file handling routines */
  6.  
  7. #include "mint.h"
  8.  
  9. extern char temp1[];    /* see filesys.c */
  10.  
  11. static long do_dup P_((int,int));
  12. static void unselectme P_((PROC *));
  13.  
  14. /*
  15.  * first, some utility routines
  16.  */
  17.  
  18. FILEPTR *
  19. do_open(name, rwmode, attr, x)
  20.     const char *name;    /* file name */
  21.     int rwmode;    /* file access mode */
  22.     int attr;    /* TOS attributes for created files (if applicable) */
  23.     XATTR *x;    /* filled in with attributes of opened file */
  24. {
  25.     struct tty *tty;
  26.     fcookie dir, fc;
  27.     long devsp;
  28.     FILEPTR *f;
  29.     DEVDRV *dev;
  30.     long r;
  31.     XATTR xattr;
  32.     unsigned perm;
  33.     int creating;
  34.  
  35. /* for special BIOS "fake" devices */
  36.     extern DEVDRV fakedev;
  37.  
  38.     TRACE("do_open(%s)", name);
  39.  
  40. /*
  41.  * first step: get a cookie for the directory
  42.  */
  43.  
  44.     r = path2cookie(name, temp1, &dir);
  45.     if (r) {
  46.         mint_errno = r;
  47.         DEBUG("do_open(%s): error %ld", name, r);
  48.         return NULL;
  49.     }
  50.  
  51. /*
  52.  * second step: try to locate the file itself
  53.  */
  54.     r = relpath2cookie(&dir, temp1, follow_links, &fc, 0);
  55.  
  56. /*
  57.  * file found: this is an error if (O_CREAT|O_EXCL) are set
  58.  */
  59.     if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) ) {
  60.         DEBUG("do_open(%s): file already exists",name);
  61.         mint_errno = EACCDN;
  62.         return NULL;
  63.     }
  64. /*
  65.  * file not found: maybe we should create it
  66.  */
  67.     if (r == EFILNF && (rwmode & O_CREAT)) {
  68.     /* check first for write permission in the directory */
  69.         r = (*dir.fs->getxattr)(&dir, &xattr);
  70.         if (r == 0) {
  71.             if (denyaccess(&xattr, S_IWOTH))
  72.                 r = EACCDN;
  73.         }
  74.         if (r) {
  75.             DEBUG("do_open(%s): couldn't get "
  76.                   "write permission on directory",name);
  77.             mint_errno = r;
  78.             return NULL;
  79.         }
  80.         r = (*dir.fs->creat)(&dir, temp1,
  81.             (S_IFREG|DEFAULT_MODE) & (~curproc->umask), attr, &fc);
  82.         if (r) {
  83.             DEBUG("do_open(%s): error %ld while creating file",
  84.                 name, r);
  85.             mint_errno = r;
  86.             return NULL;
  87.         }
  88.         creating = 1;
  89.     } else if (r) {
  90.         DEBUG("do_open(%s): error %ld while searching for file",
  91.             name, r);
  92.         mint_errno = r;
  93.         return NULL;
  94.     } else {
  95.         creating = 0;
  96.     }
  97.  
  98. /*
  99.  * check now for permission to actually access the file
  100.  */
  101.     r = (*fc.fs->getxattr)(&fc, &xattr);
  102.     if (r) {
  103.         DEBUG("do_open(%s): couldn't get file attributes",name);
  104.         mint_errno = r;
  105.         return NULL;
  106.     }
  107. /*
  108.  * we don't do directories
  109.  */
  110.     if ( (xattr.mode & S_IFMT) == S_IFDIR ) {
  111.         DEBUG("do_open(%s): file is a directory",name);
  112.         mint_errno = EFILNF;
  113.         return NULL;
  114.     }
  115.  
  116.     switch (rwmode & O_RWMODE) {
  117.     case O_WRONLY:
  118.         perm = S_IWOTH;
  119.         break;
  120.     case O_RDWR:
  121.         perm = S_IROTH|S_IWOTH;
  122.         break;
  123.     case O_EXEC:
  124.         perm = (fc.fs->fsflags & FS_NOXBIT) ? S_IROTH : S_IXOTH;
  125.         break;
  126.     case O_RDONLY:
  127.         perm = S_IROTH;
  128.         break;
  129.     default:
  130.         perm = 0;
  131.         ALERT("do_open: bad file access mode: %x", rwmode);
  132.     }
  133.     if (!creating && denyaccess(&xattr, perm)) {
  134.         DEBUG("do_open(%s): access to file denied",name);
  135.         mint_errno = EACCDN;
  136.         return NULL;
  137.     }
  138.  
  139. /*
  140.  * an extra check for write access -- even the superuser shouldn't
  141.  * write to files with the FA_RDONLY attribute bit set (unless,
  142.  * we just created the file)
  143.  */
  144.     if ( !creating && (xattr.attr & FA_RDONLY)) {
  145.         if ( (rwmode & O_RWMODE) == O_RDWR ||
  146.              (rwmode & O_RWMODE) == O_WRONLY ) {
  147.             DEBUG("do_open(%s): can't write a read-only file",
  148.                 name);
  149.             mint_errno = EACCDN;
  150.             return NULL;
  151.         }
  152.     }
  153.  
  154. /*
  155.  * if writing to a setuid or setgid file, clear those bits
  156.  */
  157.     if ( (perm & S_IWOTH) && (xattr.mode & (S_ISUID|S_ISGID)) ) {
  158.         xattr.mode &= ~(S_ISUID|S_ISGID);
  159.         (*fc.fs->chmode)(&fc, (xattr.mode & ~S_IFMT));
  160.     }
  161. /*
  162.  * If the caller asked for the attributes of the opened file, copy them over.
  163.  */
  164.     if (x) *x = xattr;
  165.  
  166. /*
  167.  * So far, so good. Let's get the device driver now, and try to
  168.  * actually open the file.
  169.  */
  170.     dev = (*fc.fs->getdev)(&fc, &devsp);
  171.     if (!dev) {
  172.         mint_errno = devsp;
  173.         DEBUG("do_open(%s): device driver not found",name);
  174.         return NULL;
  175.     }
  176.  
  177.     if (dev == &fakedev) {        /* fake BIOS devices */
  178.         f = curproc->handle[devsp];
  179.         if (!f) {
  180.             mint_errno = EIHNDL;
  181.             return 0;
  182.         }
  183.         f->links++;
  184.         return f;
  185.     }
  186.     if (!(f = new_fileptr())) {
  187.         mint_errno = ENSMEM;
  188.         return NULL;
  189.     }
  190.     f->links = 1;
  191.     f->flags = rwmode;
  192.     f->pos = 0;
  193.     f->devinfo = devsp;
  194.     f->fc = fc;
  195.     f->dev = dev;
  196.  
  197.     r = (*dev->open)(f);
  198.     if (r < 0) {
  199.         DEBUG("do_open(%s): device open failed with error %ld",
  200.             name, r);
  201.         mint_errno = r;
  202.         f->links = 0;
  203.         dispose_fileptr(f);
  204.         return NULL;
  205.     }
  206.  
  207. /* special code for opening a tty */
  208.     if (is_terminal(f)) {
  209.         extern struct tty default_tty;    /* in tty.c */
  210.  
  211.         tty = (struct tty *)f->devinfo;
  212.         if (tty->use_cnt == 0) {     /* first open for this device? */
  213.             *tty = default_tty;
  214.         }
  215.         tty->use_cnt++;
  216.     }
  217.     return f;
  218. }
  219.  
  220. /*
  221.  * helper function for do_close: this closes the indicated file pointer which
  222.  * is assumed to be associated with process p. The extra parameter is necessary
  223.  * because f_midipipe mucks with file pointers of other processes, so
  224.  * sometimes p != curproc.
  225.  *
  226.  * Note that the function changedrv() in filesys.c can call this routine.
  227.  * in that case, f->dev will be 0 to represent an invalid device, and
  228.  * we cannot call the device close routine.
  229.  */
  230.  
  231. long
  232. do_pclose(p, f)
  233.     PROC *p;
  234.     FILEPTR *f;
  235. {
  236.     long r = 0;
  237.  
  238.     if (!f) return EIHNDL;
  239.  
  240. /* if this file is "select'd" by this process, unselect it
  241.  * (this is just in case we were killed by a signal
  242.  */
  243.  
  244. /* BUG? Feature? If media change is detected while we're doing the select,
  245.  * we'll never unselect (since f->dev is set to NULL by changedrv())
  246.  */
  247.     if (f->dev) {
  248.         (*f->dev->unselect)(f, (long)p, O_RDONLY);
  249.         (*f->dev->unselect)(f, (long)p, O_WRONLY);
  250.     }
  251.  
  252.     f->links--;
  253.  
  254. /* TTY manipulation must be done *before* calling the device close routine,
  255.  * since afterwards the TTY structure may no longer exist
  256.  */
  257.     if (is_terminal(f) && f->links <= 0) {
  258.         struct tty *tty = (struct tty *)f->devinfo;
  259.         tty->use_cnt--;
  260.         if (tty->use_cnt <= 0 && tty->xkey) {
  261.             kfree(tty->xkey);
  262.             tty->xkey = 0;
  263.         }
  264.     }
  265.  
  266.     if (f->dev) {
  267.         r = (*f->dev->close)(f, p->pid);
  268.         if (r) {
  269.             DEBUG("close: device close failed");
  270.         }
  271.     }
  272.     if (f->links <= 0) {
  273.         dispose_fileptr(f);
  274.     }
  275.     return  r;
  276. }
  277.  
  278. long
  279. do_close(f)
  280.     FILEPTR *f;
  281. {
  282.     return do_pclose(curproc, f);
  283. }
  284.  
  285. long
  286. f_open(name, mode)
  287.     const char *name;
  288.     int mode;
  289. {
  290.     int i;
  291.     FILEPTR *f;
  292.     PROC *proc;
  293.  
  294.     TRACE("Fopen(%s, %x)", name, mode);
  295. #if O_GLOBAL
  296.     if (mode & O_GLOBAL) {
  297.         /* oh, boy! user wants us to open a global handle! */
  298.         proc = rootproc;
  299.     }
  300.     else
  301. #endif
  302.         proc = curproc;
  303.  
  304.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  305.         if (!proc->handle[i])
  306.             goto found_for_open;
  307.     }
  308.     DEBUG("Fopen(%s): process out of handles",name);
  309.     return ENHNDL;        /* no more handles */
  310.  
  311. found_for_open:
  312.     mode &= O_USER;        /* make sure the mode is legal */
  313.  
  314. /* note: file mode 3 is reserved for the kernel; for users, transmogrify it
  315.  * into O_RDWR (mode 2)
  316.  */
  317.     if ( (mode & O_RWMODE) == O_EXEC ) {
  318.         mode = (mode & ~O_RWMODE) | O_RDWR;
  319.     }
  320.  
  321.     f = do_open(name, mode, 0, (XATTR *)0);
  322.  
  323.  
  324.     if (!f) {
  325.         return mint_errno;
  326.     }
  327.     proc->handle[i] = f;
  328. /* default is to close non-standard files on exec */
  329.     proc->fdflags[i] = FD_CLOEXEC;
  330.  
  331. #if O_GLOBAL
  332.     if (proc != curproc) {
  333.         /* we just opened a global handle */
  334.         i += 100;
  335.     }
  336. #endif
  337.  
  338.     TRACE("Fopen: returning %d", i);
  339.     return i;
  340. }
  341.  
  342. long
  343. f_create(name, attrib)
  344.     const char *name;
  345.     int attrib;
  346. {
  347.     fcookie dir;
  348.     int i;
  349.     FILEPTR *f;
  350.     long r;
  351.     PROC *proc;
  352.     int offset = 0;
  353.  
  354.     TRACE("Fcreate(%s, %x)", name, attrib);
  355. #if O_GLOBAL
  356.     if (attrib & O_GLOBAL) {
  357.         proc = rootproc;
  358.         offset = 100;
  359.         attrib &= ~O_GLOBAL;
  360.     }
  361.     else
  362. #endif
  363.         proc = curproc;
  364.  
  365.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  366.         if (!proc->handle[i])
  367.             goto found_for_create;
  368.     }
  369.     DEBUG("Fcreate(%s): process out of handles",name);
  370.     return ENHNDL;        /* no more handles */
  371.  
  372. found_for_create:
  373.     if (attrib == FA_LABEL) {
  374.         r = path2cookie(name, temp1, &dir);
  375.         if (r) return r;
  376.         r = (*dir.fs->writelabel)(&dir, temp1);
  377.         if (r) return r;
  378. /*
  379.  * just in case the caller tries to do something with this handle,
  380.  * make it point to u:\dev\null
  381.  */
  382.         f = do_open("u:\\dev\\null", O_RDWR|O_CREAT|O_TRUNC, 0,
  383.                  (XATTR *)0);
  384.         proc->handle[i] = f;
  385.         return i+offset;
  386.     }
  387.     if (attrib & (FA_LABEL|FA_DIR)) {
  388.         DEBUG("Fcreate(%s,%x): illegal attributes",name,attrib);
  389.         return EACCDN;
  390.     }
  391.  
  392.     f = do_open(name, O_RDWR|O_CREAT|O_TRUNC, attrib, (XATTR *)0);
  393.  
  394.     if (!f) {
  395.         DEBUG("Fcreate(%s) failed, error %d", name, mint_errno);
  396.         return mint_errno;
  397.     }
  398.     proc->handle[i] = f;
  399.     i += offset;
  400.     TRACE("Fcreate: returning %d", i);
  401.     return i;
  402. }
  403.  
  404. long
  405. f_close(fh)
  406.     int fh;
  407. {
  408.     FILEPTR *f;
  409.     long r;
  410.     PROC *proc;
  411.  
  412.     TRACE("Fclose: %d", fh);
  413. #if O_GLOBAL
  414.     if (fh >= 100) {
  415.         fh -= 100;
  416.         proc = rootproc;
  417.     }
  418.     else
  419. #endif
  420.         proc = curproc;
  421.  
  422.     if (fh < 0 || fh >= MAX_OPEN || !(f = proc->handle[fh])) {
  423.         return EIHNDL;
  424.     }
  425.     r = do_close(f);
  426.  
  427. /* standard handles should be restored to default values */
  428. /* do this for TOS domain only! */
  429.     if (proc->domain == DOM_TOS) {
  430.         if (fh == 0 || fh == 1)
  431.             f = proc->handle[-1];
  432.         else if (fh == 2 || fh == 3)
  433.             f = proc->handle[-fh];
  434.         else
  435.             f = 0;
  436.     } else
  437.         f = 0;
  438.  
  439.     if (f) f->links++;
  440.     proc->handle[fh] = f;
  441.     return r;
  442. }
  443.  
  444. long
  445. f_read(fh, count, buf)
  446.     int fh;
  447.     long count;
  448.     char *buf;
  449. {
  450.     FILEPTR *f;
  451.  
  452.     PROC *proc;
  453.  
  454. #if O_GLOBAL
  455.     if (fh >= 100) {
  456.         fh -= 100;
  457.         proc = rootproc;
  458.     }
  459.     else
  460. #endif
  461.         proc = curproc;
  462.  
  463.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || !(f = proc->handle[fh])) {
  464.         DEBUG("Fread: invalid handle: %d", fh);
  465.         return EIHNDL;
  466.     }
  467.     if ( (f->flags & O_RWMODE) == O_WRONLY ) {
  468.         DEBUG("Fread: read on a write-only handle");
  469.         return EACCDN;
  470.     }
  471.     if (is_terminal(f))
  472.         return tty_read(f, buf, count);
  473.  
  474.     TRACE("Fread: %ld bytes from handle %d", count, fh);
  475.     return (*f->dev->read)(f, buf, count);
  476. }
  477.  
  478. long
  479. f_write(fh, count, buf)
  480.     int fh;
  481.     long count;
  482.     const char *buf;
  483. {
  484.     FILEPTR *f;
  485.     PROC *proc;
  486.     long r;
  487.  
  488. #if O_GLOBAL
  489.     if (fh >= 100) {
  490.         fh -= 100;
  491.         proc = rootproc;
  492.     }
  493.     else
  494. #endif
  495.         proc = curproc;
  496.  
  497.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || !(f = proc->handle[fh])) {
  498.         DEBUG("Fwrite: bad handle: %d", fh);
  499.         return EIHNDL;
  500.     }
  501.     if ( (f->flags & O_RWMODE) == O_RDONLY ) {
  502.         DEBUG("Fwrite: write on a read-only handle");
  503.         return EACCDN;
  504.     }
  505.     if (is_terminal(f))
  506.         return tty_write(f, buf, count);
  507.  
  508.     /* it would be faster to do this in the device driver, but this
  509.      * way the drivers are easier to write
  510.      */
  511.     if (f->flags & O_APPEND)
  512.         r = (*f->dev->lseek)(f, 0L, SEEK_END);
  513.     else
  514.         r = 0;
  515.     if (r >= 0) {
  516.         TRACE("Fwrite: %ld bytes to handle %d", count, fh);
  517.         r = (*f->dev->write)(f, buf, count);
  518.     }
  519.     if (r < 0) {
  520.         DEBUG("Fwrite: error %ld", r);
  521.     }
  522.     return r;
  523. }
  524.  
  525. long
  526. f_seek(place, fh, how)
  527.     long place;
  528.     int fh;
  529.     int how;
  530. {
  531.     FILEPTR *f;
  532.     PROC *proc;
  533.  
  534.     TRACE("Fseek(%ld, %d) on handle %d", place, how, fh);
  535. #if O_GLOBAL
  536.     if (fh >= 100) {
  537.         fh -= 100;
  538.         proc = rootproc;
  539.     }
  540.     else
  541. #endif
  542.         proc = curproc;
  543.  
  544.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || !(f = proc->handle[fh])) {
  545.         DEBUG("Fseek: bad handle: %d", fh);
  546.         return EIHNDL;
  547.     }
  548.     if (is_terminal(f)) {
  549.         return 0;
  550.     }
  551.     return (*f->dev->lseek)(f, place, how);
  552. }
  553.  
  554. /* duplicate file pointer fh; returns a new file pointer >= min, if
  555.    one exists, or ENHNDL if not. called by f_dup and f_cntl
  556.  */
  557.  
  558. static long do_dup(fh, min)
  559.     int fh, min;
  560. {
  561.     FILEPTR *f;
  562.     int i;
  563.     PROC *proc;
  564.  
  565.     for (i = min; i < MAX_OPEN; i++) {
  566.         if (!curproc->handle[i])
  567.             goto found;
  568.     }
  569.     return ENHNDL;        /* no more handles */
  570. found:
  571. #if O_GLOBAL
  572.     if (fh >= 100) {
  573.         fh -= 100;
  574.         proc = rootproc;
  575.     } else
  576. #endif
  577.         proc = curproc;
  578.  
  579.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || !(f = proc->handle[fh]))
  580.         return EIHNDL;
  581.  
  582.     curproc->handle[i] = f;
  583.  
  584. /* set default file descriptor flags */
  585.     if (i >= 0) {
  586.         if (i >= MIN_OPEN)
  587.             curproc->fdflags[i] = FD_CLOEXEC;
  588.         else
  589.             curproc->fdflags[i] = 0;
  590.     }
  591.     f->links++;
  592.     return i;
  593. }
  594.  
  595. long
  596. f_dup(fh)
  597.     int fh;
  598. {
  599.     long r;
  600.     r = do_dup(fh, MIN_OPEN);
  601.     TRACE("Fdup(%d) -> %ld", fh, r);
  602.     return r;
  603. }
  604.  
  605. long
  606. f_force(newh, oldh)
  607.     int newh;
  608.     int oldh;
  609. {
  610.     FILEPTR *f;
  611.     PROC *proc;
  612.  
  613.     TRACE("Fforce(%d, %d)", newh, oldh);
  614.  
  615. #if O_GLOBAL
  616.     if (oldh >= 100) {
  617.         oldh -= 100;
  618.         proc = rootproc;
  619.     } else
  620. #endif
  621.         proc = curproc;
  622.  
  623.     if (oldh < MIN_HANDLE || oldh >= MAX_OPEN ||
  624.         !(f = proc->handle[oldh])) {
  625.         DEBUG("Fforce: old handle invalid");
  626.         return EIHNDL;
  627.     }
  628.  
  629.     if (newh < MIN_HANDLE || newh >= MAX_OPEN) {
  630.         DEBUG("Fforce: new handle out of range");
  631.         return EIHNDL;
  632.     }
  633.  
  634.     (void)do_close(curproc->handle[newh]);
  635.     curproc->handle[newh] = f;
  636.     f->links++;
  637. /*
  638.  * special: for a tty, if this is becoming a control terminal and the
  639.  * tty doesn't have a pgrp yet, make it have the pgrp of the process
  640.  * doing the Fforce
  641.  */
  642.     if (is_terminal(f) && newh == -1) {
  643.         struct tty *tty = (struct tty *)f->devinfo;
  644.  
  645.         if (!tty->pgrp)
  646.             tty->pgrp = curproc->pgrp;
  647.     }
  648.     return newh;
  649. }
  650.  
  651. long
  652. f_datime(timeptr, fh, rwflag)
  653.     short *timeptr;
  654.     int fh;
  655.     int rwflag;
  656. {
  657.     FILEPTR *f;
  658.     PROC *proc;
  659.  
  660.     TRACE("Fdatime(%d)", fh);
  661. #if O_GLOBAL
  662.     if (fh >= 100) {
  663.         fh -= 100;
  664.         proc = rootproc;
  665.     }
  666.     else
  667. #endif
  668.         proc = curproc;
  669.  
  670.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || !(f = proc->handle[fh])) {
  671.         DEBUG("Fdatime: invalid handle");
  672.         return EIHNDL;
  673.     }
  674.  
  675. /* some programs use Fdatime to test for TTY devices */
  676.     if (is_terminal(f))
  677.         return EACCDN;
  678.  
  679.     return (*f->dev->datime)(f, timeptr, rwflag);
  680. }
  681.  
  682. long
  683. f_lock(fh, mode, start, length)
  684.     int fh, mode;
  685.     long start, length;
  686. {
  687.     FILEPTR *f;
  688.     struct flock lock;
  689.     PROC *proc;
  690.  
  691. #if O_GLOBAL
  692.     if (fh >= 100) {
  693.         fh -= 100;
  694.         proc = rootproc;
  695.     }
  696.     else
  697. #endif
  698.         proc = curproc;
  699.  
  700.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || !(f = proc->handle[fh])) {
  701.         DEBUG("Flock: invalid handle");
  702.         return EIHNDL;
  703.     }
  704.     TRACE("Flock(%d,%d,%ld,%ld)", fh, mode, start, length);
  705.     lock.l_whence = SEEK_SET;
  706.     lock.l_start = start;
  707.     lock.l_len = length;
  708.  
  709.     if (mode == 0)        /* create a lock */
  710.         lock.l_type = F_WRLCK;
  711.     else if (mode == 1)    /* unlock region */
  712.         lock.l_type = F_UNLCK;
  713.     else
  714.         return EINVFN;
  715.  
  716.     return (*f->dev->ioctl)(f, F_SETLK, &lock);
  717. }
  718.  
  719. /*
  720.  * extensions to GEMDOS:
  721.  */
  722.  
  723. /*
  724.  * Fpipe(int *handles): opens a pipe. if successful, returns 0, and
  725.  * sets handles[0] to a file descriptor for the read end of the pipe
  726.  * and handles[1] to one for the write end.
  727.  */
  728.  
  729. long
  730. f_pipe(usrh)
  731.     short *usrh;
  732. {
  733.     extern FILESYS pipe_filesys;
  734.     FILESYS *fs;
  735.     FILEPTR *in, *out;
  736.     static int pipeno = 0;
  737.     int i, j;
  738.     char pipename[32]; /* MAGIC: 32 >= strlen "u:\pipe\sys$pipe.000\0" */
  739.  
  740.     TRACE("Fpipe");
  741.     fs = &pipe_filesys;
  742.  
  743. /* BUG: more than 999 open pipes hangs the system */
  744.     do {
  745.         ksprintf(pipename, "u:\\pipe\\sys$pipe.%03d", pipeno);
  746.         pipeno++; if (pipeno > 999) pipeno = 0;
  747.         out = do_open(pipename, O_WRONLY|O_CREAT|O_EXCL, 3, (XATTR *)0);
  748.             /* read-only attribute means unidirectional fifo */
  749.             /* hidden attribute means check for broken pipes */
  750.     } while (out == 0 && mint_errno == EACCDN);
  751.  
  752.     if (!out) {
  753.         DEBUG("Fpipe: error %d", mint_errno);
  754.         return mint_errno;
  755.     }
  756.  
  757.     in = do_open(pipename, O_RDONLY, 0, (XATTR *)0);
  758.     if (!in) {
  759.         DEBUG("Fpipe: in side of pipe not opened (error %d)",
  760.             mint_errno);
  761.         (void)do_close(out);
  762.         return mint_errno;
  763.     }
  764.  
  765.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  766.         if (curproc->handle[i] == 0)
  767.             break;
  768.     }
  769.  
  770.     for (j = i+1; j < MAX_OPEN; j++) {
  771.         if (curproc->handle[j] == 0)
  772.             break;
  773.     }
  774.  
  775.     if (j >= MAX_OPEN) {
  776.         DEBUG("Fpipe: not enough handles left");
  777.         (void) do_close(in);
  778.         (void) do_close(out);
  779.         return ENHNDL;
  780.     }
  781.     curproc->handle[i] = in; curproc->handle[j] = out;
  782. /* leave pipes open across Pexec */
  783.     curproc->fdflags[i] = 0;
  784.     curproc->fdflags[j] = 0;
  785.  
  786.     usrh[0] = i;
  787.     usrh[1] = j;
  788.     TRACE("Fpipe: returning 0: input %d output %d",i,j);
  789.     return 0;
  790. }
  791.  
  792. /*
  793.  * f_cntl: a combination "ioctl" and "fcntl". Some functions are
  794.  * handled here, if they apply to the file descriptors directly
  795.  * (e.g. F_DUPFD) or if they're easily translated into file system
  796.  * functions (e.g. FSTAT). Others are passed on to the device driver
  797.  * via dev->ioctl.
  798.  */
  799.  
  800. long
  801. f_cntl(fh, arg, cmd)
  802.     int fh;
  803.     long arg;
  804.     int cmd;
  805. {
  806.     FILEPTR    *f;
  807.     PROC *proc;
  808.     struct flock *fl;
  809.     long r;
  810.  
  811.     TRACE("Fcntl(%d, cmd=0x%x)", fh, cmd);
  812. #if O_GLOBAL
  813.     if (fh >= 100) {
  814.         fh -= 100;
  815.         proc = rootproc;
  816.     }
  817.     else
  818. #endif
  819.         proc = curproc;
  820.  
  821.     if (fh < MIN_HANDLE || fh >= MAX_OPEN) {
  822.         DEBUG("Fcntl: bad file handle");
  823.         return EIHNDL;
  824.     }
  825.  
  826.     if (cmd == F_DUPFD) {
  827. #if O_GLOBAL
  828.         if (proc != curproc) fh += 100;
  829. #endif
  830.           return do_dup(fh, (int)arg);
  831.     }
  832.  
  833.     f = proc->handle[fh];
  834.     if (!f) return EIHNDL;
  835.  
  836.     switch(cmd) {
  837.     case F_GETFD:
  838.         TRACE("Fcntl F_GETFD");
  839.         if (fh < 0) return EIHNDL;
  840.         return proc->fdflags[fh];
  841.     case F_SETFD:
  842.         TRACE("Fcntl F_SETFD");
  843.         if (fh < 0) return EIHNDL;
  844.         proc->fdflags[fh] = arg;
  845.         return 0;
  846.     case F_GETFL:
  847.         TRACE("Fcntl F_GETFL");
  848.         return f->flags & O_USER;
  849.     case F_SETFL:
  850.         TRACE("Fcntl F_SETFL");
  851.         arg &= O_USER;        /* make sure only user bits set */
  852.     /* COMPATIBILITY WITH OLD VERSIONS ONLY */
  853.     /* THIS CODE WILL GO AWAY. REALLY! */
  854.         if (arg & 4) {
  855.             arg |= O_NDELAY;
  856.             arg &= ~4;
  857.         }
  858.  
  859.     /* make sure the file access and sharing modes are not changed */
  860.         arg &= ~(O_RWMODE|O_SHMODE);
  861.         arg |= f->flags & (O_RWMODE|O_SHMODE);
  862.         f->flags &= ~O_USER;    /* set user bits to arg */
  863.         f->flags |= arg;
  864.         return 0;
  865.     case FSTAT:
  866.         return (*f->fc.fs->getxattr)(&f->fc, (XATTR *)arg);
  867.     case F_SETLK:
  868.     /* make sure that the file was opened with appropriate permissions */
  869.         fl = (struct flock *)arg;
  870.         if (fl->l_type == F_RDLCK) {
  871.             if ( (f->flags & O_RWMODE) == O_WRONLY )
  872.                 return EACCDN;
  873.         } else {
  874.             if ( (f->flags & O_RWMODE) == O_RDONLY )
  875.                 return EACCDN;
  876.         }
  877.         /* fall through to device ioctl */
  878.     default:
  879.         TRACE("Fcntl mode %x: calling ioctl",cmd);
  880.         r = (*f->dev->ioctl)(f, cmd, (void *)arg);
  881.         if (r == EINVFN && is_terminal(f)) {
  882.             r = tty_ioctl(f, cmd, (void *)arg);
  883.         }
  884.         return r;
  885.     }
  886. }
  887.  
  888. /*
  889.  * fselect(timeout, rfd, wfd, xfd)
  890.  * timeout is an (unsigned) 16 bit integer giving the maximum number
  891.  * of milliseconds to wait; rfd, wfd, and xfd are pointers to 32 bit
  892.  * integers containing bitmasks that describe which file descriptors
  893.  * we're interested in. These masks are changed to represent which
  894.  * file descriptors actually have data waiting (rfd), are ready to
  895.  * output (wfd), or have exceptional conditions (xfd -- currently
  896.  * ignored). If timeout is 0, fselect blocks until some file descriptor
  897.  * is ready; otherwise, it waits only "timeout" milliseconds.
  898.  * Return value: number of file descriptors that are available for
  899.  * reading/writing; or a negative error number.
  900.  */
  901.  
  902. /* helper function for time outs */
  903. static void
  904. unselectme(p)
  905.     PROC *p;
  906. {
  907.     wakeselect((long)p);
  908. }
  909.  
  910. long
  911. f_select(timeout, rfdp, wfdp, xfdp)
  912.     unsigned timeout;
  913.     long *rfdp, *wfdp, *xfdp;
  914. {
  915.     long rfd, wfd;
  916.     long mask, bytes;
  917.     int i, count;
  918.     FILEPTR *f;
  919.     PROC *p;
  920.     TIMEOUT *t;
  921.  
  922.     if (rfdp) {
  923.         rfd = *rfdp; *rfdp = 0;
  924.     }
  925.     else
  926.         rfd = 0;
  927.     if (wfdp) {
  928.         wfd = *wfdp; *wfdp = 0;
  929.     }
  930.     else
  931.         wfd = 0;
  932.  
  933.     TRACE("Fselect(%u, %lx, %lx)", timeout, rfd, wfd);
  934.     p = curproc;            /* help the optimizer out */
  935.  
  936.     /* first, validate the masks */
  937.     mask = 1L;
  938.     for (i = 0; i < MAX_OPEN; i++) {
  939.         if ( ((rfd & mask) || (wfd & mask)) && !(p->handle[i]) ) {
  940.             DEBUG("Fselect: invalid handle");
  941.             return EIHNDL;
  942.         }
  943.         mask = mask << 1L;
  944.     }
  945.  
  946. /* now, loop through the file descriptors, setting up the select process */
  947. /* NOTE: wakeselect will set p->wait_cond to 0 if data arrives during the
  948.  * selection
  949.  * Also note: because of the validation above, we may assume that the
  950.  * file handles are valid here. However, this assumption may no longer
  951.  * be true after we've gone to sleep, since a signal handler may have
  952.  * closed one of the handles.
  953.  */
  954.  
  955.     mask = 1L;
  956.     count = 0;
  957.     curproc->wait_cond = (long)&wakeselect;        /* flag */
  958.  
  959.     for (i = 0; i < MAX_OPEN; i++) {
  960.         if (rfd & mask) {
  961.             f = p->handle[i];
  962.             if ((*f->dev->select)(f, (long)p, O_RDONLY)) {
  963.                 count++;
  964.                 *rfdp |= mask;
  965.             }
  966.         }
  967.         if (wfd & mask) {
  968.             f = p->handle[i];
  969.             if ((*f->dev->select)(f, (long)p, O_WRONLY)) {
  970.                 count++;
  971.                 *wfdp |= mask;
  972.             }
  973.         }
  974.         mask = mask << 1L;
  975.     }
  976.  
  977.     if (count == 0) {
  978.         /* OK, now let's set a timeout */
  979.  
  980.         if (timeout) {
  981.             t = addtimeout((long)timeout, unselectme);
  982.         } else {
  983.             t = 0;
  984.         }
  985.  
  986.     /* curproc->wait_cond changes when data arrives or the timeout happens */
  987.         while (curproc->wait_cond == (long)&wakeselect) {
  988.             TRACE("sleeping in Fselect");
  989.             sleep(SELECT_Q, (long)&wakeselect);
  990.         }
  991.  
  992.     /* we can cancel the time out now (if it hasn't already happened) */
  993.         if (t) canceltimeout(t);
  994.  
  995.     /* OK, let's see what data arrived (if any) */
  996.         mask = 1L;
  997.         for (i = 0; i < MAX_OPEN; i++) {
  998.             if (rfd & mask) {
  999.                 f = p->handle[i];
  1000.                 if (f) {
  1001.                     bytes = 1L;
  1002.                     (void)(*f->dev->ioctl)(f, FIONREAD,&bytes);
  1003.                     if (bytes > 0) {
  1004.                     *rfdp |= mask;
  1005.                     count++;
  1006.                     }
  1007.                 }
  1008.             }
  1009.             if (wfd & mask) {
  1010.                 f = p->handle[i];
  1011.                 if (f) {
  1012.                     bytes = 1L;
  1013.                     (void)(*f->dev->ioctl)(f, FIONWRITE,&bytes);
  1014.                     if (bytes > 0) {
  1015.                     *wfdp |= mask;
  1016.                     count++;
  1017.                     }
  1018.                 }
  1019.             }
  1020.             mask = mask << 1L;
  1021.         }
  1022.     } else {
  1023. /*        TRACE("Fselect: data already present (count == %d)", count); */
  1024.     }
  1025.  
  1026.     /* at this point, we either have data or a time out */
  1027.     /* cancel all the selects */
  1028.     mask = 1L;
  1029.  
  1030.     for (i = 0; i < MAX_OPEN; i++) {
  1031.         if (rfd & mask) {
  1032.             f = p->handle[i];
  1033.             if (f)
  1034.                 (*f->dev->unselect)(f, (long)p, O_RDONLY);
  1035.         }
  1036.         if (wfd & mask) {
  1037.             f = p->handle[i];
  1038.             if (f)
  1039.                 (*f->dev->unselect)(f, (long)p, O_WRONLY);
  1040.         }
  1041.         mask = mask << 1L;
  1042.     }
  1043.  
  1044.     TRACE("Fselect: returning %d", count);
  1045.     return count;
  1046. }
  1047.  
  1048.  
  1049. /*
  1050.  * GEMDOS extension: Fmidipipe
  1051.  * Fmidipipe(pid, in, out) manipultes the MIDI file handles (handles -4 and -5)
  1052.  * of process "pid" so that they now point to the files with handles "in" and
  1053.  * "out" in the calling process
  1054.  */
  1055.  
  1056. long
  1057. f_midipipe(pid, in, out)
  1058.     int pid, in, out;
  1059. {
  1060.     PROC *p;
  1061.     FILEPTR *fin, *fout;
  1062.  
  1063. /* first, find the process */
  1064.  
  1065.     if (pid == 0)
  1066.         p = curproc;
  1067.     else {
  1068.         p = pid2proc(pid);
  1069.         if (!p)
  1070.             return EFILNF;
  1071.     }
  1072.  
  1073. /* next, validate the input and output file handles */
  1074.     if (in < MIN_HANDLE || in >= MAX_OPEN || (!(fin = curproc->handle[in])))
  1075.         return EIHNDL;
  1076.     if ( (fin->flags & O_RWMODE) == O_WRONLY ) {
  1077.         DEBUG("Fmidipipe: input side is write only");
  1078.         return EACCDN;
  1079.     }
  1080.     if (out < MIN_HANDLE || out >= MAX_OPEN || (!(fout = curproc->handle[out])))
  1081.         return EIHNDL;
  1082.     if ( (fout->flags & O_RWMODE) == O_RDONLY ) {
  1083.         DEBUG("Fmidipipe: output side is read only");
  1084.         return EACCDN;
  1085.     }
  1086.  
  1087. /* OK, duplicate the handles and put them in the new process */
  1088.     fin->links++; fout->links++;
  1089.     (void)do_pclose(p, p->midiin);
  1090.     (void)do_pclose(p, p->midiout);
  1091.     p->midiin = fin; p->midiout = fout;
  1092.     return 0;
  1093. }
  1094.