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

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