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

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* a VERY simple tosfs.c 
  8.  * this one is extremely brain-damaged, but will serve OK for a
  9.  * skeleton in which to put a "real" tosfs.c
  10.  */
  11.  
  12. #include "mint.h"
  13.  
  14. /* if NEWWAY is defined, tosfs uses the new dup_cookie/release_cookie
  15.  * protocol to keep track of file cookies, instead of the old
  16.  * method of "timing"
  17.  */
  18. /* #define NEWWAY */
  19. #if 0
  20. #define COOKIE_DB(x) DEBUG(x)
  21. #else
  22. #define COOKIE_DB(x)
  23. #endif
  24.  
  25. /* if RO_FASCISM is defined, the read/write modes are enforced. This is
  26.  * a Good Thing, not fascist at all. Ask Allan Pratt why he chose
  27.  * that name sometime.
  28.  */
  29. #define RO_FASCISM
  30.  
  31. /* temporary code for debugging Falcon media change bug */
  32. #if 0
  33. #define MEDIA_DB(x) DEBUG(x)
  34. #else
  35. #define MEDIA_DB(x)
  36. #endif
  37.  
  38. /* search mask for anything OTHER THAN a volume label */
  39. #define FILEORDIR 0x37
  40.  
  41. char tmpbuf[PATH_MAX+1];
  42.  
  43. static long    ARGS_ON_STACK tos_root    P_((int drv, fcookie *fc));
  44. static long    ARGS_ON_STACK tos_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  45. static long    ARGS_ON_STACK tos_getxattr    P_((fcookie *fc, XATTR *xattr));
  46. static long    ARGS_ON_STACK tos_chattr    P_((fcookie *fc, int attrib));
  47. static long    ARGS_ON_STACK tos_chown    P_((fcookie *fc, int uid, int gid));
  48. static long    ARGS_ON_STACK tos_chmode    P_((fcookie *fc, unsigned mode));
  49. static long    ARGS_ON_STACK tos_mkdir    P_((fcookie *dir, const char *name, unsigned mode));
  50. static long    ARGS_ON_STACK tos_rmdir    P_((fcookie *dir, const char *name));
  51. static long    ARGS_ON_STACK tos_remove    P_((fcookie *dir, const char *name));
  52. static long    ARGS_ON_STACK tos_getname    P_((fcookie *root, fcookie *dir,
  53.                             char *pathname, int size));
  54. static long    ARGS_ON_STACK tos_rename    P_((fcookie *olddir, char *oldname,
  55.                     fcookie *newdir, const char *newname));
  56. static long    ARGS_ON_STACK tos_opendir    P_((DIR *dirh, int flags));
  57. static long    ARGS_ON_STACK tos_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  58. static long    ARGS_ON_STACK tos_rewinddir    P_((DIR *dirh));
  59. static long    ARGS_ON_STACK tos_closedir    P_((DIR *dirh));
  60. static long    ARGS_ON_STACK tos_pathconf    P_((fcookie *dir, int which));
  61. static long    ARGS_ON_STACK tos_dfree    P_((fcookie *dir, long *buf));
  62. static long    ARGS_ON_STACK tos_writelabel    P_((fcookie *dir, const char *name));
  63. static long    ARGS_ON_STACK tos_readlabel    P_((fcookie *dir, char *name, int namelen));
  64.  
  65. static long    ARGS_ON_STACK tos_creat    P_((fcookie *dir, const char *name, unsigned mode,
  66.                     int attrib, fcookie *fc));
  67. static DEVDRV *    ARGS_ON_STACK tos_getdev    P_((fcookie *fc, long *devsp));
  68. static long    ARGS_ON_STACK tos_open    P_((FILEPTR *f));
  69. static long    ARGS_ON_STACK tos_write    P_((FILEPTR *f, const char *buf, long bytes));
  70. static long    ARGS_ON_STACK tos_read    P_((FILEPTR *f, char *buf, long bytes));
  71. static long    ARGS_ON_STACK tos_lseek    P_((FILEPTR *f, long where, int whence));
  72. static long    ARGS_ON_STACK tos_ioctl    P_((FILEPTR *f, int mode, void *buf));
  73. static long    ARGS_ON_STACK tos_datime    P_((FILEPTR *f, short *time, int rwflag));
  74. static long    ARGS_ON_STACK tos_close    P_((FILEPTR *f, int pid));
  75. static long    ARGS_ON_STACK tos_dskchng    P_((int drv));
  76.  
  77. #ifdef NEWWAY
  78. static long    ARGS_ON_STACK tos_release P_((fcookie *fc));
  79. static long    ARGS_ON_STACK tos_dupcookie P_((fcookie *dst, fcookie *src));
  80. #endif
  81.  
  82. /* some routines from biosfs.c */
  83. extern long    ARGS_ON_STACK null_select    P_((FILEPTR *f, long p, int mode));
  84. extern void    ARGS_ON_STACK null_unselect    P_((FILEPTR *f, long p, int mode));
  85.  
  86. DEVDRV tos_device = {
  87.     tos_open, tos_write, tos_read, tos_lseek, tos_ioctl, tos_datime,
  88.     tos_close, null_select, null_unselect
  89. };
  90.  
  91. FILESYS tos_filesys = {
  92.     (FILESYS *)0,
  93.     FS_KNOPARSE | FS_NOXBIT | FS_LONGPATH,
  94.     tos_root,
  95.     tos_lookup, tos_creat, tos_getdev, tos_getxattr,
  96.     tos_chattr, tos_chown, tos_chmode,
  97.     tos_mkdir, tos_rmdir, tos_remove, tos_getname, tos_rename,
  98.     tos_opendir, tos_readdir, tos_rewinddir, tos_closedir,
  99.     tos_pathconf, tos_dfree, tos_writelabel, tos_readlabel,
  100.     nosymlink, noreadlink, nohardlink, nofscntl, tos_dskchng,
  101. #ifdef NEWWAY
  102.     tos_release, tos_dupcookie
  103. #else
  104.     0, 0
  105. #endif
  106. };
  107.  
  108. /* some utility functions and variables: see end of file */
  109. static DTABUF     *lastdta;    /* last DTA buffer we asked TOS about */
  110. static DTABUF    foo;
  111. static void do_setdta P_((DTABUF *dta));
  112. static int executable_extension P_((char *));
  113.  
  114. /* this array keeps track of which drives have been changed */
  115. /* a nonzero entry means that the corresponding drive has been changed,
  116.  * but GEMDOS doesn't know it yet
  117.  */
  118. static char drvchanged[NUM_DRIVES];
  119.  
  120. /* force TOS to see a media change */
  121. static void force_mediach P_((int drv));
  122. static long ARGS_ON_STACK Newgetbpb P_((int));
  123. static long ARGS_ON_STACK Newmediach P_((int));
  124. static long ARGS_ON_STACK Newrwabs P_((int, void *, int, int, int, long));
  125.  
  126. #ifdef NEWWAY
  127. #define NUM_INDICES 64
  128. #else
  129. #define NUM_INDICES 128
  130. #define MIN_AGE 8
  131. #endif
  132.  
  133. struct tindex {
  134.     char *name;        /* full path name */
  135.     FILEPTR *open;        /* fileptrs for this file; OR
  136.                  * count of number of open directories
  137.                  */
  138.     LOCK *locks;        /* locks on this file */
  139. /* file status */
  140.     long  size;
  141.     short time;
  142.     short date;
  143.     short attr;
  144.     short valid;        /* 1 if the above status is still valid */
  145. #ifdef NEWWAY
  146.     short links;        /* how many times index is in use */
  147. #else
  148.     short stamp;        /* age of this index, for garbage collection */
  149. #endif
  150. } gl_ti[NUM_INDICES];
  151.  
  152. /* temporary index for files found by readdir */
  153. static struct tindex tmpindex;
  154. static char tmpiname[PATH_MAX];
  155.  
  156. static struct tindex *tstrindex P_((char *s));
  157. static int tfullpath P_((char *result, struct tindex *base, const char *name));
  158. static struct tindex *garbage_collect P_((void));
  159.  
  160. #ifndef NEWWAY
  161. static short tclock;        /* #calls to tfullpath since last garbage
  162.                    collection */
  163. #endif
  164.  
  165. /* some extra flags for the attr field */
  166.  
  167. /*
  168.  * is a string the name of a file with executable extension?
  169.  */
  170. #define FA_EXEC 0x4000
  171. /*
  172.  * should the file be deleted when it is closed?
  173.  */
  174. #define FA_DELETE 0x2000
  175.  
  176. /*
  177.  * NOTE: call executable_extension only on a DTA name returned from
  178.  * Fsfirst(), not on an arbitrary path, for two reasons: (1) it
  179.  * expects only upper case, and (2) it looks only for the 1st extension,
  180.  * so a folder with a '.' in its name would confuse it.
  181.  */
  182.  
  183. static int
  184. executable_extension(s)
  185.     char *s;
  186. {
  187.     while (*s && *s != '.') s++;
  188.     if (!*s) return 0;
  189.     s++;
  190.     if (s[0] == 'T') {
  191.         return (s[1] == 'T' && s[2] == 'P') ||
  192.                (s[1] == 'O' && s[2] == 'S');
  193.     }
  194.     if (s[0] == 'P')
  195.         return s[1] == 'R' && s[2] == 'G';
  196.     if (s[0] == 'A')
  197.         return s[1] == 'P' && s[2] == 'P';
  198.     if (s[0] == 'G')
  199.         return s[1] == 'T' && s[2] == 'P';
  200.     return 0;
  201. }
  202.  
  203. /*
  204.  * Look in the table of tos indices to see if an index corresponding
  205.  * to this file name already exists. If so, mark it as being used
  206.  * and return it. If not, find an empty slot and make an index for
  207.  * this string. If no empty slots exist, garbage collect and
  208.  * try again.
  209.  *
  210.  * This routine is pretty dumb; we really should use a hash table
  211.  * of some sort
  212.  */
  213.  
  214. static struct tindex *tstrindex(s)
  215.     char *s;
  216. {
  217.     int i;
  218.     char *r;
  219.     struct tindex *t, *free = 0;
  220.  
  221.     assert(s != 0);
  222.     t = gl_ti;
  223.     for (i = 0; i < NUM_INDICES; i++, t++) {
  224.         if (t->name && !stricmp(t->name, s)) {
  225. #ifndef NEWWAY
  226.             t->stamp = tclock;    /* update use time */
  227. #endif
  228.             return t;
  229.         }
  230.         else if (!t->name && !free)
  231.             free = t;
  232.     }
  233.     if (!free) {
  234.         free = garbage_collect();
  235.     }
  236. #ifdef NEWWAY
  237.     if (!free) {
  238.         FORCE("tosfs: all slots in use!!");
  239.         FORCE("Links\tName");
  240.         t = gl_ti;
  241.         for (i = 0; i < NUM_INDICES; i++,t++) {
  242.             FORCE("%d\t%s", t->links, t->name);
  243.         }
  244.         FATAL("tosfs: unable to get a file name index");
  245.     }
  246. #else
  247.     if (!free) {
  248.         FATAL("tosfs: unable to get a file name index");
  249.     }
  250. #endif
  251.     r = kmalloc((long)strlen(s)+1);
  252.     if (!r) {
  253.         FATAL("tosfs: unable to allocate space for a file name");
  254.     }
  255.     strcpy(r, s);
  256.     free->name = r;
  257. #ifdef NEWWAY
  258.     free->links = 0;
  259. #else
  260.     free->stamp = tclock;
  261. #endif
  262.     free->open = 0;
  263.     free->locks = 0;
  264.  
  265. /* check to see if this file was recently returned by opendir() */
  266. #ifndef NEWWAY
  267.     if (tmpindex.valid && tclock - tmpindex.stamp < MIN_AGE &&
  268.         !stricmp(free->name, tmpindex.name)) {
  269.         free->size = tmpindex.size;
  270.         free->time = tmpindex.time;
  271.         free->date = tmpindex.date;
  272.         free->attr = tmpindex.attr;
  273.         free->valid = 1;
  274.         tmpindex.valid = 0;
  275.     } else
  276. #endif
  277.         free->valid = 0;
  278.     return free;
  279. }
  280.  
  281. /*
  282.  * garbage collection routine: for any TOS index older than MIN_AGE,
  283.  * check through all current processes to see if it's in use. If
  284.  * not, free the corresponding string.
  285.  * Returns: a pointer to a newly freed index, or NULL.
  286.  */
  287.  
  288. /* it's unlikely that the kernel would need to hold onto a file cookie
  289.    for longer than this many calls to tstrindex() without first
  290.    saving the cookie in a directory or file pointer
  291.  */
  292.  
  293. static struct tindex *
  294. garbage_collect()
  295. {
  296.     struct tindex *free, *t;
  297.     int i;
  298. #ifndef NEWWAY
  299.     fcookie *fc, *gc;
  300.     PROC *p;
  301.     int j;
  302.     int age;
  303. #endif
  304.  
  305.     free = 0;
  306.     t = gl_ti;
  307.     for (i = 0; i < NUM_INDICES; i++,t++) {
  308.         if (!t->name) continue;
  309. #ifdef NEWWAY
  310.         if (t->links == 0) {
  311.             kfree(t->name);
  312.             t->name = 0;
  313.             if (!free) free = t;
  314.         }
  315. #else
  316.         age = tclock - t->stamp;
  317.         t->stamp = 0;
  318.         assert(age >= 0);
  319.         if (age > MIN_AGE) {
  320.         /* see if any process is using this index */
  321.             if (t->open)
  322.                 goto found_index;
  323.             for (p = proclist; p; p = p->gl_next) {
  324.                 fc = p->curdir;
  325.                 gc = p->root;
  326.                 for (j = 0; j < NUM_DRIVES; j++,fc++,gc++) {
  327.                     if (( fc->fs == &tos_filesys &&
  328.                           fc->index == (long)t ) ||
  329.                         ( gc->fs == &tos_filesys &&
  330.                           gc->index == (long)t ) )
  331.                         goto found_index;
  332.                 }
  333.             }
  334.         /* here, we couldn't find the index in use by any proc. */
  335.             kfree(t->name);
  336.             t->name = 0;
  337.             if (!free)
  338.                 free = t;
  339.         found_index:
  340.             ;
  341.         } else {
  342.     /* make sure that future garbage collections might look at this file */
  343.             t->stamp = -age;
  344.         }
  345. #endif
  346.     }
  347.  
  348. #ifndef NEWWAY
  349.     tclock = 0;    /* reset the clock */
  350.     tmpindex.valid = 0; /* expire the temporary Fsfirst buffer */
  351. #endif
  352.     return free;
  353. }
  354.  
  355. #define DIRSEP(c) ((c) == '\\')
  356.  
  357. static int
  358. tfullpath(result, basei, path)
  359.     char *result;
  360.     struct tindex *basei;
  361.     const char *path;
  362. {
  363. #define TNMTEMP 32
  364.     char *n, name[TNMTEMP+1];
  365.     int namelen, pathlen;
  366.     char *base = basei->name;
  367.     int r = 0;
  368.  
  369. #ifndef NEWWAY
  370.     basei->stamp = ++tclock;
  371.     if (tclock > 10000) {
  372.     /* garbage collect every so often whether we need it or not */
  373.         (void)garbage_collect();
  374.     }
  375. #endif
  376.     if (!*path) {
  377.         strncpy(result, base, PATH_MAX-1);
  378.         return r;
  379.     }
  380.  
  381.     strncpy(result, base, PATH_MAX-1);
  382.  
  383.     pathlen = strlen(result);
  384.  
  385. /* now path is relative to what's currently in "result" */
  386.  
  387.     while(*path) {
  388. /* get next name in path */
  389.         n = name; namelen = 0;
  390.         while (*path && !DIRSEP(*path)) {
  391. /* BUG: we really should to the translation to DOS 8.3
  392.  * format *here*, so that really long names are truncated
  393.  * correctly.
  394.  */
  395.             if (namelen < TNMTEMP) {
  396.                 *n++ = toupper(*path); path++; namelen++;
  397.             }
  398.             else
  399.                 path++;
  400.         }
  401.         *n = 0;
  402.         while (DIRSEP(*path)) path++;
  403. /* check for "." and ".." */
  404.         if (!strcmp(name, ".")) continue;
  405.         if (!strcmp(name, "..")) {
  406.             n = strrchr(result, '\\');
  407.             if (n) {
  408.                 *n = 0;
  409.                 pathlen = (int)(n - result);
  410.             }
  411.             else r = EMOUNT;
  412.             continue;
  413.         }
  414.         if (pathlen + namelen < PATH_MAX - 1) {
  415.             strcat(result, "\\");
  416.             pathlen++;
  417.  
  418.     /* make sure the name is restricted to DOS 8.3 format */
  419.             for (base = result; *base; base++)
  420.                 ;
  421.             n = name;
  422.             namelen = 0;
  423.             while (*n && *n != '.' && namelen++ < 8) {
  424.                 *base++ = *n++;
  425.                 pathlen++;
  426.             }
  427.             while (*n && *n != '.') n++;
  428.             if (*n == '.' && *(n+1) != 0) {
  429.                 *base++ = *n++;
  430.                 pathlen++;
  431.                 namelen = 0;
  432.                 while (*n && namelen++ < 3) {
  433.                     *base++ = *n++;
  434.                     pathlen++;
  435.                 }
  436.             }
  437.             *base = 0;
  438.         }
  439.     }
  440.     return r;
  441. }
  442.  
  443. static long ARGS_ON_STACK 
  444. tos_root(drv, fc)
  445.     int drv;
  446.     fcookie *fc;
  447. {
  448.     struct tindex *ti;
  449.  
  450.     ksprintf(tmpbuf, "%c:", drv+'A');
  451.     fc->fs = &tos_filesys;
  452.     fc->dev = drv;
  453.     ti = tstrindex(tmpbuf);
  454.     ti->size = ti->date = ti->time = 0;
  455.     ti->attr = FA_DIR;
  456.     ti->valid = 1;
  457.     fc->index = (long)ti;
  458.  
  459. /* if the drive has changed, make sure GEMDOS knows it! */
  460.     if (drvchanged[drv]) {
  461.         force_mediach(drv);
  462.     }
  463. #ifdef NEWWAY
  464.     ti->links++;
  465. #endif
  466.     return 0;
  467. }
  468.  
  469. static long ARGS_ON_STACK 
  470. tos_lookup(dir, name, fc)
  471.     fcookie *dir;
  472.     const char *name;
  473.     fcookie *fc;
  474. {
  475.     long r;
  476.     struct tindex *ti = (struct tindex *)dir->index;
  477.  
  478.     r = tfullpath(tmpbuf, ti, name);
  479.  
  480. /* if the name is empty or otherwise trivial, just return the directory */
  481.     if (!strcmp(ti->name, tmpbuf)) {
  482.         *fc = *dir;
  483. #ifdef NEWWAY
  484.         ti->links++;
  485.         COOKIE_DB(("tos_lookup: %s now has %d links", ti->name, ti->links));
  486. #endif 
  487.         return r;
  488.     }
  489.  
  490. /* is there already an index for this file?? If so, is it up to date?? */
  491.     ti = tstrindex(tmpbuf);
  492.     if (!ti->valid) {
  493.         if (tmpbuf[1] == ':' && tmpbuf[2] == 0) {
  494.             /* a root directory -- lookup always succeeds */
  495.             foo.dta_size = 0;
  496.             foo.dta_date = foo.dta_time = 0;
  497.             foo.dta_attrib = FA_DIR;
  498.             foo.dta_name[0] = 0;
  499.         } else {
  500.             do_setdta(&foo);
  501.             r = Fsfirst(tmpbuf, FILEORDIR);
  502.             if (r) {
  503. DEBUG(("tos_lookup: Fsfirst(%s) returned %ld", tmpbuf, r));
  504.                 return r;
  505.             }
  506.         }
  507.         ti->size = foo.dta_size;
  508.         ti->date = foo.dta_date;
  509.         ti->time = foo.dta_time;
  510.         ti->attr = foo.dta_attrib;
  511.         if (executable_extension(foo.dta_name))
  512.             ti->attr |= FA_EXEC;
  513.         ti->valid = 1;
  514.     }
  515.     fc->fs = &tos_filesys;
  516.     fc->index = (long)ti;
  517.     fc->dev = dir->dev;
  518. #ifdef NEWWAY
  519.     ti->links++;
  520.     COOKIE_DB(("tos_lookup: %s now has %d links", ti->name, ti->links));
  521. #endif
  522.     return r;
  523. }
  524.  
  525. static long ARGS_ON_STACK 
  526. tos_getxattr(fc, xattr)
  527.     fcookie *fc;
  528.     XATTR *xattr;
  529. {
  530.     struct tindex *ti = (struct tindex *)fc->index;
  531.     long r;
  532.     static long junkindex = 0;
  533.  
  534.     xattr->index = junkindex++;
  535.     xattr->dev = fc->dev;
  536.     xattr->nlink = 1;
  537.     xattr->uid = xattr->gid = 0;
  538.  
  539. #ifndef NEWWAY
  540.     ti->stamp = ++tclock;
  541. #endif
  542.  
  543.     if (!ti->valid) {
  544.         do_setdta(&foo);
  545.         if (ti->name[2] == 0) {        /* a root directory */
  546. /* actually, this can also happen if a program tries to open a file
  547.  * with an empty name... so we should fail gracefully
  548.  */
  549.             ti->attr = FA_DIR;
  550.             ti->size = 0;
  551.             ti->date = ti->time = 0;
  552.             goto around;
  553.         }
  554.     
  555.         r = Fsfirst(ti->name, FILEORDIR);
  556.         if (r) {
  557.             DEBUG(("tosfs: search error %ld on [%s]", r, ti->name));
  558.             return r;
  559.         }
  560.         ti->size = foo.dta_size;
  561.         ti->date = foo.dta_date;
  562.         ti->time = foo.dta_time;
  563.         ti->attr = foo.dta_attrib;
  564.         if (executable_extension(foo.dta_name))
  565.             ti->attr |= FA_EXEC;
  566. around:
  567.         ti->valid = 1;
  568.     }
  569.     xattr->size = ti->size;
  570.  
  571. /* BUG: blksize isn't accurate if the sector size is not 512 */
  572.     xattr->blksize = 1024;
  573.     xattr->nblocks = (xattr->size + 1023) / 1024;
  574.     xattr->mdate = xattr->cdate = xattr->adate = ti->date;
  575.     xattr->mtime = xattr->ctime = xattr->atime = ti->time;
  576.     xattr->mode = (ti->attr & FA_DIR) ? (S_IFDIR | DEFAULT_DIRMODE) :
  577.              (S_IFREG | DEFAULT_MODE);
  578.  
  579.     if (ti->attr & FA_RDONLY) {
  580.         xattr->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  581.     }
  582.  
  583.     if (ti->attr & FA_EXEC) {
  584.         xattr->mode |= (S_IXUSR|S_IXGRP|S_IXOTH);
  585.     }
  586.     xattr->attr = ti->attr & 0xff;
  587.     return 0;
  588. }
  589.  
  590. static long ARGS_ON_STACK
  591. tos_chattr(fc, attrib)
  592.     fcookie *fc;
  593.     int attrib;
  594. {
  595.     struct tindex *ti = (struct tindex *)fc->index;
  596.  
  597.     if (ti->attr & FA_DIR) {
  598.         DEBUG(("error: attempt to change attributes of a directory"));
  599.         return EACCDN;
  600.     }
  601.     ti->valid = 0;
  602.     (void)tfullpath(tmpbuf, ti, "");
  603.     return Fattrib(tmpbuf, 1, attrib);
  604. }
  605.  
  606. static long ARGS_ON_STACK 
  607. tos_chown(dir, uid, gid)
  608.     fcookie *dir;
  609.     int uid, gid;
  610. {
  611.     UNUSED(dir); UNUSED(uid); UNUSED(gid);
  612.     return EINVFN;
  613. }
  614.  
  615. static long ARGS_ON_STACK 
  616. tos_chmode(fc, mode)
  617.     fcookie *fc;
  618.     unsigned mode;
  619. {
  620.     int oldattr, newattr;
  621.     long r;
  622.     struct tindex *ti = (struct tindex *)fc->index;
  623.  
  624.     oldattr = Fattrib(ti->name, 0, 0);
  625.     if (oldattr < 0)
  626.         return oldattr;
  627.  
  628.     ti->valid = 0;
  629.  
  630.     if (!(mode & S_IWUSR))
  631.         newattr = oldattr | FA_RDONLY;
  632.     else
  633.         newattr = oldattr & ~FA_RDONLY;
  634.     if (newattr != oldattr)
  635.         r = Fattrib(ti->name, 1, newattr);
  636.     else
  637.         r = 0;
  638.     return (r < 0) ? r : 0;
  639. }
  640.  
  641. static long ARGS_ON_STACK 
  642. tos_mkdir(dir, name, mode)
  643.     fcookie *dir;
  644.     const char *name;
  645.     unsigned mode;        /* ignored under TOS */
  646. {
  647.     UNUSED(mode);
  648.  
  649.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  650.     tmpindex.valid = 0;
  651.  
  652.     return Dcreate(tmpbuf);
  653. }
  654.  
  655. static long ARGS_ON_STACK 
  656. tos_rmdir(dir, name)
  657.     fcookie *dir;
  658.     const char *name;
  659. {
  660.     struct tindex *ti;
  661.  
  662.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  663.     ti = tstrindex(tmpbuf);
  664.     ti->valid = 0;
  665.  
  666.     return Ddelete(tmpbuf);
  667. }
  668.  
  669. static long ARGS_ON_STACK 
  670. tos_remove(dir, name)
  671.     fcookie *dir;
  672.     const char *name;
  673. {
  674.     struct tindex *ti;
  675.  
  676.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  677.  
  678.     ti = tstrindex(tmpbuf);
  679.     if (ti->open) {
  680.         DEBUG(("tos_remove: file is open, will be deleted later"));
  681.         if (ti->attr & FA_RDONLY)
  682.             return EACCDN;
  683.         ti->attr |= FA_DELETE;
  684.         return 0;
  685.     }
  686.     ti->valid = 0;
  687.     return Fdelete(tmpbuf);
  688. }
  689.  
  690. static long ARGS_ON_STACK 
  691. tos_getname(root, dir, pathname, size)
  692.     fcookie *root, *dir;
  693.     char *pathname;
  694.     int size;
  695. {
  696.     char *rootnam = ((struct tindex *)root->index)->name;
  697.     char *dirnam = ((struct tindex *)dir->index)->name;
  698.     int i;
  699.  
  700.     i = strlen(rootnam);
  701.     if (strlen(dirnam) < i) {
  702.         DEBUG(("tos_getname: root is longer than path"));
  703.         return EINTRN;
  704.     }
  705.     if (strlen(dirnam+i) < size) {
  706.         strcpy(pathname, dirnam + i);
  707. /*
  708.  * BUG: must be a better way to decide upper/lower case
  709.  */
  710.         if (curproc->domain == DOM_MINT)
  711.             strlwr(pathname);
  712.         return 0;
  713.     } else {
  714.         DEBUG(("tosfs: name too long"));
  715.         return ERANGE;
  716.     }
  717. }
  718.  
  719. static long ARGS_ON_STACK 
  720. tos_rename(olddir, oldname, newdir, newname)
  721.     fcookie *olddir;
  722.     char *oldname;
  723.     fcookie *newdir;
  724.     const char *newname;
  725. {
  726.     char newbuf[128];
  727.     struct tindex *ti;
  728.     long r;
  729.  
  730.     (void)tfullpath(tmpbuf, (struct tindex *)olddir->index, oldname);
  731.     (void)tfullpath(newbuf, (struct tindex *)newdir->index, newname);
  732.     r = Frename(0, tmpbuf, newbuf);
  733.     if (r == 0) {
  734.         ti = tstrindex(tmpbuf);
  735.         kfree(ti->name);
  736.         ti->name = kmalloc((long)strlen(newbuf)+1);
  737.         if (!ti->name) {
  738.             FATAL("tosfs: unable to allocate space for a name");
  739.         }
  740.         strcpy(ti->name, newbuf);
  741.         ti->valid = 0;
  742.     }
  743.     return r;
  744. }
  745.  
  746. #define DIR_FLAG(x)    (x->fsstuff[0])
  747. #define STARTSEARCH    0    /* opendir() was just called */
  748. #define INSEARCH    1    /* readdir() has been called at least once */
  749. #define NMFILE        2    /* no more files to read */
  750.  
  751. #define DIR_DTA(x)    ((DTABUF *)(x->fsstuff + 2))
  752. #define DIR_NAME(x)    (x->fsstuff + 32)
  753.  
  754. /*
  755.  * The directory functions are a bit tricky. What we do is have
  756.  * opendir() do Fsfirst; the first readdir() picks up this name,
  757.  * subsequent readdir()'s have to do Fsnext
  758.  */
  759.  
  760. static long ARGS_ON_STACK 
  761. tos_opendir(dirh, flags)
  762.     DIR *dirh;
  763.     int flags;
  764. {
  765.     long r;
  766.     struct tindex *t = (struct tindex *)dirh->fc.index;
  767.  
  768.     UNUSED(flags);
  769.  
  770.     (void)tfullpath(tmpbuf, t, "*.*");
  771.  
  772.     do_setdta(DIR_DTA(dirh));
  773.  
  774.     r = Fsfirst(tmpbuf, FILEORDIR);
  775.  
  776.     if (r == 0) {
  777.         t->open++;
  778.         DIR_FLAG(dirh) = STARTSEARCH;
  779.         return 0;
  780.     } else if (r == EFILNF) {
  781.         t->open++;
  782.         DIR_FLAG(dirh) = NMFILE;
  783.         return 0;
  784.     }
  785.      return r;
  786. }
  787.  
  788. static long ARGS_ON_STACK 
  789. tos_readdir(dirh, name, namelen, fc)
  790.     DIR *dirh;
  791.     char *name;
  792.     int namelen;
  793.     fcookie *fc;
  794. {
  795.     static long index = 0;
  796.     long ret;
  797.     int giveindex = dirh->flags == 0;
  798.     struct tindex *ti;
  799.     DTABUF *dta = DIR_DTA(dirh);
  800.  
  801. again:
  802.     if (DIR_FLAG(dirh) == NMFILE)
  803.         return ENMFIL;
  804.  
  805.     if (DIR_FLAG(dirh) == STARTSEARCH) {
  806.         DIR_FLAG(dirh) = INSEARCH;
  807.     } else {
  808.         assert(DIR_FLAG(dirh) == INSEARCH);
  809.         do_setdta(dta);
  810.         ret = Fsnext();
  811.         if (ret) {
  812.             DIR_FLAG(dirh) = NMFILE;
  813.             return ret;
  814.         }
  815.     }
  816.  
  817. /* don't return volume labels from readdir */
  818.     if (dta->dta_attrib == FA_LABEL) goto again;
  819.  
  820.     fc->fs = &tos_filesys;
  821.     fc->dev = dirh->fc.dev;
  822.  
  823.     (void)tfullpath(tmpiname, (struct tindex *)dirh->fc.index, DIR_NAME(dirh));
  824.  
  825.     ti = &tmpindex;
  826.     ti->name = tmpiname;
  827.     ti->valid = 1;
  828.     ti->size = dta->dta_size;
  829.     ti->date = dta->dta_date;
  830.     ti->time = dta->dta_time;
  831.     ti->attr = dta->dta_attrib;
  832. #ifndef NEWWAY
  833.     ti->stamp = tclock;
  834. #endif
  835.     if (executable_extension(dta->dta_name))
  836.         ti->attr |= FA_EXEC;
  837.     fc->index = (long)ti;
  838.  
  839.     if (giveindex) {
  840.         namelen -= (int) sizeof(long);
  841.         if (namelen <= 0) return ERANGE;
  842.         *((long *)name) = index++;
  843.         name += sizeof(long);
  844.     }
  845.     strncpy(name, DIR_NAME(dirh), namelen-1);
  846.     name[namelen-1] = 0;
  847.  
  848. /* BUG: we really should do the "strlwr" operation only
  849.  * for Dreaddir (i.e. if giveindex == 0) but
  850.  * unfortunately some old programs rely on the behaviour
  851.  * below
  852.  */
  853.     if (curproc->domain == DOM_MINT) {
  854.         strlwr(name);
  855.     }
  856.     if (strlen(DIR_NAME(dirh)) >= namelen)
  857.         return ENAMETOOLONG;
  858. #ifdef NEWWAY
  859.     ti->links++;
  860.     COOKIE_DB(("tos_readdir: %s now has %d links", ti->name, ti->links));
  861. #endif
  862.     return 0;
  863. }
  864.  
  865. static long ARGS_ON_STACK 
  866. tos_rewinddir(dirh)
  867.     DIR *dirh;
  868. {
  869.     struct tindex *ti = (struct tindex *)dirh->fc.index;
  870.     long r;
  871.  
  872.     (void)tfullpath(tmpbuf, ti, "*.*");
  873.     do_setdta(DIR_DTA(dirh));
  874.     r = Fsfirst(tmpbuf, FILEORDIR);
  875.     if (r == 0) {
  876.         DIR_FLAG(dirh) = STARTSEARCH;
  877.     } else {
  878.         DIR_FLAG(dirh) = NMFILE;
  879.     }
  880.     return r;
  881. }
  882.  
  883. static long ARGS_ON_STACK 
  884. tos_closedir(dirh)
  885.     DIR *dirh;
  886. {
  887.     struct tindex *t = (struct tindex *)dirh->fc.index;
  888.  
  889.     if (t->open == 0) {
  890.         FATAL("t->open == 0: directory == %s", t->name);
  891.     }
  892.     --t->open;
  893.     DIR_FLAG(dirh) = NMFILE;
  894.     return 0;
  895. }
  896.  
  897. static long ARGS_ON_STACK 
  898. tos_pathconf(dir, which)
  899.     fcookie *dir;
  900.     int which;
  901. {
  902.     UNUSED(dir);
  903.  
  904.     switch(which) {
  905.     case -1:
  906.         return DP_MAXREQ;
  907.     case DP_IOPEN:
  908.         return 60;    /* we can only keep about this many open */
  909.     case DP_MAXLINKS:
  910.          return 1;    /* no hard links */
  911.     case DP_PATHMAX:
  912.         return PATH_MAX;
  913.     case DP_NAMEMAX:
  914.         return 8+3+1;
  915.     case DP_ATOMIC:
  916.         return 512;    /* we can write at least a sector atomically */
  917.     case DP_TRUNC:
  918.         return DP_DOSTRUNC;    /* DOS style file names */
  919.     case DP_CASE:
  920.         return DP_CASECONV;    /* names converted to upper case */
  921.     default:
  922.         return EINVFN;
  923.     }
  924. }
  925.  
  926. long ARGS_ON_STACK 
  927. tos_dfree(dir, buf)
  928.     fcookie *dir;
  929.     long *buf;
  930. {
  931.     return Dfree(buf, (dir->dev)+1);
  932. }
  933.  
  934. /*
  935.  * writelabel: creates a volume label
  936.  * readlabel: reads a volume label
  937.  * both of these are only guaranteed to work in the root directory
  938.  */
  939.  
  940. /*
  941.  * BUG: this should first delete any old labels, so that it will
  942.  * work with TOS <1.4
  943.  */
  944.  
  945. long ARGS_ON_STACK 
  946. tos_writelabel(dir, name)
  947.     fcookie *dir;
  948.     const char *name;
  949. {
  950.     long r;
  951.     struct tindex *ti;
  952.  
  953.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  954.     r = Fcreate(tmpbuf, FA_LABEL);
  955.     if (r < 0) return r;
  956.     (void)Fclose((int)r);
  957.     ti = tstrindex(tmpbuf);
  958.     ti->valid = 0;
  959.     return 0;
  960. }
  961.  
  962. long ARGS_ON_STACK 
  963. tos_readlabel(dir, name, namelen)
  964.     fcookie *dir;
  965.     char *name;
  966.     int namelen;
  967. {
  968.     long r;
  969.     struct tindex *ti = (struct tindex *)dir->index;
  970.  
  971.     if (ti->name[2] != 0)        /* not a root directory? */
  972.         return EFILNF;
  973.  
  974.     (void)tfullpath(tmpbuf, ti, "*.*");
  975.     do_setdta(&foo);
  976.     r = Fsfirst(tmpbuf, FA_LABEL);
  977.     if (r)
  978.         return r;
  979.     strncpy(name, foo.dta_name, namelen-1);
  980.     return (strlen(foo.dta_name) < namelen) ? 0 : ENAMETOOLONG;
  981. }
  982.  
  983. /*
  984.  * TOS creat: this doesn't actually create the file, rather it
  985.  * sets up a (fake) index for the file that will be used by
  986.  * the later tos_open call.
  987.  */
  988.  
  989. static long ARGS_ON_STACK 
  990. tos_creat(dir, name, mode, attrib, fc)
  991.     fcookie *dir;
  992.     const char *name;
  993.     unsigned mode;
  994.     int attrib;
  995.     fcookie *fc;
  996. {
  997.     struct tindex *ti;
  998.     UNUSED(mode);
  999.  
  1000.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  1001.  
  1002.     ti = tstrindex(tmpbuf);
  1003.     ti->size = 0;
  1004.     ti->date = datestamp;
  1005.     ti->time = timestamp;
  1006.     ti->attr = attrib;
  1007.     ti->valid = 1;
  1008.  
  1009.     fc->fs = &tos_filesys;
  1010.     fc->index = (long)ti;
  1011.     fc->dev = dir->dev;
  1012. #ifdef NEWWAY
  1013.     ti->links++;
  1014.     COOKIE_DB(("tos_creat: %s now has %d links", ti->name, ti->links));
  1015. #endif
  1016.     return 0;
  1017. }
  1018.     
  1019. /*
  1020.  * TOS device driver
  1021.  */
  1022.  
  1023. static DEVDRV * ARGS_ON_STACK 
  1024. tos_getdev(fc, devsp)
  1025.     fcookie *fc;
  1026.     long *devsp;
  1027. {
  1028.     UNUSED(fc); UNUSED(devsp);
  1029.     return &tos_device;
  1030. }
  1031.  
  1032. static long ARGS_ON_STACK 
  1033. tos_open(f)
  1034.     FILEPTR *f;
  1035. {
  1036.     struct tindex *ti;
  1037.     int mode = f->flags;
  1038.     int tosmode;
  1039.     long r;
  1040.     extern int flk;        /* in main.c, set if _FLK cookie already present */
  1041.  
  1042.     ti = (struct tindex *)(f->fc.index);
  1043.     assert(ti != 0);
  1044.  
  1045. #ifndef NEWWAY
  1046.     ti->stamp = ++tclock;
  1047. #endif
  1048.     ti->valid = 0;
  1049.  
  1050. #ifndef RO_FASCISM
  1051. /* TEMPORARY HACK: change all modes to O_RDWR for files opened in
  1052.  * compatibility sharing mode. This is silly, but
  1053.  * allows broken TOS programs that write to read-only handles to continue
  1054.  * to work (it also helps file sharing, by making the realistic assumption
  1055.  * that any open TOS file can be written to). Eventually,
  1056.  * this should be tuneable by the user somehow.
  1057.  * ALSO: change O_COMPAT opens into O_DENYNONE; again, this may be temporary.
  1058.  */
  1059.     if ( (mode & O_SHMODE) == O_COMPAT ) {
  1060.         f->flags = (mode & ~(O_RWMODE|O_SHMODE)) | O_RDWR | O_DENYNONE;
  1061.     }
  1062. #endif
  1063.  
  1064. /* check to see that nobody has opened this file already in an
  1065.  * incompatible mode
  1066.  */
  1067.     if (denyshare(ti->open, f)) {
  1068.         TRACE(("tos_open: file sharing denied"));
  1069.         return EACCDN;
  1070.     }
  1071.  
  1072. /*
  1073.  * now open the file; if O_TRUNC was specified, actually
  1074.  * create the file anew.
  1075.  * BUG: O_TRUNC without O_CREAT doesn't work right. The kernel doesn't
  1076.  * use this mode, anyways
  1077.  */
  1078.  
  1079.     if (mode & O_TRUNC) {
  1080.         if (ti->open) {
  1081.             DEBUG(("tos_open: attempt to truncate an open file"));
  1082.             return EACCDN;
  1083.         }
  1084.         r = Fcreate(ti->name, ti->attr);
  1085.     } else {
  1086.         if (flk)
  1087.             tosmode = mode & (O_RWMODE|O_SHMODE);
  1088.         else
  1089.             tosmode = (mode & O_RWMODE);
  1090.         if (tosmode == O_EXEC) tosmode = O_RDONLY;
  1091.  
  1092.         r = Fopen(ti->name, tosmode );
  1093.         if (r == EFILNF && (mode & O_CREAT))
  1094.             r = Fcreate(ti->name, ti->attr);
  1095.     }
  1096.  
  1097.     if (r < 0) {
  1098. /* get rid of the index for the file, since it doesn't exist */
  1099.         kfree(ti->name);
  1100.         ti->name = 0;
  1101.         ti->valid = 0;
  1102.         return r;
  1103.     }
  1104.  
  1105.     f->devinfo = r;
  1106.  
  1107.     f->next = ti->open;
  1108.     ti->open = f;
  1109.     return 0;
  1110. }
  1111.  
  1112. static long ARGS_ON_STACK 
  1113. tos_write(f, buf, bytes)
  1114.     FILEPTR *f; const char *buf; long bytes;
  1115. {
  1116.     struct tindex *ti = (struct tindex *)f->fc.index;
  1117.  
  1118.     ti->valid = 0;
  1119.     return Fwrite((int)f->devinfo, bytes, buf);
  1120. }
  1121.  
  1122. static long ARGS_ON_STACK 
  1123. tos_read(f, buf, bytes)
  1124.     FILEPTR *f; char *buf; long bytes;
  1125. {
  1126.     return Fread((int)f->devinfo, bytes, buf);
  1127. }
  1128.  
  1129. static long ARGS_ON_STACK 
  1130. tos_lseek(f, where, whence)
  1131.     FILEPTR *f; long where; int whence;
  1132. {
  1133.     long r;
  1134.  
  1135.     r = Fseek(where, (int)f->devinfo, whence);
  1136.     return r;
  1137. }
  1138.  
  1139. static long ARGS_ON_STACK 
  1140. tos_ioctl(f, mode, buf)
  1141.     FILEPTR *f; int mode; void *buf;
  1142. {
  1143.     LOCK t, *lck, **old;
  1144.     struct flock *fl;
  1145.     long r;
  1146.     struct tindex *ti;
  1147.     extern int flk;        /* set in main.c if _FLK already installed */
  1148.  
  1149.     if (mode == FIONREAD || mode == FIONWRITE) {
  1150.         *((long *)buf) = 1;
  1151.         return 0;
  1152.     }
  1153.     else if (mode == F_SETLK || mode == F_SETLKW || mode == F_GETLK) {
  1154.         fl = ((struct flock *)buf);
  1155.         t.l = *fl;
  1156.         switch(t.l.l_whence) {
  1157.         case 0:
  1158.             break;
  1159.         case 1:        /* SEEK_CUR */
  1160.             r = Fseek(0L, (int)f->devinfo, 1);
  1161.             t.l.l_start += r;
  1162.             break;
  1163.         case 2:
  1164.             r = Fseek(0L, (int)f->devinfo, 1);
  1165.             t.l.l_start = Fseek(t.l.l_start, (int)f->devinfo, 2);
  1166.             (void)Fseek(r, (int)f->devinfo, 0);
  1167.             break;
  1168.         default:
  1169.             DEBUG(("Invalid value for l_whence"));
  1170.             return EINVFN;
  1171.         }
  1172. /* BUG: can't lock a file starting at >2gigabytes from the beginning */
  1173.         if (t.l.l_start < 0) t.l.l_start = 0;
  1174.         t.l.l_whence = 0;
  1175.         ti = (struct tindex *)f->fc.index;
  1176.  
  1177.         if (mode == F_GETLK) {
  1178.             lck = denylock(ti->locks, &t);
  1179.             if (lck)
  1180.                 *fl = lck->l;
  1181.             else
  1182.                 fl->l_type = F_UNLCK;
  1183.             return 0;
  1184.         }
  1185.  
  1186.         if (t.l.l_type == F_UNLCK) {
  1187.         /* try to find the lock */
  1188.             old = &ti->locks;
  1189.             lck = *old;
  1190.             while (lck) {
  1191.                 if (lck->l.l_pid == curproc->pid &&
  1192.                     lck->l.l_start == t.l.l_start &&
  1193.                     lck->l.l_len == t.l.l_len) {
  1194.         /* found it -- remove the lock */
  1195.                     *old = lck->next;
  1196.                     TRACE(("tosfs: unlocked %s: %ld + %ld",
  1197.                         ti->name, t.l.l_start, t.l.l_len));
  1198.                     if (flk)
  1199.                         (void)Flock((int)f->devinfo, 1,
  1200.                             t.l.l_start, t.l.l_len);
  1201.                 /* wake up anyone waiting on the lock */
  1202.                     wake(IO_Q, (long)lck);
  1203.                     kfree(lck);
  1204.                     break;
  1205.                 }
  1206.                 old = &lck->next;
  1207.                 lck = lck->next;
  1208.             }
  1209.             return lck ?  0 : ENSLOCK;
  1210.         }
  1211.         TRACE(("tosfs: lock %s: %ld + %ld", ti->name,
  1212.             t.l.l_start, t.l.l_len));
  1213.         do {
  1214.         /* see if there's a conflicting lock */
  1215.             while ((lck = denylock(ti->locks, &t)) != 0) {
  1216.                 DEBUG(("tosfs: lock conflicts with one held by %d",
  1217.                     lck->l.l_pid));
  1218.                 if (mode == F_SETLKW) {
  1219.                     sleep(IO_Q, (long)lck);        /* sleep a while */
  1220.                 }
  1221.                 else
  1222.                     return ELOCKED;
  1223.             }
  1224.         /* if not, add this lock to the list */
  1225.             lck = kmalloc(SIZEOF(LOCK));
  1226.             if (!lck) return ENSMEM;
  1227.         /* see if other _FLK code might object */
  1228.             if (flk) {
  1229.                 r = Flock((int)f->devinfo, 0, t.l.l_start, t.l.l_len);
  1230.                 if (r) {
  1231.                     kfree(lck);
  1232.                     if (mode == F_SETLKW && r == ELOCKED) {
  1233.                         yield();
  1234.                         lck = NULL;
  1235.                     }
  1236.                     else
  1237.                         return r;
  1238.                 }
  1239.             }
  1240.         } while (!lck);
  1241.         lck->l = t.l;
  1242.         lck->l.l_pid = curproc->pid;
  1243.         lck->next = ti->locks;
  1244.         ti->locks = lck;
  1245.     /* mark the file as being locked */
  1246.         f->flags |= O_LOCK;
  1247.         return 0;
  1248.     }
  1249.     return EINVFN;
  1250. }
  1251.  
  1252. static long ARGS_ON_STACK 
  1253. tos_datime(f, timeptr, rwflag)
  1254.     FILEPTR *f;
  1255.     short *timeptr;
  1256.     int rwflag;
  1257. {
  1258.     if (rwflag) {
  1259.         struct tindex *ti = (struct tindex *)f->fc.index;
  1260.         ti->valid = 0;
  1261.     }
  1262.     return Fdatime(timeptr, (int)f->devinfo, rwflag);
  1263. }
  1264.  
  1265. static long ARGS_ON_STACK 
  1266. tos_close(f, pid)
  1267.     FILEPTR *f;
  1268.     int pid;
  1269. {
  1270.     LOCK *lck, **oldl;
  1271.     struct tindex *t;
  1272.     FILEPTR **old, *p;
  1273.     long r = 0;
  1274.     extern int flk;        /* set in main.c */
  1275.  
  1276.     t = (struct tindex *)(f->fc.index);
  1277. /* if this handle was locked, remove any locks held by the process
  1278.  */
  1279.     if (f->flags & O_LOCK) {
  1280.         TRACE(("tos_close: releasing locks (file mode: %x)", f->flags));
  1281.         oldl = &t->locks;
  1282.         lck = *oldl;
  1283.         while (lck) {
  1284.             if (lck->l.l_pid == pid) {
  1285.                 *oldl = lck->next;
  1286.                 if (flk)
  1287.                     (void)Flock((int)f->devinfo, 1,
  1288.                         lck->l.l_start, lck->l.l_len);
  1289.                 wake(IO_Q, (long)lck);
  1290.                 kfree(lck);
  1291.             } else {
  1292.                 oldl = &lck->next;
  1293.             }
  1294.             lck = *oldl;
  1295.         }
  1296.     }
  1297.  
  1298.     if (f->links <= 0) {
  1299. /* remove f from the list of open file pointers on this index */
  1300.         t->valid = 0;
  1301.         old = &t->open;
  1302.         p = t->open;
  1303.         while (p && p != f) {
  1304.             old = &p->next;
  1305.             p = p->next;
  1306.         }
  1307.         assert(p);
  1308.         *old = f->next;
  1309.         f->next = 0;
  1310.         r = Fclose((int)f->devinfo);
  1311.  
  1312. /* if the file was marked for deletion, delete it */
  1313.         if (!t->open) {
  1314.             if (t->attr & FA_DELETE) {
  1315.                 (void)Fdelete(t->name);
  1316.                 t->name = 0;
  1317.             }
  1318.         }
  1319.     }
  1320.     return r;
  1321. }
  1322.  
  1323. /*
  1324.  * check for disk change: called by the kernel if Mediach returns a
  1325.  * non-zero value
  1326.  */
  1327.  
  1328. long ARGS_ON_STACK 
  1329. tos_dskchng(drv)
  1330.     int drv;
  1331. {
  1332.     char dlet;
  1333.     int i;
  1334.     struct tindex *ti;
  1335.     FILEPTR *f, *nextf;
  1336.  
  1337.     dlet = 'A' + drv;
  1338. MEDIA_DB(("tos_dskchng(%c)", dlet));
  1339.     ti = gl_ti;
  1340.     for (i = 0; i < NUM_INDICES; i++, ti++) {
  1341.         if (ti->name && ti->name[0] == dlet) {
  1342.             kfree(ti->name);
  1343.             ti->name = 0;
  1344.             nextf = ti->open;
  1345.             while ( (f = nextf) != 0 ) {
  1346.                 nextf = f->next;
  1347.                 f->next = 0;
  1348.             }
  1349.             ti->open = 0;
  1350.     /* if there are any cookies pointing at this name, they're not
  1351.      * valid any more, so we will *want* to get an error if they're
  1352.      * used.
  1353.      */
  1354.         }
  1355.     }
  1356.     tmpindex.valid = 0;
  1357. /*
  1358.  * OK, make sure that GEMDOS knows to look for a change if we
  1359.  * ever use this drive again.
  1360.  */
  1361.     drvchanged[drv] = 1;
  1362.     return 1;
  1363. }
  1364.  
  1365. #ifdef NEWWAY
  1366. /* release/copy file cookies; these functions exist to keep
  1367.  * track of whether or not the kernel is still using a file
  1368.  */
  1369. long
  1370. tos_release(fc)
  1371.     fcookie *fc;
  1372. {
  1373.     struct tindex *ti = (struct tindex *)fc->index;
  1374.  
  1375.     if (ti->links <= 0) {
  1376.         FATAL("tos_release: link count of `%s' is %d", ti->name, ti->links);
  1377.     }
  1378.     ti->links--;
  1379.     COOKIE_DB(("tos_release: %s now has %d links", ti->name, ti->links));
  1380.     return 0;
  1381. }
  1382.  
  1383. long
  1384. tos_dupcookie(dest, src)
  1385.     fcookie *dest, *src;
  1386. {
  1387.     struct tindex *ti = (struct tindex *)src->index;
  1388.  
  1389.     if (ti->links <= 0) {
  1390.         FATAL("tos_dupcookie: link count of %s is %d", ti->name, ti->links);
  1391.     }
  1392.     ti->links++;
  1393.     COOKIE_DB(("tos_dupcookie: %s now has %d links", ti->name, ti->links));
  1394.     *dest = *src;
  1395.     return 0;
  1396. }
  1397. #endif
  1398.  
  1399. /*
  1400.  * utility function: sets the TOS DTA, and also records what directory
  1401.  * this was in. This is just to save us a call into the kernel if the
  1402.  * correct DTA has already been set.
  1403.  */
  1404.  
  1405. static void
  1406. do_setdta(dta)
  1407.     DTABUF *dta;
  1408. {
  1409.     if (dta != lastdta) {
  1410.         Fsetdta(dta);
  1411.         lastdta = dta;
  1412.     }
  1413. }
  1414.  
  1415. /*
  1416.  * routines for forcing a media change on drive "drv"
  1417.  */
  1418.  
  1419. static int chdrv;
  1420.  
  1421. /* new Getbpb function: when this is called, all the other
  1422.  * vectors can be un-installed
  1423.  */
  1424.  
  1425. static long ARGS_ON_STACK (*Oldgetbpb) P_((int));
  1426. static long ARGS_ON_STACK (*Oldmediach) P_((int));
  1427. static long ARGS_ON_STACK (*Oldrwabs) P_((int, void *, int, int, int, long));
  1428.  
  1429. static long  ARGS_ON_STACK
  1430. Newgetbpb(d)
  1431.     int d;
  1432. {
  1433.     if (d == chdrv) {
  1434. MEDIA_DB(("Newgetbpb(%c)", d+'A'));
  1435. if (Oldgetbpb == Newgetbpb) {
  1436. MEDIA_DB(("AARGH!!! BAD BPBs"));
  1437. }
  1438.         *((Func *)0x472L) = Oldgetbpb;
  1439.         *((Func *)0x476L) = Oldrwabs;
  1440.         *((Func *)0x47eL) = Oldmediach;
  1441.     }
  1442.     return (*Oldgetbpb)(d);
  1443. }
  1444.  
  1445. static long ARGS_ON_STACK
  1446. Newmediach(d)
  1447.     int d;
  1448. {
  1449.     if (d == chdrv) {
  1450. MEDIA_DB(("Newmediach(%c)", d+'A'));
  1451.         return 2;
  1452.     }
  1453.     return (*Oldmediach)(d);
  1454. }
  1455.  
  1456. static long ARGS_ON_STACK
  1457. Newrwabs(d, buf, a, b, c, l)
  1458.     int d;
  1459.     void *buf;
  1460.     int a, b, c;
  1461.     long l;
  1462. {
  1463.     if (d == chdrv) {
  1464. MEDIA_DB(("Newrwabs"));
  1465.         return E_CHNG;
  1466.     }
  1467.     return (*Oldrwabs)(d, buf, a, b, c, l);
  1468. }
  1469.  
  1470. static void
  1471. force_mediach(d)
  1472.     int d;
  1473. {
  1474. #ifdef FSFIRST_MEDIACH
  1475.     static char fname[] = "X:\\*.*";
  1476. #else
  1477.     long r;
  1478.     static char fname[] = "X:\\X";
  1479. #endif
  1480.     TRACE(("tosfs: disk change drive %c", d+'A'));
  1481. MEDIA_DB(("forcing media change on %c", d+'A'));
  1482.  
  1483.     chdrv = d;
  1484.     Oldrwabs = *((Func *)0x476L);
  1485.     Oldgetbpb = *((Func *)0x472L);
  1486.     Oldmediach = *((Func *)0x47eL);
  1487.  
  1488.     if (Oldrwabs == Newrwabs || Oldgetbpb == Newgetbpb ||
  1489.         Oldmediach == Newmediach) {
  1490.         FORCE("tosfs: error in media change code");
  1491.     } else {
  1492.         *((Func *)0x476L) = Newrwabs;
  1493.         *((Func *)0x472L) = Newgetbpb;
  1494.         *((Func *)0x47eL) = Newmediach;
  1495.     }
  1496.  
  1497.     fname[0] = d + 'A';
  1498. MEDIA_DB(("calling GEMDOS"));
  1499. #ifdef FSFIRST_MEDIACH
  1500.     (void)Fsfirst(fname, 8);
  1501. #else    
  1502.     r = Fopen(fname, 0);
  1503.     if (r >= 0) Fclose((int)r);
  1504. #endif
  1505. MEDIA_DB(("done calling GEMDOS"));
  1506.     drvchanged[d] = 0;
  1507.     if ( *((Func *)0x476L) == Newrwabs ) {
  1508.         DEBUG(("WARNING: media change not performed correctly"));
  1509.         *((Func *)0x472L) = Oldgetbpb;
  1510.         *((Func *)0x476L) = Oldrwabs;
  1511.         *((Func *)0x47eL) = Oldmediach;
  1512.     }
  1513. }
  1514.