home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 10: Diskmags / nf_archive_10.iso / MAGS / PURE_B / PBMAG22A.MSA / MINT095S.ZIP / SRC / FILESYS.C < prev    next >
C/C++ Source or Header  |  1987-04-22  |  23KB  |  950 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * various file system interface things
  7.  */
  8.  
  9. #include "mint.h"
  10.  
  11. FILESYS *active_fs;
  12. FILESYS *drives[NUM_DRIVES];
  13.  
  14. FILEPTR *flist;        /* a list of free file pointers */
  15.  
  16. char follow_links[1];    /* dummy "name" used as a parameter to path2cookie */
  17.  
  18. /* vector of valid drives, according to GEMDOS */
  19. /* note that this isn't necessarily the same as what the BIOS thinks of
  20.  * as valid
  21.  */
  22. long dosdrvs;
  23.  
  24. /*
  25.  * Initialize a specific drive. This is called whenever a new drive
  26.  * is accessed, or when media change occurs on an old drive.
  27.  * Assumption: at this point, active_fs is a valid pointer
  28.  * to a list of file systems.
  29.  */
  30.  
  31. /* table of processes holding locks on drives */
  32. extern PROC *dlockproc[];    /* in dosdir.c */
  33.  
  34. void
  35. init_drive(i)
  36.     int i;
  37. {
  38.     long r;
  39.     FILESYS *fs;
  40.     fcookie root_dir;
  41.  
  42.     TRACE("init_drive(%c)", i+'A');
  43.  
  44.     drives[i] = 0;        /* no file system */
  45.     if (i >= 0 && i < NUM_DRIVES) {
  46.         if (dlockproc[i]) return;
  47.     }
  48.  
  49.     for (fs = active_fs; fs; fs = fs->next) {
  50.         r = (*fs->root)(i, &root_dir);
  51.         if (r == 0) {
  52.             drives[i] = root_dir.fs;
  53.             break;
  54.         }
  55.     }
  56. }
  57.  
  58. /*
  59.  * initialize the file system
  60.  */
  61.  
  62. #define NUMFPS    40    /* initial number of file pointers */
  63.  
  64. void
  65. init_filesys()
  66. {
  67.     static FILEPTR initial[NUMFPS+1];
  68.     long drv;
  69.     int i;
  70.     extern FILESYS tos_filesys, bios_filesys, pipe_filesys,
  71.         proc_filesys, uni_filesys;
  72.  
  73. /* get the vector of connected GEMDOS drives */
  74.     dosdrvs = Dsetdrv(Dgetdrv()) | drvmap();
  75.  
  76. /* set up some initial file pointers */
  77.     for (i = 0; i < NUMFPS; i++) {
  78.         initial[i].devinfo = (ulong) (&initial[i+1]);
  79.     }
  80.     initial[NUMFPS].devinfo = 0;
  81.     flist = initial;
  82.  
  83. /* set up the file systems */
  84.     tos_filesys.next = 0;
  85.     bios_filesys.next = &tos_filesys;
  86.     pipe_filesys.next = &bios_filesys;
  87.     proc_filesys.next = &pipe_filesys;
  88.     uni_filesys.next = &proc_filesys;
  89.  
  90.     active_fs = &uni_filesys;
  91.  
  92. /* initialize the BIOS file system */
  93.     biosfs_init();
  94.  
  95. /* initialize the unified file system */
  96.     unifs_init();
  97.  
  98.     drv = dosdrvs | PSEUDODRVS;
  99.  
  100. #if 0
  101. /* now run through the systems and see who's interested in what drives */
  102. /* THIS IS NOW DONE AUTOMAGICALLY IN path2cookie */
  103.     for (i = 0; i < NUM_DRIVES; i++) {
  104.         if ( drv & (1L << i) )
  105.             init_drive(i);
  106.     }
  107. #endif
  108. }
  109.  
  110. /*
  111.  * load file systems from disk
  112.  * this routine is called after process 0 is set up, but before any user
  113.  * processes are run
  114.  *
  115.  * NOTE that a number of directory changes take place here: we look first
  116.  * in the current directory, then in the directory \mint, and finally
  117.  * the d_lock() calls force us into the root directory.
  118.  */
  119.  
  120. typedef FILESYS * (*FSFUNC) P_((struct kerinfo *));
  121.  
  122. void
  123. load_filesys()
  124. {
  125.     long r;
  126.     BASEPAGE *b;
  127.     FILESYS *fs;
  128.     FSFUNC initf;
  129.     static DTABUF dta;
  130.     int i;
  131.     extern struct kerinfo kernelinfo; /* in main.c */
  132. #define NPATHS 2
  133.     static const char *paths[NPATHS] = {"", "\\mint"};
  134.  
  135.     curproc->dta = &dta;
  136.  
  137.     for (i = 0; i < NPATHS; i++) {
  138.         if (*paths[i])
  139.             d_setpath(paths[i]);
  140.         r = f_sfirst("*.xfs", 0);
  141.         while (r == 0) {
  142.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  143.         if ( ((long)b) < 0 ) {
  144.             DEBUG("Error loading file system %s", dta.dta_name);
  145.             continue;
  146.         }
  147.     /* we leave a little bit of slop at the end of the loaded stuff */
  148.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  149.         initf = (FSFUNC)b->p_tbase;
  150.         fs = (*initf)(&kernelinfo);
  151.         TRACE("initializing %s", dta.dta_name);
  152.  
  153.         if (fs) {
  154.             TRACE("%s loaded OK", dta.dta_name);
  155.             fs->next = active_fs;
  156.             active_fs = fs;
  157.         } else {
  158.             DEBUG("%s returned null", dta.dta_name);
  159.         }
  160.         r = f_snext();
  161.         }
  162.     }
  163.  
  164. /* here, we invalidate all old drives EXCEPT for ones we're already using (at
  165.  * this point, only the bios devices should be open)
  166.  * this gives newly loaded file systems a chance to replace the
  167.  * default tosfs.c
  168.  */
  169.     for (i = 0; i < NUM_DRIVES; i++) {
  170.         if (d_lock(1, i) == 0)    /* lock if possible */
  171.             d_lock(0, i);    /* and then unlock */
  172.     }
  173. }
  174.  
  175. void
  176. close_filesys()
  177. {
  178.     PROC *p;
  179.     FILEPTR *f;
  180.     int i;
  181.  
  182.     TRACE("close_filesys");
  183. /* close every open file */
  184.     for (p = proclist; p; p = p->gl_next) {
  185.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  186.             if ( (f = p->handle[i]) != 0) {
  187.                 if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q)
  188.                     ALERT("Open file for dead process?");
  189.                 do_pclose(p, f);
  190.             }
  191.         }
  192.     }
  193. }
  194.  
  195. /*
  196.  * "media change" routine: called when a media change is detected on device
  197.  * d, which may or may not be a BIOS device. All handles associated with
  198.  * the device are closed, and all directories invalidated. This routine
  199.  * does all the dirty work, and is called automatically when
  200.  * disk_changed detects a media change.
  201.  */
  202.  
  203. void
  204. changedrv(d)
  205.     unsigned d;
  206. {
  207.     PROC *p;
  208.     int i;
  209.     FILEPTR *f;
  210.     FILESYS *fs;
  211.     DIR *dirh;
  212.     fcookie dir;
  213.     int warned = (d & 0xf000) == PROC_BASE_DEV;
  214.     int r;
  215.  
  216. /* re-initialize the device, if it was a BIOS device */
  217.     if (d < NUM_DRIVES) {
  218.         fs = drives[d];
  219.         if (fs) {
  220.             (void)(*fs->dskchng)(d);
  221.         }
  222.         init_drive(d);
  223.     }
  224.  
  225.     for (p = proclist; p; p = p->gl_next) {
  226.     /* invalidate all open files on this device */
  227.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  228.             if (((f = p->handle[i]) != 0) && (f->fc.dev == d)) {
  229.                 if (!warned) {
  230.                 ALERT(
  231. "Files were open on a changed drive (0x%x)!", d);
  232.                 warned++;
  233.                 }
  234.  
  235. /* we set f->dev to NULL to indicate to do_pclose that this is an
  236.  * emergency close, and that it shouldn't try to make any
  237.  * calls to the device driver since the file has gone away
  238.  */
  239.                 f->dev = NULL;
  240.                 (void)do_pclose(p, f);
  241.                 p->handle[i] = 0;
  242.             }
  243.         }
  244.  
  245.     /* terminate any active directory searches on the drive */
  246.     /* BUG: This handles only Fsfirst/Fsnext searches! */
  247.         for (i = 0; i < NUM_SEARCH; i++) {
  248.             dirh = &curproc->srchdir[i];
  249.             if (dirh->fc.fs && dirh->fc.dev == d) {
  250.                 dirh->fc.fs = 0;
  251.                 curproc->srchdta[i] = 0;
  252.             }
  253.         }
  254.  
  255.         if (d >= NUM_DRIVES) continue;
  256.  
  257.     /* change any active directories on the device to the (new) root */
  258.         fs = drives[d];
  259.         if (fs) {
  260.             r = (*fs->root)(d, &dir);
  261.             if (r != E_OK) dir.fs = 0;
  262.         } else {
  263.             dir.fs = 0; dir.dev = d;
  264.         }
  265.  
  266.         for (i = 0; i < NUM_DRIVES; i++) {
  267.             if (p->root[i].dev == d)
  268.                 p->root[i] = dir;
  269.             if (p->curdir[i].dev == d)
  270.                 p->curdir[i] = dir;
  271.         }
  272.     }
  273. }
  274.  
  275. /*
  276.  * check for media change: if the drive has changed, call changedrv to
  277.  * invalidate any open files and file handles associated with it, and
  278.  * call the file system's media change routine.
  279.  * returns: 0 if no change, 1 if change
  280.  */
  281.  
  282. int
  283. disk_changed(d)
  284.     int d;
  285. {
  286.     short r;
  287.     FILESYS *fs;
  288.     static char tmpbuf[8192];
  289.  
  290. /* for now, only check BIOS devices */
  291.     if (d < 0 || d >= NUM_DRIVES)
  292.         return 0;
  293.  
  294. /* has the drive been initialized yet? If not, then initialize it and return
  295.  * "no change"
  296.  */
  297.     if (!(fs = drives[d])) {
  298.         TRACE("drive %c not yet initialized", d+'A');
  299.         changedrv(d);
  300.         return 0;
  301.     }
  302.  
  303. /* We have to do this stuff no matter what, because someone may have installed
  304.  * vectors to force a media change...
  305.  * PROBLEM: AHDI may get upset if the drive isn't valid.
  306.  * SOLUTION: don't change the default PSEUDODRIVES setting!
  307.  */
  308.     r = mediach(d);
  309.     if (r == 1) {        /* drive _may_ have changed */
  310.         r = rwabs(0, tmpbuf, 1, 0, d, 0L);    /* check the BIOS */
  311.         if (r != E_CHNG) {            /* nope, no change */
  312.             return 0;
  313.         }
  314.         r = 2;            /* drive was definitely changed */
  315.     }
  316.     if (r == 2) {
  317.         fs = drives[d];        /* get filesystem associated with drive */
  318.         if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */
  319.             changedrv(d);    /* yes -- do the change */
  320.             return 1;
  321.         }
  322.     }
  323.     return 0;
  324. }
  325.  
  326. /*
  327.  * routines for parsing path names
  328.  */
  329.  
  330. char temp1[PATH_MAX];    /* temporary storage for file names */
  331.  
  332. #define DIRSEP(p) ((p) == '\\')
  333.  
  334. /*
  335.  * relpath2cookie converts a TOS file name into a file cookie representing
  336.  * the directory the file resides in, and a character string representing
  337.  * the name of the file in that directory. The character string is
  338.  * copied into the "lastname" array. If lastname is NULL, then the cookie
  339.  * returned actually represents the file, instead of just the directory
  340.  * the file is in.
  341.  *
  342.  * note that lastname, if non-null, should be big enough to contain all the
  343.  * characters in "path", since if the file system doesn't want the kernel
  344.  * to do path name parsing we may end up just copying path to lastname
  345.  * and returning the current or root directory, as appropriate
  346.  *
  347.  * "relto" is the directory relative to which the search should start.
  348.  * if you just want the current directory, use path2cookie instead.
  349.  *
  350.  * "depth" is used to control recursion in symbolic links; if it exceeds
  351.  * MAX_LINKS, we return ELOOP.
  352.  *
  353.  * N.B.: "depth" is also overloaded to control whether drive letter
  354.  * interpretation is performed; if drive == 0, it is assumed that
  355.  * drive letters should _not_ be interpreted; if drive > 0, it
  356.  * is assumed that they should be, since we are in this case following
  357.  * a symbolic link.
  358.  */
  359.  
  360. #define MAX_LINKS 4
  361.  
  362. long
  363. relpath2cookie(relto, path, lastname, res, depth)
  364.     fcookie *relto;
  365.     const char *path;
  366.     char *lastname;
  367.     fcookie *res;
  368.     int depth;
  369. {
  370.     static fcookie dir;
  371.     int drv;
  372.     int len;
  373.     char c, *s;
  374.     XATTR xattr;
  375.     static char newpath[16] = "U:\\DEV\\";
  376.     char temp2[PATH_MAX];
  377.     char linkstuff[PATH_MAX];
  378.     long r = 0;
  379.  
  380. /* dolast: 0 == return a cookie for the directory the file is in
  381.  *         1 == return a cookie for the file itself, don't follow links
  382.  *       2 == return a cookie for whatever the file points at
  383.  */
  384.     int dolast = 0;
  385.     int i = 0;
  386.  
  387. TRACE("relpath2cookie(%s)", path);
  388.  
  389.     if (depth > MAX_LINKS) return ELOOP;
  390.  
  391.     if (!lastname) {
  392.         dolast = 1;
  393.         lastname = temp2;
  394.     } else if (lastname == follow_links) {
  395.         dolast = 2;
  396.         lastname = temp2;
  397.     }
  398.  
  399.     *lastname = 0;
  400.  
  401. /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON,
  402.  * U:\DEV\AUX, etc.
  403.  */
  404.     if (strlen(path) == 4 && path[3] == ':') {
  405.         strncpy(newpath+7, path, 3);
  406.         path = newpath;
  407.     }
  408.  
  409. /* first, check for a drive letter */
  410. /* BUG: a '\' at the start of a symbolic link is relative to the current
  411.  * drive of the process, not the drive the link is located on
  412.  */
  413.     if (path[1] == ':' && depth > 0) {
  414.         c = path[0];
  415.         if (c >= 'a' && c <= 'z')
  416.             drv = c - 'a';
  417.         else if (c >= 'A' && c <= 'Z')
  418.             drv = c - 'A';
  419.         else
  420.             goto nodrive;
  421.         path += 2;
  422.         i = 1;        /* remember that we saw a drive letter */
  423.     } else {
  424. nodrive:
  425.         drv = curproc->curdrv;
  426.     }
  427.  
  428. /* see if the path is rooted from '\\' */
  429.     if (DIRSEP(*path)) {
  430.         while(DIRSEP(*path))path++;
  431.         dir = curproc->root[drv];
  432.     } else {
  433.         if (i)    {    /* an explicit drive letter was given */
  434.             dir = curproc->curdir[drv];
  435.         }
  436.         else
  437.             dir = *relto;
  438.     }
  439.  
  440.     if (!dir.fs) {
  441.         changedrv(dir.dev);
  442.         dir = curproc->root[drv];
  443.     }
  444.  
  445.     if (!dir.fs) {
  446.         DEBUG("path2cookie: no file system");
  447.         return EDRIVE;
  448.     }
  449.  
  450.     *res = dir;
  451.     if (!*path) {        /* nothing more to do */
  452.         return 0;
  453.     }
  454.  
  455.     /* here's where we come when we've gone across a mount point */
  456.     
  457. restart_mount:
  458.  
  459. /* see if there has been a disk change; if so, return E_CHNG.
  460.  * path2cookie will restart the search automatically; other functions
  461.  * that call relpath2cookie directly will have to fail gracefully
  462.  */
  463.     if (disk_changed(dir.dev)) {
  464.         return E_CHNG;
  465.     }
  466.  
  467.     if (dir.fs->fsflags & FS_KNOPARSE) {
  468.         if (!dolast) {
  469.             strncpy(lastname, path, PATH_MAX-1);
  470.             lastname[PATH_MAX - 1] = 0;
  471.             r = 0;
  472.         } else {
  473.             r = (*dir.fs->lookup)(&dir, path, res);
  474.         }
  475.         goto check_for_mount;
  476.     }
  477.  
  478. /* parse all but (possibly) the last component of the path name */
  479.  
  480.     for(;;) {
  481.     /* if nothing left in path, and we don't care about links,
  482.      * then we're finished
  483.      */
  484.         if (dolast < 2 && !*path) {
  485.             dir = *res;
  486.             break;
  487.         }
  488.     /* first, check to see if we're allowed to read this link/directory
  489.      * NOTE: at this point, "res" contains the new 'directory', and
  490.      * "dir" contains the old directory we were in (in case we need
  491.      * to call relpath2cookie on a link)
  492.      */
  493.         r = (res->fs->getxattr)(res, &xattr);
  494.         if (r != 0) {
  495.             DEBUG("path2cookie: couldn't get file attributes");
  496.             break;
  497.         }
  498.     /* if the "directory" is a link, follow it */
  499.         i = depth;
  500.         while ( (xattr.mode & S_IFMT) == S_IFLNK ) {
  501.             if (i++ > MAX_LINKS)
  502.                 return ELOOP;
  503.             r = (res->fs->readlink)(res, linkstuff, PATH_MAX);
  504.             if (r) {
  505.                 DEBUG("error reading symbolic link");
  506.                 break;
  507.             }
  508.             r = relpath2cookie(&dir, linkstuff, follow_links, res,
  509.                         depth+1);
  510.             if (r) {
  511.                 DEBUG("error following symbolic link");
  512.                 break;
  513.             }
  514.             (void)(res->fs->getxattr)(res, &xattr);
  515.         }
  516.  
  517.     /* if there's nothing left in the path, we can break here */
  518.         if (!*path) {
  519.             dir = *res;
  520.             break;
  521.         }
  522.  
  523.     /* the "directory" had better, in fact, be a directory */
  524.         if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  525.             return EPTHNF;
  526.          }
  527.     /* and we had better have search permission to it */
  528.         if (denyaccess(&xattr, S_IXOTH)) {
  529.             DEBUG("search permission in directory denied");
  530.             return EPTHNF;
  531.         }
  532.  
  533.         dir = *res;
  534.  
  535.     /* next, peel off the next name in the path */
  536.         len = 0;
  537.         s = lastname;
  538.         c = *path;
  539.         while (c && !DIRSEP(c)) {
  540.             if (len++ < PATH_MAX)
  541.                 *s++ = c;
  542.             c = *++path;
  543.         }
  544.         *s = 0;
  545.         while(DIRSEP(*path))path++;
  546.  
  547.     /* if there are no more names in the path, then we may be done */
  548.         if (dolast == 0 && !*path)
  549.             break;
  550.  
  551.         r = (*dir.fs->lookup)(&dir, lastname, res);
  552.         if (r) {        /* error? */
  553.             DEBUG("path2cookie: lookup returned %ld", r);
  554.             dir = *res;
  555.             break;
  556.         }
  557.     }
  558.  
  559. check_for_mount:
  560.  
  561.     if (r == EMOUNT) {    /* hmmm... a ".." at a mount point, maybe */
  562.         fcookie mounteddir;
  563.         r = (*dir.fs->root)(dir.dev, &mounteddir);
  564.         if (r == 0 && drv == UNIDRV) {
  565.             if (dir.fs == mounteddir.fs &&
  566.                 dir.index == mounteddir.index &&
  567.                 dir.dev == mounteddir.dev) {
  568.                 *res = dir = curproc->root[UNIDRV];
  569.             TRACE("path2cookie: restarting from mount point");
  570.                 goto restart_mount;
  571.             }
  572.         }
  573.         else r = 0;
  574.     }
  575.  
  576.     return r;
  577. }
  578.  
  579. #define MAX_TRYS 8
  580.  
  581. long
  582. path2cookie(path, lastname, res)
  583.     const char *path;
  584.     char *lastname;
  585.     fcookie *res;
  586. {
  587.     fcookie *dir;
  588.     long r;
  589. /* AHDI sometimes will keep insisting that a media change occured;
  590.  * we limit the number or retrys to avoid hanging the system
  591.  */
  592.     int trycnt = 0;
  593.  
  594.     dir = &curproc->curdir[curproc->curdrv];
  595.  
  596.     do {
  597.     /* NOTE: depth == 1 is necessary; see the comments before relpath2cookie */
  598.         r = relpath2cookie(dir, path, lastname, res, 1);
  599.         if (r == E_CHNG)
  600.             DEBUG("path2cookie: restarting due to media change");
  601.     } while (r == E_CHNG && trycnt++ < MAX_TRYS);
  602.  
  603.     return r;
  604. }
  605.  
  606. /*
  607.  * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer
  608.  */
  609.  
  610. FILEPTR *
  611. new_fileptr()
  612. {
  613.     FILEPTR *f;
  614.  
  615.     if ((f = flist)) {
  616.         flist = f->next;
  617.         f->next = 0;
  618.         return f;
  619.     }
  620.     f = kmalloc(SIZEOF(FILEPTR));
  621.     if (!f) {
  622.         FATAL("new_fileptr: out of memory");
  623.     }
  624.     else {
  625.         f->next = 0;
  626.     }
  627.     return f;
  628. }
  629.  
  630. void
  631. dispose_fileptr(f)
  632.     FILEPTR *f;
  633. {
  634.     if (f->links != 0) {
  635.         FATAL("dispose_fileptr: f->links == %d", f->links);
  636.     }
  637.     f->next = flist;
  638.     flist = f;
  639. }
  640.  
  641. /*
  642.  * denyshare(list, f): "list" points at the first FILEPTR in a
  643.  * chained list of open FILEPTRS referring to the same file;
  644.  * f is a newly opened FILEPTR. Every FILEPTR in the given list is
  645.  * checked to see if its "open" mode (in list->flags) is compatible with
  646.  * the open mode in f->flags. If not (for example, if f was opened with
  647.  * a "read" mode and some other file has the O_DENYREAD share mode),
  648.  * then 1 is returned. If all the open FILEPTRs in the list are
  649.  * compatible with f, then 0 is returned.
  650.  * This is not as complicated as it sounds. In practice, just keep a
  651.  * list of open FILEPTRs attached to each file, and put something like
  652.  *     if (denyshare(thisfile->openfileptrlist, newfileptr))
  653.  *        return EACCDN;
  654.  * in the device open routine.
  655.  */
  656.  
  657. int
  658. denyshare(list, f)
  659.     FILEPTR *list, *f;
  660. {
  661.     int newrm, newsm;
  662.     int oldrm, oldsm;
  663.     int i;
  664.  
  665.     newrm = f->flags & O_RWMODE;
  666.     newsm = f->flags & O_SHMODE;
  667.  
  668.     for ( ; list; list = list->next) {
  669.         oldrm = list->flags & O_RWMODE;
  670.         oldsm = list->flags & O_SHMODE;
  671.         if (oldsm == O_DENYW || oldsm == O_DENYRW) {
  672.              if (newrm != O_RDONLY) {
  673.                 DEBUG("write access denied");
  674.                 return 1;
  675.             }
  676.         }
  677.         if (oldsm == O_DENYR || oldsm == O_DENYRW) {
  678.             if (newrm != O_WRONLY) {
  679.                 DEBUG("read access denied");
  680.                 return 1;
  681.             }
  682.         }
  683.         if (newsm == O_DENYW || newsm == O_DENYRW) {
  684.             if (oldrm != O_RDONLY) {
  685.                 DEBUG("couldn't deny writes");
  686.                 return 1;
  687.             }
  688.         }
  689.         if (newsm == O_DENYR || newsm == O_DENYRW) {
  690.             if (oldrm != O_WRONLY) {
  691.                 DEBUG("couldn't deny reads");
  692.                 return 1;
  693.             }
  694.         }
  695. /* If either sm == O_COMPAT, then we check to make sure
  696.    that the file pointers are owned by the same process (O_COMPAT means
  697.    "deny access to any other processes"). Also, once a file is opened
  698.    in compatibility mode, it can't be opened in any other mode.
  699.  */
  700.         if (newsm == O_COMPAT || oldsm == O_COMPAT) {
  701.             if (newsm != O_COMPAT || oldsm != O_COMPAT) {
  702.                 DEBUG("O_COMPAT mode conflict");
  703.                 return 1;
  704.             }
  705.             for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  706.                 if (curproc->handle[i] == list)
  707.                     goto found;
  708.             }
  709.         /* old file pointer is not open by this process */
  710.             DEBUG("O_COMPAT file was opened by another process");
  711.             return 1;
  712.         found:
  713.             ;    /* everything is OK */
  714.         }
  715.     }
  716.     return 0;
  717. }
  718.  
  719. /*
  720.  * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access
  721.  * specified by perm (which must be some combination of S_IROTH, S_IWOTH,
  722.  * and S_IXOTH) should be granted to the current process
  723.  * on a file with the given extended attributes. Returns 0 if access
  724.  * by the current process is OK, 1 if not.
  725.  */
  726.  
  727. int
  728. denyaccess(xattr, perm)
  729.     XATTR *xattr;
  730.     unsigned perm;
  731. {
  732.     unsigned mode;
  733.  
  734. /* the super-user can do anything! */
  735.     if (curproc->euid == 0)
  736.         return 0;
  737.  
  738.     mode = xattr->mode;
  739.     if (curproc->euid == xattr->uid)
  740.         perm = perm << 6;
  741.     else if (curproc->egid == xattr->gid)
  742.         perm = perm << 3;
  743.     if ((mode & perm) != perm) return 1;    /* access denied */
  744.     return 0;
  745. }
  746.  
  747. /*
  748.  * Checks a lock against a list of locks to see if there is a conflict.
  749.  * This is a utility to be used by file systems, somewhat like denyshare
  750.  * above. Returns 0 if there is no conflict, or a pointer to the
  751.  * conflicting LOCK structure if there is.
  752.  *
  753.  * Conflicts occur for overlapping locks if the process id's are
  754.  * different and if at least one of the locks is a write lock.
  755.  *
  756.  * NOTE: we assume before being called that the locks have been converted
  757.  * so that l_start is absolute. not relative to the current position or
  758.  * end of file.
  759.  */
  760.  
  761. LOCK *
  762. denylock(list, lck)
  763.     LOCK *list, *lck;
  764. {
  765.     LOCK *t;
  766.     unsigned long tstart, tend;
  767.     unsigned long lstart, lend;
  768.     int pid = curproc->pid;
  769.     int ltype;
  770.  
  771.     ltype = lck->l.l_type;
  772.     lstart = lck->l.l_start;
  773.  
  774.     if (lck->l.l_len == 0)
  775.         lend = 0xffffffff;
  776.     else
  777.         lend = lstart + lck->l.l_len;
  778.  
  779.     for (t = list; t; t = t->next) {
  780.         tstart = t->l.l_start;
  781.         if (t->l.l_len == 0)
  782.             tend = 0xffffffff;
  783.         else
  784.             tend = tstart + t->l.l_len;
  785.  
  786.     /* look for overlapping locks */
  787.         if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid &&
  788.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  789.             break;
  790.         if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid &&
  791.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  792.             break;
  793.     }
  794.     return t;
  795. }
  796.  
  797. /*
  798.  * check to see that a file is a directory, and that write permission
  799.  * is granted; return an error code, or 0 if everything is ok.
  800.  */
  801. long
  802. dir_access(dir, perm)
  803.     fcookie *dir;
  804.     unsigned perm;
  805. {
  806.     XATTR xattr;
  807.     long r;
  808.  
  809.     r = (*dir->fs->getxattr)(dir, &xattr);
  810.     if (r) return r;
  811.     if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  812. DEBUG("file is not a directory");
  813.         return EPTHNF;
  814.     }
  815.     if (denyaccess(&xattr, perm)) {
  816. DEBUG("no permission for directory");
  817.         return EACCDN;
  818.     }
  819.     return 0;
  820. }
  821.  
  822. /*
  823.  * returns 1 if the given name contains a wildcard character 
  824.  */
  825.  
  826. int
  827. has_wild(name)
  828.     const char *name;
  829. {
  830.     char c;
  831.  
  832.     while (c = *name++) {
  833.         if (c == '*' || c == '?') return 1;
  834.     }
  835.     return 0;
  836. }
  837.  
  838. /*
  839.  * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format
  840.  * (in dest). Note the following things:
  841.  * if a field has less than the required number of characters, it is
  842.  * padded with blanks
  843.  * a '*' means to pad the rest of the field with '?' characters
  844.  * special things to watch for:
  845.  *    "." and ".." are more or less left alone
  846.  *    "*.*" is recognized as a special pattern, for which dest is set
  847.  *    to just "*"
  848.  * Long names are truncated. Any extensions after the first one are
  849.  * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c.
  850.  */
  851.  
  852. void
  853. copy8_3(dest, src)
  854.     char *dest;
  855.     const char *src;
  856. {
  857.     char fill = ' ', c;
  858.     int i;
  859.  
  860.     if (src[0] == '.') {
  861.         if (src[1] == 0) {
  862.             strcpy(dest, ".       .   ");
  863.             return;
  864.         }
  865.         if (src[1] == '.' && src[2] == 0) {
  866.             strcpy(dest, "..      .   ");
  867.             return;
  868.         }
  869.     }
  870.     if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) {
  871.         dest[0] = '*';
  872.         dest[1] = 0;
  873.         return;
  874.     }
  875.  
  876.     for (i = 0; i < 8; i++) {
  877.         c = *src++;
  878.         if (!c || c == '.') break;
  879.         if (c == '*') {
  880.             fill = c = '?';
  881.         }
  882.         *dest++ = toupper(c);
  883.     }
  884.     while (i++ < 8) {
  885.         *dest++ = fill;
  886.     }
  887.     *dest++ = '.';
  888.     i = 0;
  889.     fill = ' ';
  890.     while (c && c != '.')
  891.         c = *src++;
  892.  
  893.     if (c) {
  894.         for( ;i < 3; i++) {
  895.             c = *src++;
  896.             if (!c || c == '.') break;
  897.             if (c == '*')
  898.                 c = fill = '?';
  899.             *dest++ = toupper(c);
  900.         }
  901.     }
  902.     while (i++ < 3)
  903.         *dest++ = fill;
  904.     *dest++ = 0;
  905. }
  906.  
  907. /*
  908.  * int pat_match(name, patrn): returns 1 if "name" matches the template in
  909.  * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3
  910.  * format by copy8_3; "name" need not be. Any '?' characters in patrn
  911.  * will match any character in name. Note that if "patrn" has a '*' as
  912.  * the first character, it will always match; this will happen only if
  913.  * the original pattern (before copy8_3 was applied) was "*.*".
  914.  *
  915.  * BUGS: acts a lot like the silly TOS pattern matcher.
  916.  */
  917.  
  918. int
  919. pat_match(name, template)
  920.     const char *name, *template;
  921. {
  922.     register char *s, c;
  923.     char expname[TOS_NAMELEN+1];
  924.  
  925.     if (*template == '*') return 1;
  926.     copy8_3(expname, name);
  927.  
  928.     s = expname;
  929.     while (c = *template++) {
  930.         if (c != *s && c != '?')
  931.             return 0;
  932.         s++;
  933.     }
  934.     return 1;
  935. }
  936.  
  937. /*
  938.  * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies
  939.  * refer to the same file or directory, 0 otherwise
  940.  */
  941.  
  942. int
  943. samefile(a, b)
  944.     fcookie *a, *b;
  945. {
  946.     if (a->fs == b->fs && a->dev == b->dev && a->index == b->index)
  947.         return 1;
  948.     return 0;
  949. }
  950.