home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mint104s.zoo / mint.src / dosfile.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  25KB  |  1,136 lines

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