home *** CD-ROM | disk | FTP | other *** search
/ Vectronix 2 / VECTRONIX2.iso / FILES_01 / MIDICOM.LZH / MC_UTILS / MC_XFS / MCXFS.C < prev    next >
C/C++ Source or Header  |  1993-10-05  |  42KB  |  1,828 lines

  1. #define NEWWAY
  2. #include <string.h>
  3. #include <ctype.h>
  4.  
  5. #include "atarierr.h"
  6. #include "osbind.h"
  7.  
  8. #define DTABUF DTA
  9. #define NUM_DRIVES 1
  10. #include "filesys.h"
  11. #include "mcxfs.h"
  12.  
  13. typedef long cdecl (*Func)();
  14.  
  15. #define NULL (void *)0L
  16. #define UNUSED(x) (void)x
  17. #define READY_Q    1
  18. #define IO_Q    3
  19. #define F_SETLKW    7
  20.  
  21. /* search mask for anything OTHER THAN a volume label */
  22. #define FILEORDIR 0x37
  23. int MCDRIVE =13;
  24.  
  25. static char tmpbuf[PATH_MAX+1];
  26. int flk = 0;
  27.  
  28. static long    cdecl mc_root        (int drv, fcookie *fc);
  29. static long    cdecl mc_lookup        (fcookie *dir, const char *name, fcookie *fc);
  30. static long    cdecl mc_getxattr    (fcookie *fc, XATTR *xattr);
  31. static long    cdecl mc_chattr        (fcookie *fc, int attrib);
  32. static long    cdecl mc_chown        (fcookie *fc, int uid, int gid);
  33. static long    cdecl mc_chmode        (fcookie *fc, unsigned mode);
  34. static long    cdecl mc_mkdir        (fcookie *dir, const char *name, unsigned mode);
  35. static long    cdecl mc_rmdir        (fcookie *dir, const char *name);
  36. static long    cdecl mc_remove        (fcookie *dir, const char *name);
  37. static long    cdecl mc_getname    (fcookie *root, fcookie *dir,char *pathname,int size);
  38. static long    cdecl mc_rename        (fcookie *olddir, char *oldname,fcookie *newdir, const char *newname);
  39. static long    cdecl mc_opendir    (DIR *dirh, int flags);
  40. static long    cdecl mc_readdir    (DIR *dirh, char *nm, int nmlen, fcookie *);
  41. static long    cdecl mc_rewinddir    (DIR *dirh);
  42. static long    cdecl mc_closedir    (DIR *dirh);
  43. static long    cdecl mc_pathconf    (fcookie *dir, int which);
  44. static long    cdecl mc_dfree        (fcookie *dir, long *buf);
  45. static long    cdecl mc_writelabel    (fcookie *dir, const char *name);
  46. static long    cdecl mc_readlabel    (fcookie *dir, char *name, int namelen);
  47. static long cdecl nodskchng(int drv);
  48. static long cdecl nofscntl(fcookie *dir,const char *name,int cmd,long arg);
  49. static long cdecl nosymlink(fcookie *dir,const char *name,const char *to);
  50. static long cdecl noreadlink(fcookie *dir,char *buf,int buflen);
  51. static long cdecl nohardlink(fcookie *fromdir,fcookie *todir,const char *fromname,    const char *toname);
  52. static long    cdecl mc_release    (fcookie *fc);
  53. static long    cdecl mc_dupcookie(fcookie *dest,fcookie *src);
  54.  
  55. long     cdecl     mc_creat        (fcookie *dir,const char *name, unsigned mode,int attrib, fcookie *fc);
  56. DEVDRV * cdecl    mc_getdev        (fcookie *fc, long *devsp);
  57. long    cdecl     mc_open            (FILEPTR *f);
  58. long    cdecl     mc_read            (FILEPTR *f, char *buf, long bytes);
  59. long    cdecl     mc_lseek        (FILEPTR *f, long where, int whence);
  60. long    cdecl     mc_write        (FILEPTR *f, const char *buf, long bytes);
  61. long    cdecl     mc_ioctl        (FILEPTR *f, int mode, void *buf);
  62. long    cdecl     mc_datime         (FILEPTR *f, int *time, int rwflag);
  63. long    cdecl     mc_close        (FILEPTR *f, int pid);
  64. /*long    cdecl     mc_dskchng        (int drv);*/
  65.  
  66. /* some routines from biosfs.c */
  67. long    cdecl null_select    (FILEPTR *f, long p, int mode);
  68. void    cdecl null_unselect    (FILEPTR *f, long p, int mode);
  69.  
  70. DEVDRV mc_device = {
  71.     mc_open,mc_write,mc_read,mc_lseek,mc_ioctl,
  72.     mc_datime,mc_close,null_select, null_unselect};
  73.  
  74. FILESYS mc_filesys = {
  75.     (FILESYS *)0,FS_NOXBIT | FS_KNOPARSE,
  76.     mc_root,mc_lookup,mc_creat,mc_getdev,mc_getxattr,mc_chattr, 
  77.     mc_chown,mc_chmode,mc_mkdir,mc_rmdir,mc_remove,mc_getname, 
  78.     mc_rename,mc_opendir,mc_readdir,mc_rewinddir,mc_closedir,
  79.     mc_pathconf,mc_dfree,mc_writelabel,mc_readlabel,
  80.     nosymlink,noreadlink,nohardlink,nofscntl,nodskchng,
  81. #ifdef NEWWAY
  82.     mc_release,
  83.     mc_dupcookie
  84. #else    
  85.     0,0
  86. #endif
  87. };
  88.  
  89. struct kerinfo *kernel;
  90.  
  91. #define CCONWS         (void)(*kernel->dos_tab[0x09])
  92. #define Timestamp()     (*kernel->dos_tab[0x2c])
  93. #define Datestamp()     (*kernel->dos_tab[0x2a])
  94. #define Domain()     (*kernel->dos_tab[0x119])(-1)
  95. #define Getpid()         (*kernel->dos_tab[0x10b])
  96. #define Getuid()         (*kernel->dos_tab[0x10f])
  97. #define Getgid()         (*kernel->dos_tab[0x114])
  98.  
  99. #define Nap            (*kernel->nap)
  100. #define Sleep        (*kernel->sleep)
  101. #define Yield()     Sleep(READY_Q, 0L)
  102. #define Wake        (*kernel->wake)
  103.  
  104. #define DEBUG         (*kernel->debug)
  105. #define ALERT         (*kernel->alert)
  106. #define TRACE         (*kernel->trace)
  107. #define FATAL         (*kernel->fatal)
  108. #define Kmalloc     (*kernel->kmalloc)
  109. #define Kfree         (*kernel->kfree)
  110. #define Stricmp     (*kernel->stricmp)
  111. #define Sprintf     (*kernel->sprintf)
  112. #define Strlwr      (*kernel->strlwr)
  113. #define Unixtime     (*kernel->unixtim)
  114. #define Dostime     (*kernel->dostim)
  115. #define Denyshare     (*kernel->denyshare)
  116. #define Denylock     (*kernel->denylock)
  117. #define Changedrive (*kernel->drvchng)
  118.  
  119. static long install_cookies(void);
  120.  
  121. /*
  122.  * this must be the first function; it is called by the kernel when the
  123.  * file system is being loaded, and should return the file system
  124.  * structure
  125.  */
  126.  
  127. FILESYS * cdecl mc_init(struct kerinfo *k)
  128. {
  129.     kernel = k;
  130.     Cconws("MiNT Filesystem\r\n");
  131.     Cconws(" für MIDI_COM\r\n");
  132.     instmedia();
  133.     Cconws("Drive N: only\r\n");
  134.     (void)install_cookies();
  135.     return (&mc_filesys);
  136. }
  137. /* some utility functions and variables: see end of file */
  138. static DTABUF     *lastdta;    /* last DTA buffer we asked TOS about */
  139. static DTABUF    foo;
  140. static void do_setdta (DTABUF *dta);
  141. static int executable_extension (char *);
  142.  
  143. /* this array keeps track of which drives have been changed */
  144. /* a nonzero entry means that the corresponding drive has been changed,
  145.  * but GEMDOS doesn't know it yet
  146.  */
  147.  
  148. #ifdef NEWWAY
  149. #define NUM_INDICES 64
  150. #else
  151. #define NUM_INDICES 128
  152. #define MIN_AGE 8
  153. #endif
  154.  
  155. struct tindex {
  156.     char *name;        /* full path name */
  157.     FILEPTR *open;        /* fileptrs for this file; OR
  158.                  * count of number of open directories
  159.                  */
  160.     LOCK *locks;        /* locks on this file */
  161. /* file status */
  162.     long  size;
  163.     int time;
  164.     int date;
  165.     int attr;
  166.     int valid;        /* 1 if the above status is still valid */
  167. #ifdef NEWWAY
  168.     int links;        /* how many times index is in use */
  169. #else
  170.     int stamp;        /* age of this index, for garbage collection */
  171. #endif
  172. }gl_ti[NUM_INDICES];
  173.  
  174. /* temporary index for files found by readdir */
  175. static struct tindex tmpindex;
  176. static char tmpiname[PATH_MAX];
  177.  
  178. static struct tindex *tstrindex (char *s);
  179. static int tfullpath (char *result, struct tindex *base, const char *name);
  180. static struct tindex *garbage_collect(void);
  181. static para * getmc_cookie(void);
  182.  
  183. #ifndef NEWWAY
  184. static int tclock;        /* #calls to tfullpath since last garbage
  185.                    collection */
  186. #endif
  187. /* some extra flags for the attr field */
  188.  
  189. /*
  190.  * is a string the name of a file with executable extension?
  191.  */
  192. #define FA_EXEC 0x4000
  193. /*
  194.  * should the file be deleted when it is closed?
  195.  */
  196. #define FA_DELETE 0x2000
  197.  
  198. /*
  199.  * NOTE: call executable_extension only on a DTA name returned from
  200.  * Fsfirst(), not on an arbitrary path, for two reasons: (1) it
  201.  * expects only upper case, and (2) it looks only for the 1st extension,
  202.  * so a folder with a '.' in its name would confuse it.
  203.  */
  204.  
  205. static int executable_extension(char *s)
  206. {
  207.     while (*s && *s != '.') s++;
  208.     if (!*s) return 0;
  209.     s++;
  210.     if (s[0] == 'T') {
  211.         return ((s[1] == 'T' && s[2] == 'P') ||
  212.                (s[1] == 'O' && s[2] == 'S'));
  213.     }
  214.     if (s[0] == 'P')
  215.         return (s[1] == 'R' && s[2] == 'G');
  216.     if (s[0] == 'A')
  217.         return (s[1] == 'P' && s[2] == 'P');
  218.     if (s[0] == 'G')
  219.         return (s[1] == 'T' && s[2] == 'P');
  220.     return 0;
  221. }
  222.  
  223. /*
  224.  * Look in the table of tos indices to see if an index corresponding
  225.  * to this file name already exists. If so, mark it as being used
  226.  * and return it. If not, find an empty slot and make an index for
  227.  * this string. If no empty slots exist, garbage collect and
  228.  * try again.
  229.  *
  230.  * This routine is pretty dumb; we really should use a hash table
  231.  * of some sort
  232.  */
  233.  
  234. static struct tindex *tstrindex(char *s)
  235. {
  236.     int i;
  237.     char *r;
  238.     struct tindex *t, *free = NULL;
  239.  
  240.     t = gl_ti;
  241.     for (i = 0; i < NUM_INDICES; i++, t++) {
  242.         if (t->name && !stricmp(t->name, s)) {
  243. #ifndef NEWWAY
  244.             t->stamp = tclock;    /* update use time */
  245. #endif
  246.             return t;
  247.         }
  248.         else if (!t->name && !free)
  249.             free = t;
  250.     }
  251.     if (!free) {
  252.         free = garbage_collect();
  253.     }
  254. #ifdef NEWWAY
  255.     if (!free) {
  256.         t = gl_ti;
  257.         FATAL("tosfs: unable to get a file name index");
  258.     }
  259. #else
  260.     if (!free) {
  261.         FATAL("tosfs: unable to get a file name index");
  262.     }
  263. #endif
  264.     r = Kmalloc((long)strlen(s)+1);
  265.     if (!r) {
  266.         FATAL("MCfs: unable to allocate space for a file name");
  267.     }
  268.     strcpy(r, s);
  269.     free->name = r;
  270. #ifdef NEWWAY
  271.     free->links = 0;
  272.  
  273. #else
  274.     free->stamp = tclock;
  275. #endif
  276.     free->open = 0;
  277.     free->locks = 0;
  278.  
  279. /* check to see if this file was recently returned by opendir() */
  280. #ifndef NEWWAY
  281.     if (tmpindex.valid && tclock - tmpindex.stamp < MIN_AGE &&
  282.         !stricmp(free->name, tmpindex.name)) {
  283.         free->size = tmpindex.size;
  284.         free->time = tmpindex.time;
  285.         free->date = tmpindex.date;
  286.         free->attr = tmpindex.attr;
  287.         free->valid = 1;
  288.         tmpindex.valid = 0;
  289.     } else
  290. #endif
  291.     free->valid = 0;
  292.     return free;
  293. }
  294.  
  295. /*
  296.  * garbage collection routine: for any TOS index older than MIN_AGE,
  297.  * check through all current processes to see if it's in use. If
  298.  * not, free the corresponding string.
  299.  * Returns: a pointer to a newly freed index, or NULL.
  300.  */
  301.  
  302. /* it's unlikely that the kernel would need to hold onto a file cookie
  303.    for longer than this many calls to tstrindex() without first
  304.    saving the cookie in a directory or file pointer
  305.  */
  306.  
  307. static struct tindex * garbage_collect()
  308. {
  309.     struct tindex *free, *t;
  310.     int i;
  311. #ifndef NEWWAY
  312.     fcookie *fc, *gc;
  313.     PROC *p;
  314.     int j;
  315.     int age;
  316. #endif
  317.  
  318.     free = 0;
  319.     t = gl_ti;
  320.     for (i = 0; i < NUM_INDICES; i++,t++) {
  321.         if (!t->name) continue;
  322. #ifdef NEWWAY
  323.         if (t->links == 0) {
  324.             Kfree(t->name);
  325.             t->name = 0;
  326.             if (!free) free = t;
  327.         }
  328. #else
  329.         age = tclock - t->stamp;
  330.         t->stamp = 0;
  331.         if (age > MIN_AGE) {
  332.         /* see if any process is using this index */
  333.             if (t->open)
  334.                 goto found_index;
  335.             for (p = proclist; p; p = p->gl_next) {
  336.                 fc = p->curdir;
  337.                 gc = p->root;
  338.                 for (j = 0; j < NUM_DRIVES; j++,fc++,gc++) {
  339.                     if (( fc->fs == &mc_filesys &&
  340.                           fc->index == (long)t ) ||
  341.                         ( gc->fs == &mc_filesys &&
  342.                           gc->index == (long)t ) )
  343.                         goto found_index;
  344.                 }
  345.             }
  346.         /* here, we couldn't find the index in use by any proc. */
  347.             Kfree(t->name);
  348.             t->name = 0;
  349.             if (!free)
  350.                 free = t;
  351.         found_index:
  352.             ;
  353.         } else {
  354.     /* make sure that future garbage collections might look at this file */
  355.             t->stamp = -age;
  356.         }
  357. #endif
  358.     }
  359.  
  360. #ifndef NEWWAY
  361.     tclock = 0;    /* reset the clock */
  362.     tmpindex.valid = 0; /* expire the temporary Fsfirst buffer */
  363. #endif
  364.     return free;
  365. }
  366.  
  367. #define DIRSEP(c) ((c) == '\\')
  368.  
  369. static int tfullpath(char *result,struct tindex *basei,    const char *path)
  370. {
  371. #define TNMTEMP 32
  372. static char name[TNMTEMP+1];
  373.     char *n; 
  374.     int namelen, pathlen;
  375.     char *base = basei->name;
  376.     int r;
  377.  
  378. #ifndef NEWWAY
  379.     basei->stamp = ++tclock;
  380.     if (tclock > 10000) {
  381.     /* garbage collect every so often whether we need it or not */
  382.         (void)garbage_collect();
  383.     }
  384. #endif
  385.     r=0;
  386.     if (!*path) {
  387.         strncpy(result, base, PATH_MAX-1);
  388.         return r;
  389.     }
  390.  
  391.     strncpy(result, base, PATH_MAX-1);
  392.     pathlen = (int) strlen(result);
  393.  
  394. /* now path is relative to what's currently in "result" */
  395.  
  396.     while(*path) {
  397. /* get next name in path */
  398.         n = name; namelen = 0;
  399.         while (*path && !DIRSEP(*path)) {
  400. /* BUG: we really should to the translation to DOS 8.3
  401.  * format *here*, so that really long names are truncated
  402.  * correctly.
  403.  */
  404.             if (namelen < TNMTEMP) {
  405.                 *n++ = toupper(*path); path++; namelen++;
  406.             }
  407.             else
  408.                 path++;
  409.         }
  410.         *n = 0;
  411.         while (DIRSEP(*path)) path++;
  412. /* check for "." and ".." */
  413.         if (!strcmp(name, ".")) continue;
  414.         if (!strcmp(name, "..")) {
  415.             n = strrchr(result, '\\');
  416.             if (n) {
  417.                 *n = 0;
  418.                 pathlen = (int)(n - result);
  419.             }
  420.             else r = EMOUNT;
  421.             continue;
  422.         }
  423.         if (pathlen + namelen < PATH_MAX - 1) {
  424.             strcat(result, "\\");
  425.             pathlen++;
  426.  
  427.     /* make sure the name is restricted to DOS 8.3 format */
  428.             for (base = result; *base; base++)
  429.                 ;
  430.             n = name;
  431.             namelen = 0;
  432.             while (*n && *n != '.' && namelen++ < 8) {
  433.                 *base++ = *n++;
  434.                 pathlen++;
  435.             }
  436.             while (*n && *n != '.') n++;
  437.             if (*n == '.' && *(n+1) != 0) {
  438.                 *base++ = *n++;
  439.                 pathlen++;
  440.                 namelen = 0;
  441.                 while (*n && namelen++ < 3) {
  442.                     *base++ = *n++;
  443.                     pathlen++;
  444.                 }
  445.             }
  446.             *base = 0;
  447.         }
  448.     }
  449.     return r;
  450. }
  451.  
  452. static long cdecl mc_root(int drv,fcookie *fc)
  453. {
  454.     struct tindex *ti;
  455.     DEBUG(" mc_root");
  456.         if (drv==MCDRIVE)
  457.         {
  458.              Sprintf(tmpbuf, "%c:", drv+'A');
  459.             fc->fs = &mc_filesys;
  460.             fc->dev = drv;
  461.             ti = tstrindex(tmpbuf);
  462.             ti->size = ti->date = ti->time = 0;
  463.             ti->attr = FA_DIR;
  464.             ti->valid = 1;
  465.             fc->index = (long)ti;
  466. #ifdef NEWWAY
  467.             ti->links++;
  468. #endif
  469.             return (0);
  470.         }
  471.     return(EDRIVE);
  472. }
  473.  
  474. long MC_Fsfirst(char *filename, int attr,DTABUF *dta );
  475. long MC_Fsnext(DTABUF *dta);
  476. long MC_Fopen(char *name,int tosmode );
  477. long MC_Fread( int handle, long count, void *buf );
  478. long MC_Fcreate(char *name,int tosmode );
  479. long MC_Fclose(int handle);
  480. long MC_Dcreate(char *path );
  481. long MC_Ddelete(char *path );
  482. long MC_Dfree(long *buf, int driveno);
  483. long MC_Fseek( long offset, int handle, int seekmode );
  484. long MC_Fattrib(char *filename, int wflag, int attrib );
  485. long MC_Fdelete(char *filename );
  486. long MC_Frename( int zero,char *oldname,char *newname );
  487. long MC_Fwrite( int handle, long count, void *buf );
  488. long MC_Fdatime( int *timeptr, int handle, int wflag );
  489.  
  490.  
  491. static long cdecl mc_lookup(fcookie *dir,const char *name,fcookie *fc)
  492. {
  493.     long r;
  494.     struct tindex *ti = (struct tindex *)dir->index;
  495.     DEBUG(" mc_lookup(dir=%s name=%s",ti->name,name);
  496.     r = tfullpath(tmpbuf, ti, name);
  497. /* if the name is empty or otherwise trivial, just return the directory */
  498.     if (!strcmp(ti->name, tmpbuf)) {
  499.         *fc = *dir;
  500. #ifdef NEWWAY
  501.         ti->links++;
  502. #endif 
  503.         return r;
  504.     }
  505.  
  506. /* is there already an index for this file?? If so, is it up to date?? */
  507.     ti = tstrindex(tmpbuf);
  508.  
  509.     if (!ti->valid) {
  510.         if (tmpbuf[1] == ':' && tmpbuf[2] == 0) {
  511.             /* a root directory -- lookup always succeeds */
  512.             foo.d_length = 0;
  513.             foo.d_date = foo.d_time = 0;
  514.             foo.d_attrib = FA_DIR;
  515.             foo.d_fname[0] = 0;
  516.         } else {
  517.             do_setdta(&foo);
  518.             r = MC_Fsfirst(tmpbuf, FILEORDIR,&foo);
  519.             if (r) {
  520.                 return (r);
  521.             }
  522.         }
  523.         ti->size = foo.d_length;
  524.         ti->date = foo.d_date;
  525.         ti->time = foo.d_time;
  526.         ti->attr = foo.d_attrib;
  527.         if (executable_extension(foo.d_fname))
  528.             ti->attr |= FA_EXEC;
  529.         ti->valid = 1;
  530.     }
  531.     fc->fs = &mc_filesys;
  532.     fc->index = (long)ti;
  533.     fc->dev = dir->dev;
  534. #ifdef NEWWAY
  535.     ti->links++;
  536.     DEBUG(" mc_lookup neu: %s links=%d",ti->name,ti->links);
  537. #endif
  538.     return r;
  539. }
  540.  
  541. static long cdecl mc_getxattr(fcookie *fc,XATTR *xattr)
  542. {
  543.     struct tindex *ti = (struct tindex *)fc->index;
  544.     long r;
  545.     static long junkindex = 0;
  546.  
  547.     DEBUG(" mc_getxattr %s links=%d",ti->name,ti->links);
  548.     xattr->index = junkindex++;
  549.     xattr->dev = fc->dev;
  550.     xattr->nlink = 1;
  551.     xattr->uid = xattr->gid = 0;
  552.  
  553. #ifndef NEWWAY
  554.     ti->stamp = ++tclock;
  555. #endif
  556.  
  557.     if (!ti->valid) {
  558.         do_setdta(&foo);
  559.         if (ti->name[2] == 0) {        /* a root directory */
  560. /* actually, this can also happen if a program tries to open a file
  561.  * with an empty name... so we should fail gracefully
  562.  */
  563.             ti->attr = FA_DIR;
  564.             ti->size = 0;
  565.             ti->date = ti->time = 0;
  566.             goto around;
  567.         }
  568.     
  569.         r = MC_Fsfirst(ti->name, FILEORDIR,&foo);
  570.         if (r) {
  571.             return r;
  572.         }
  573.         ti->size = foo.d_length;
  574.         ti->date = foo.d_date;
  575.         ti->time = foo.d_time;
  576.         ti->attr = foo.d_attrib;
  577.         if (executable_extension(foo.d_fname))
  578.             ti->attr |= FA_EXEC;
  579. around:
  580.         ti->valid = 1;
  581.     }
  582.     xattr->size = ti->size;
  583.  
  584. /* BUG: blksize isn't accurate if the sector size is not 512 */
  585.     xattr->blksize = 1024;
  586.     xattr->nblocks = (xattr->size + 1023) / 1024;
  587.     xattr->mdate = xattr->cdate = xattr->adate = ti->date;
  588.     xattr->mtime = xattr->ctime = xattr->atime = ti->time;
  589.     xattr->mode = (ti->attr & FA_DIR) ? (S_IFDIR | DEFAULT_DIRMODE) :
  590.              (S_IFREG | DEFAULT_MODE);
  591.  
  592.     if (ti->attr & FA_RDONLY) {
  593.         xattr->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  594.     }
  595.  
  596.     if (ti->attr & FA_EXEC) {
  597.         xattr->mode |= (S_IXUSR|S_IXGRP|S_IXOTH);
  598.     }
  599.     xattr->attr = ti->attr & 0xff;
  600.     return 0;
  601. }
  602.  
  603. static long cdecl mc_chattr(fcookie *fc,int attrib)
  604. {
  605.     struct tindex *ti = (struct tindex *)fc->index;
  606.  
  607.  
  608.     DEBUG(" mc_chattr");
  609.     if (ti->attr & FA_DIR) {
  610.         DEBUG("error: attempt to change attributes of a directory");
  611.         return EACCDN;
  612.     }
  613.     ti->valid = 0;
  614.     (void)tfullpath(tmpbuf, ti, "");
  615.     return MC_Fattrib(tmpbuf, 1, attrib);
  616. }
  617.  
  618. static long cdecl 
  619. mc_chown(dir, uid, gid)
  620.     fcookie *dir;
  621.     int uid, gid;
  622. {
  623.     UNUSED(dir); UNUSED(uid); UNUSED(gid);
  624.     DEBUG(" mc_chown returns %ld",EINVFN);
  625.     return EINVFN;
  626. }
  627.  
  628. static long cdecl mc_chmode(fcookie *fc,unsigned mode)
  629. {
  630.     int oldattr, newattr;
  631.     long r;
  632.     struct tindex *ti = (struct tindex *)fc->index;
  633.  
  634.     DEBUG(" mc_chmode");
  635.     oldattr =(int) MC_Fattrib(ti->name, 0, 0);
  636.     if (oldattr < 0)
  637.         return oldattr;
  638.  
  639.     ti->valid = 0;
  640.  
  641.     if (!(mode & S_IWUSR))
  642.         newattr = oldattr | FA_RDONLY;
  643.     else
  644.         newattr = oldattr & ~FA_RDONLY;
  645.     if (newattr != oldattr)
  646.         r = MC_Fattrib(ti->name, 1, newattr);
  647.     else
  648.         r = 0;
  649.     return (r < 0) ? r : 0;
  650. }
  651.  
  652. static long cdecl mc_mkdir(fcookie *dir,const char *name,unsigned mode)
  653. /*     ignored under TOS */
  654. {
  655.     UNUSED(mode);
  656.  
  657.     DEBUG(" mc_mkdir");
  658.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  659.     tmpindex.valid = 0;
  660.  
  661.     return MC_Dcreate(tmpbuf);
  662. }
  663.  
  664. static long cdecl mc_rmdir(fcookie *dir,const char *name)
  665. {
  666.     struct tindex *ti;
  667.  
  668.     DEBUG(" mc_rmdir");
  669.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  670.     ti = tstrindex(tmpbuf);
  671.     ti->valid = 0;
  672.  
  673.     return MC_Ddelete(tmpbuf);
  674. }
  675.  
  676. static long cdecl mc_remove(fcookie *dir,const char *name)
  677. {
  678.     struct tindex *ti;
  679.  
  680.     DEBUG(" mc_remove");
  681.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  682.  
  683.     ti = tstrindex(tmpbuf);
  684.     if (ti->open) {
  685.         DEBUG("mc_remove: file is open, will be deleted later");
  686.         if (ti->attr & FA_RDONLY)
  687.             return EACCDN;
  688.         ti->attr |= FA_DELETE;
  689.         return 0;
  690.     }
  691.     ti->valid = 0;
  692.     return MC_Fdelete(tmpbuf);
  693. }
  694.  
  695. static long cdecl
  696. mc_getname(fcookie *root,fcookie *dir,char *pathname,int size)
  697. {
  698.     char *rootnam = ((struct tindex *)root->index)->name;
  699.     char *dirnam = ((struct tindex *)dir->index)->name;
  700.     int i;
  701.  
  702.     DEBUG(" mc_getname");
  703.     i = (int) strlen(rootnam);
  704.     if (strlen(dirnam) < i) {
  705.         return (EINTRN);
  706.     }
  707.     if (strlen(dirnam+i) < size) {
  708.         strcpy(pathname, dirnam + i);
  709.         return(0);
  710.     }
  711.     return(ERANGE);
  712.     
  713.  
  714. }
  715.  
  716. static long cdecl mc_rename(fcookie *olddir,char *oldname,fcookie *newdir,const char *newname)
  717. {
  718. static    char newbuf[128];
  719.     struct tindex *ti;
  720.     long r;
  721.  
  722.     DEBUG(" mc_rename");
  723.     (void)tfullpath(tmpbuf, (struct tindex *)olddir->index, oldname);
  724.     (void)tfullpath(newbuf, (struct tindex *)newdir->index, newname);
  725.     r = MC_Frename(0, tmpbuf, newbuf);
  726.     if (r == 0) {
  727.         ti = tstrindex(tmpbuf);
  728.         Kfree(ti->name);
  729.         ti->name = Kmalloc((long)strlen(newbuf)+1);
  730.         if (!ti->name) {
  731.             FATAL("tosfs: unable to allocate space for a name");
  732.         }
  733.         strcpy(ti->name, newbuf);
  734.         ti->valid = 0;
  735.     }
  736.     return r;
  737. }
  738.  
  739. #define DIR_FLAG(x)    (x->fsstuff[0])
  740. #define STARTSEARCH    0    /* opendir() was just called */
  741. #define INSEARCH    1    /* readdir() has been called at least once */
  742. #define NMFILE        2    /* no more files to read */
  743.  
  744. #define DIR_DTA(x)    ((DTABUF *)(x->fsstuff + 2))
  745. #define DIR_NAME(x)    (x->fsstuff + 32)
  746.  
  747. /*
  748.  * The directory functions are a bit tricky. What we do is have
  749.  * opendir() do Fsfirst; the first readdir() picks up this name,
  750.  * subsequent readdir()'s have to do Fsnext
  751.  */
  752.  
  753. static long cdecl 
  754. mc_opendir(DIR *dirh,int flags)
  755. {
  756.     long r;
  757.     struct tindex *t = (struct tindex *)dirh->fc.index;
  758.  
  759.     UNUSED(flags);
  760.     DEBUG(" mc_opendir");
  761.     (void)tfullpath(tmpbuf, t, "*.*");
  762.  
  763.     do_setdta(DIR_DTA(dirh));
  764.  
  765.     r = MC_Fsfirst(tmpbuf, FILEORDIR,DIR_DTA(dirh));
  766.  
  767.     if (r == 0) {
  768.         t->open++;
  769.         DIR_FLAG(dirh) = STARTSEARCH;
  770.         return 0;
  771.     } else if (r == EFILNF) {
  772.         t->open++;
  773.         DIR_FLAG(dirh) = NMFILE;
  774.         return 0;
  775.     }
  776.      return (r);
  777. }
  778.  
  779. static long cdecl 
  780. mc_readdir(dirh, name, namelen, fc)
  781.     DIR *dirh;
  782.     char *name;
  783.     int namelen;
  784.     fcookie *fc;
  785. {
  786.     static long index = 0;
  787.     long ret;
  788.     int giveindex = dirh->flags == 0;
  789.     struct tindex *ti;
  790.     DTABUF *dta = DIR_DTA(dirh);
  791.  
  792.     DEBUG(" mc_readdir");
  793.  
  794. again:
  795.     if (DIR_FLAG(dirh) == NMFILE)
  796.         return ENMFIL;
  797.  
  798.     if (DIR_FLAG(dirh) == STARTSEARCH) {
  799.         DIR_FLAG(dirh) = INSEARCH;
  800.     } else {
  801.         do_setdta(dta);
  802.         ret = MC_Fsnext(dta);
  803.         if (ret) {
  804.             DIR_FLAG(dirh) = NMFILE;
  805.             return ret;
  806.         }
  807.     }
  808.  
  809. /* don't return volume labels from readdir */
  810.     if (dta->d_attrib == FA_LABEL) goto again;
  811.  
  812.     fc->fs = &mc_filesys;
  813.     fc->dev = dirh->fc.dev;
  814.  
  815.     (void)tfullpath(tmpiname, (struct tindex *)dirh->fc.index, DIR_NAME(dirh));
  816.  
  817.     ti = &tmpindex;
  818.     ti->name = tmpiname;
  819.     ti->valid = 1;
  820.     ti->size = dta->d_length;
  821.     ti->date = dta->d_date;
  822.     ti->time = dta->d_time;
  823.     ti->attr = dta->d_attrib;
  824. #ifdef NEWWAY
  825.     ti->links++;
  826. #else
  827.     ti->stamp = tclock;
  828. #endif
  829.     if (executable_extension(dta->d_fname))
  830.         ti->attr |= FA_EXEC;
  831.     fc->index = (long)ti;
  832.  
  833.     if (giveindex) {
  834.         namelen -= (int) sizeof(long);
  835.         if (namelen <= 0) return ERANGE;
  836.         *((long *)name) = index++;
  837.         name += sizeof(long);
  838.     }
  839.     strncpy(name, DIR_NAME(dirh), namelen-1);
  840.     name[namelen-1] = 0;
  841.  
  842. /* BUG: we really should do the "strlwr" operation only
  843.  * for Dreaddir (i.e. if giveindex == 0) but
  844.  * unfortunately some old programs rely on the behaviour
  845.  * below
  846.  */
  847.     if (strlen(DIR_NAME(dirh)) >= namelen)
  848.         return ENAMETOOLONG;
  849.     else
  850.         return 0;
  851. }
  852.  
  853. static long cdecl 
  854. mc_rewinddir(dirh)
  855.     DIR *dirh;
  856. {
  857.     struct tindex *ti = (struct tindex *)dirh->fc.index;
  858.     long r;
  859.  
  860.  
  861.     DEBUG(" mc_rewinddir");
  862.     (void)tfullpath(tmpbuf, ti, "*.*");
  863.     do_setdta(DIR_DTA(dirh));
  864.     r = MC_Fsfirst(tmpbuf, FILEORDIR,DIR_DTA(dirh));
  865.     if (r == 0) {
  866.         DIR_FLAG(dirh) = STARTSEARCH;
  867.     } else {
  868.         DIR_FLAG(dirh) = NMFILE;
  869.     }
  870.     return r;
  871. }
  872.  
  873. static long cdecl 
  874. mc_closedir(dirh)
  875.     DIR *dirh;
  876. {
  877.     struct tindex *t = (struct tindex *)dirh->fc.index;
  878.  
  879.     DEBUG(" mc_closedir");
  880.     if (t->open == 0) {
  881.         FATAL("t->open == 0: directory == %s", t->name);
  882.     }
  883.     --t->open;
  884.     DIR_FLAG(dirh) = NMFILE;
  885.     return 0;
  886. }
  887.  
  888. static long cdecl 
  889. mc_pathconf(dir, which)
  890.     fcookie *dir;
  891.     int which;
  892. {
  893.     UNUSED(dir);
  894.  
  895.     DEBUG(" mc_pathconf");
  896.     switch(which) {
  897.     case -1:
  898.         return DP_MAXREQ;
  899.     case DP_IOPEN:
  900.         return 60;    /* we can only keep about this many open */
  901.     case DP_MAXLINKS:
  902.          return 1;    /* no hard links */
  903.     case DP_PATHMAX:
  904.         return PATH_MAX;
  905.     case DP_NAMEMAX:
  906.         return 8+3+1;
  907.     case DP_ATOMIC:
  908.         return 512;    /* we can write at least a sector atomically */
  909.     case DP_TRUNC:
  910.         return DP_DOSTRUNC;    /* DOS style file names */
  911. /*    case DP_CASE:
  912.         return DP_CASECONV;    /* names converted to upper case */
  913. */
  914.     default:
  915.         return EINVFN;
  916.     }
  917. }
  918.  
  919. long cdecl 
  920. mc_dfree(dir, buf)
  921.     fcookie *dir;
  922.     long *buf;
  923. {
  924.     DEBUG(" mc_dfree");
  925.     return MC_Dfree(buf, (dir->dev)+1);
  926. }
  927.  
  928. /*
  929.  * writelabel: creates a volume label
  930.  * readlabel: reads a volume label
  931.  * both of these are only guaranteed to work in the root directory
  932.  */
  933.  
  934. /*
  935.  * BUG: this should first delete any old labels, so that it will
  936.  * work with TOS <1.4
  937.  */
  938.  
  939. long cdecl 
  940. mc_writelabel(dir, name)
  941.     fcookie *dir;
  942.     const char *name;
  943. {
  944.     long r;
  945.     struct tindex *ti;
  946.  
  947.     DEBUG(" mc_writelabel");
  948.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  949.     r = MC_Fcreate(tmpbuf, FA_LABEL);
  950.     if (r < 0) return r;
  951.     (void)MC_Fclose((int)r);
  952.     ti = tstrindex(tmpbuf);
  953.     ti->valid = 0;
  954.     return 0;
  955. }
  956.  
  957. long cdecl 
  958. mc_readlabel(dir, name, namelen)
  959.     fcookie *dir;
  960.     char *name;
  961.     int namelen;
  962. {
  963.     long r;
  964.     struct tindex *ti = (struct tindex *)dir->index;
  965.     DEBUG(" mc_readlabel");
  966.  
  967.     if (ti->name[2] != 0)        /* not a root directory? */
  968.         return EFILNF;
  969.  
  970.     (void)tfullpath(tmpbuf, ti, "*.*");
  971.     do_setdta(&foo);
  972.     r = MC_Fsfirst(tmpbuf, FA_LABEL,&foo);
  973.     if (r)
  974.         return r;
  975.     strncpy(name, foo.d_fname, namelen-1);
  976.     return (strlen(foo.d_fname) < namelen) ? 0 : ENAMETOOLONG;
  977. }
  978.  
  979. /*
  980.  * TOS creat: this doesn't actually create the file, rather it
  981.  * sets up a (fake) index for the file that will be used by
  982.  * the later mc_open call.
  983.  */
  984.  
  985. static long cdecl 
  986. mc_creat(dir, name, mode, attrib, fc)
  987.     fcookie *dir;
  988.     const char *name;
  989.     unsigned mode;
  990.     int attrib;
  991.     fcookie *fc;
  992. {
  993.     struct tindex *ti=(struct tindex *)dir->index;
  994.     UNUSED(mode);
  995.  
  996.     DEBUG(" mc_create dir=%ld name=%ld",dir->index,(long)name);
  997.     
  998.     (void)tfullpath(tmpbuf,ti, name);
  999.  
  1000.     ti = tstrindex(tmpbuf);
  1001.     ti->size = 0;
  1002.     ti->date = (int) Datestamp();
  1003.     ti->time = (int) Timestamp();
  1004.     ti->attr = attrib;
  1005.     ti->valid = 1;
  1006.  
  1007.     fc->fs = &mc_filesys;
  1008.     fc->index = (long)ti;
  1009.     fc->dev = dir->dev;
  1010. #ifdef NEWWAY
  1011.     ti->links++;
  1012. #endif
  1013.     return 0;
  1014. }
  1015.     
  1016. /*
  1017.  * TOS device driver
  1018.  */
  1019.  
  1020. static DEVDRV * cdecl 
  1021. mc_getdev(fc, devsp)
  1022.     fcookie *fc;
  1023.     long *devsp;
  1024. {
  1025.     UNUSED(fc); UNUSED(devsp);
  1026.     DEBUG(" mc_getdevice");
  1027.     return &mc_device;
  1028. }
  1029.  
  1030. static long cdecl mc_open(FILEPTR *f)
  1031. {
  1032.     struct tindex *ti;
  1033.     int mode = f->flags;
  1034.     int tosmode;
  1035.     long r;
  1036.     extern int flk;        /* in main.c, set if _FLK cookie already present */
  1037.  
  1038.     ti = (struct tindex *)(f->fc.index);
  1039.     DEBUG(" mc_open");
  1040.  
  1041. #ifndef NEWWAY
  1042.     ti->stamp = ++tclock;
  1043. #endif
  1044.     ti->valid = 0;
  1045.  
  1046. #ifndef RO_FASCISM
  1047. /* TEMPORARY HACK: change all modes to O_RDWR for files opened in
  1048.  * compatibility sharing mode. This is silly, but
  1049.  * allows broken TOS programs that write to read-only handles to continue
  1050.  * to work (it also helps file sharing, by making the realistic assumption
  1051.  * that any open TOS file can be written to). Eventually,
  1052.  * this should be tuneable by the user somehow.
  1053.  * ALSO: change O_COMPAT opens into O_DENYNONE; again, this may be temporary.
  1054.  */
  1055.     if ( (mode & O_SHMODE) == O_COMPAT ) {
  1056.         f->flags = (mode & ~(O_RWMODE|O_SHMODE)) | O_RDWR | O_DENYNONE;
  1057.     }
  1058. #endif
  1059.  
  1060. /* check to see that nobody has opened this file already in an
  1061.  * incompatible mode
  1062.  */
  1063.     if (Denyshare(ti->open, f)) {
  1064.         return EACCDN;
  1065.     }
  1066.  
  1067. /*
  1068.  * now open the file; if O_TRUNC was specified, actually
  1069.  * create the file anew.
  1070.  * BUG: O_TRUNC without O_CREAT doesn't work right. The kernel doesn't
  1071.  * use this mode, anyways
  1072.  */
  1073.  
  1074.     if (mode & O_TRUNC) {
  1075.         if (ti->open) {
  1076.             return EACCDN;
  1077.         }
  1078.         r = MC_Fcreate(ti->name, ti->attr);
  1079.     } else {
  1080.         if (flk)
  1081.             tosmode = mode & (O_RWMODE|O_SHMODE);
  1082.         else
  1083.             tosmode = (mode & O_RWMODE);
  1084.         if (tosmode == O_EXEC) tosmode = O_RDONLY;
  1085.  
  1086.         r = MC_Fopen(ti->name, tosmode );
  1087.         if (r == EFILNF && (mode & O_CREAT))
  1088.         {
  1089.             r = MC_Fcreate(ti->name, ti->attr);
  1090.         }
  1091.     }
  1092.  
  1093.     if (r < 0) {
  1094. /* get rid of the index for the file, since it doesn't exist */
  1095.         Kfree(ti->name);
  1096.         ti->name = 0;
  1097.         ti->valid = 0;
  1098.         return r;
  1099.     }
  1100.  
  1101.     f->devinfo = r;
  1102.  
  1103.     f->next = ti->open;
  1104.     ti->open = f;
  1105.     return 0;
  1106. }
  1107.  
  1108. static long cdecl 
  1109. mc_write(f, buf, bytes)
  1110.     FILEPTR *f; const char *buf; long bytes;
  1111. {
  1112.     struct tindex *ti = (struct tindex *)f->fc.index;
  1113.  
  1114.     ti->valid = 0;
  1115.     DEBUG(" mc_write");
  1116.     return MC_Fwrite((int)f->devinfo, bytes, buf);
  1117. }
  1118.  
  1119. static long cdecl 
  1120. mc_read(f, buf, bytes)
  1121.     FILEPTR *f; char *buf; long bytes;
  1122. {
  1123.     DEBUG(" mc_read");
  1124.     return MC_Fread((int)f->devinfo, bytes, buf);
  1125. }
  1126.  
  1127. static long cdecl 
  1128. mc_lseek(f, where, whence)
  1129.     FILEPTR *f; long where; int whence;
  1130. {
  1131.     long r;
  1132.  
  1133.     DEBUG(" mc_lseek");
  1134.     r = MC_Fseek(where, (int)f->devinfo, whence);
  1135.     return r;
  1136. }
  1137.  
  1138. static long cdecl 
  1139. mc_ioctl(f, mode, buf)
  1140.     FILEPTR *f; int mode; void *buf;
  1141. {
  1142.     LOCK t, *lck, **old;
  1143.     struct flock *fl;
  1144.     long r;
  1145.     struct tindex *ti;
  1146.     extern int flk;        /* set in main.c if _FLK already installed */
  1147.  
  1148.     DEBUG(" mc_ioctl");
  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 = MC_Fseek(0L, (int)f->devinfo, 1);
  1161.             t.l.l_start += r;
  1162.             break;
  1163.         case 2:
  1164.             r = MC_Fseek(0L, (int)f->devinfo, 1);
  1165.             t.l.l_start = MC_Fseek(t.l.l_start, (int)f->devinfo, 2);
  1166.             (void)MC_Fseek(r, (int)f->devinfo, 0);
  1167.             break;
  1168.         default:
  1169.             return EINVFN;
  1170.         }
  1171. /* BUG: can't lock a file starting at >2gigabytes from the beginning */
  1172.         if (t.l.l_start < 0) t.l.l_start = 0;
  1173.         t.l.l_whence = 0;
  1174.         ti = (struct tindex *)f->fc.index;
  1175.  
  1176.         if (mode == F_GETLK) {
  1177.             lck = Denylock(ti->locks, &t);
  1178.             if (lck)
  1179.                 *fl = lck->l;
  1180.             else
  1181.                 fl->l_type = F_UNLCK;
  1182.             return 0;
  1183.         }
  1184.  
  1185.         if (t.l.l_type == F_UNLCK) {
  1186.         /* try to find the lock */
  1187.             old = &ti->locks;
  1188.             lck = *old;
  1189.             while (lck) { /*???*/
  1190.                 if (lck->l.l_start == t.l.l_start &&
  1191.                     lck->l.l_len == t.l.l_len) {
  1192.         /* found it -- remove the lock */
  1193.                     *old = lck->next;
  1194.                     if (flk)
  1195.                         (void)Flock((int)f->devinfo, 1,
  1196.                             t.l.l_start, t.l.l_len);
  1197.                 /* wake up anyone waiting on the lock */
  1198.                     Wake(IO_Q, (long)lck);
  1199.                     Kfree(lck);
  1200.                     break;
  1201.                 }
  1202.                 old = &lck->next;
  1203.                 lck = lck->next;
  1204.             }
  1205.             return lck ?  0 : ENSLOCK;
  1206.         }
  1207.         do {
  1208.         /* see if there's a conflicting lock */
  1209.             while ((lck = Denylock(ti->locks, &t)) != 0) {
  1210.             if (mode == F_SETLKW) {
  1211.                 Sleep(IO_Q, (long)lck);
  1212.             }
  1213.             else
  1214.                 return ELOCKED;
  1215.             }
  1216.         /* if not, add this lock to the list */
  1217.             lck = Kmalloc(sizeof(LOCK));
  1218.             if (!lck) return ENSMEM;
  1219.         /* see if other _FLK code might object */
  1220.             if (flk) {
  1221.                 r = Flock((int)f->devinfo, 0, t.l.l_start, t.l.l_len);
  1222.                 if (r) {
  1223.                     Kfree(lck);
  1224.                     if (mode == F_SETLKW && r == ELOCKED) {
  1225.                         Yield();
  1226.                         lck = NULL;
  1227.                     }
  1228.                     else
  1229.                         return r;
  1230.                 }
  1231.             }
  1232.         } while (!lck);
  1233.         lck->l = t.l;
  1234.         lck->l.l_pid = 0;/* ??? */
  1235.         lck->next = ti->locks;
  1236.         ti->locks = lck;
  1237.     /* mark the file as being locked */
  1238.         f->flags |= O_LOCK;
  1239.         return 0;
  1240.     }
  1241.     return EINVFN;
  1242. }
  1243.  
  1244. static long cdecl 
  1245. mc_datime(FILEPTR *f,int *timeptr,int rwflag)
  1246. {
  1247.     DEBUG(" mc_datime");
  1248.     if (rwflag) {
  1249.         struct tindex *ti = (struct tindex *)f->fc.index;
  1250.         ti->valid = 0;
  1251.     }
  1252.     return MC_Fdatime(timeptr, (int)f->devinfo, rwflag);
  1253. }
  1254.  
  1255. static long cdecl 
  1256. mc_close(f, pid)
  1257.     FILEPTR *f;
  1258.     int pid;
  1259. {
  1260.     LOCK *lck, **oldl;
  1261.     struct tindex *t;
  1262.     FILEPTR **old, *p;
  1263.     long r = 0;
  1264.     extern int flk;        /* set in main.c */
  1265.  
  1266.     t = (struct tindex *)(f->fc.index);
  1267.     DEBUG(" mc_close");
  1268. /* if this handle was locked, remove any locks held by the process
  1269.  */
  1270.     if (f->flags & O_LOCK) {
  1271.         oldl = &t->locks;
  1272.         lck = *oldl;
  1273.         while (lck) {
  1274.             if (lck->l.l_pid == pid) {
  1275.                 *oldl = lck->next;
  1276.                 if (flk)
  1277.                     (void)Flock((int)f->devinfo, 1,
  1278.                         lck->l.l_start, lck->l.l_len);
  1279.                 Wake(IO_Q, (long)lck);
  1280.                 Kfree(lck);
  1281.             } else {
  1282.                 oldl = &lck->next;
  1283.             }
  1284.             lck = *oldl;
  1285.         }
  1286.     }
  1287.  
  1288.     if (f->links <= 0) {
  1289. /* remove f from the list of open file pointers on this index */
  1290.         t->valid = 0;
  1291.         old = &t->open;
  1292.         p = t->open;
  1293.         while (p && p != f) {
  1294.             old = &p->next;
  1295.             p = p->next;
  1296.         }
  1297.         *old = f->next;
  1298.         f->next = 0;
  1299.         r = MC_Fclose((int)f->devinfo);
  1300.  
  1301. /* if the file was marked for deletion, delete it */
  1302.         if (!t->open) {
  1303.             if (t->attr & FA_DELETE) {
  1304.                 (void)MC_Fdelete(t->name);
  1305.                 t->name = 0;
  1306.             }
  1307.         }
  1308.     }
  1309.     return r;
  1310. }
  1311.  
  1312. /*
  1313.  * check for disk change: called by the kernel if Mediach returns a
  1314.  * non-zero value
  1315.  */
  1316. /*
  1317. long cdecl 
  1318. mc_dskchng(drv)
  1319.     int drv;
  1320. {
  1321.     char dlet;
  1322.     int i;
  1323.     struct tindex *ti;
  1324.  
  1325.     dlet = 'A' + drv;
  1326.  
  1327.     DEBUG(" mc_dskchng");
  1328.     ti = gl_ti;
  1329.     for (i = 0; i < NUM_INDICES; i++, ti++) {
  1330.         if (ti->name && ti->name[0] == dlet) {
  1331.             Kfree(ti->name);
  1332.             ti->name = 0;
  1333.         }
  1334.     }
  1335.     tmpindex.valid = 0;
  1336. /*
  1337.  * OK, make sure that GEMDOS knows to look for a change if we
  1338.  * ever use this drive again.
  1339.  */
  1340.     return 1;
  1341. }
  1342. */
  1343.  
  1344. #ifdef NEWWAY
  1345. /* release/copy file cookies; these functions exist to keep
  1346.  * track of whether or not the kernel is still using a file
  1347.  */
  1348. long cdecl mc_release(fcookie *fc)
  1349. {
  1350.     struct tindex *ti = (struct tindex *)fc->index;
  1351.  
  1352.     if (ti->links <= 0) {
  1353.         FATAL("mc_release: link count of `%s' is %d", ti->name, ti->links);
  1354.     }
  1355.     
  1356.     ti->links--;
  1357.     DEBUG("mc_release: %s now has %d links", ti->name, ti->links);
  1358.     return 0;
  1359. }
  1360.  
  1361.  
  1362. long cdecl mc_dupcookie(fcookie *dest,fcookie *src)
  1363. {
  1364.     struct tindex *ti = (struct tindex *)src->index;
  1365.  
  1366.     if (ti->links <= 0) {
  1367.         FATAL("mc_dupcookie: link count of %s is %d", ti->name, ti->links);
  1368.     }
  1369.     ti->links++;
  1370.     DEBUG("mc_dupcookie: %s now has %d links", ti->name, ti->links);
  1371.     *dest=*src;
  1372.     return 0;
  1373. }
  1374. #endif
  1375.  
  1376. /*
  1377.  * utility function: sets the TOS DTA, and also records what directory
  1378.  * this was in. This is just to save us a call into the kernel if the
  1379.  * correct DTA has already been set.
  1380.  */
  1381.  
  1382. static void
  1383. do_setdta(dta)
  1384.     DTABUF *dta;
  1385. {
  1386.     if (dta != lastdta) {
  1387. /*        Fsetdta(dta);*/
  1388.         lastdta = dta;
  1389.     }
  1390. }
  1391.  
  1392. static    CINFO    infos;
  1393.  
  1394. static long install_cookies(void)
  1395. {
  1396.     COOKIE  *cokie;
  1397.     int        found=0;
  1398.     long    laenge;
  1399.     
  1400.     cokie =     *CJAR;
  1401.     if (cokie) 
  1402.     {
  1403.         while (cokie->tag.aslong != 0) 
  1404.         {
  1405.             if (!strncmp(cokie->tag.aschar, "MICO",4))
  1406.             {
  1407.                 cokie->value=(long)&infos;
  1408.                 found=1;
  1409.             }
  1410.             cokie++;
  1411.         }
  1412.         if (!found)
  1413.         {
  1414.             laenge=cokie->value;
  1415.             strncpy(cokie->tag.aschar,"MICO",4);
  1416.             cokie->value=(long) &infos;
  1417.             cokie++;
  1418.             cokie->tag.aslong = 0; 
  1419.             cokie->value=laenge;
  1420.         }
  1421.         infos.LW=MCDRIVE+'A';
  1422.         infos.params=NULL;
  1423.         infos.kernel=kernel;
  1424.     }
  1425.     return(0);
  1426. }
  1427.  
  1428. static para * getmc_cookie(void)
  1429. {
  1430.     COOKIE *jar;
  1431.  
  1432.     if (infos.params) return((para*) infos.params);
  1433.     jar = *CJAR;    /* CJAR defined in cookie.h */
  1434.     if (jar) 
  1435.     {
  1436.         while (jar->tag.aslong != 0) 
  1437.         {
  1438.             if (!strncmp(jar->tag.aschar, "MICO",4)) 
  1439.             {
  1440.                 return((para*) infos.params);
  1441.             }
  1442.             jar++;
  1443.         }
  1444.     } else return(NULL);
  1445.     return(NULL);
  1446. }
  1447.  
  1448. long cdecl nosymlink(fcookie *dir,const char *name,const char *to)
  1449. {
  1450.     DEBUG("nosymlink");
  1451.     UNUSED(dir); UNUSED(name);
  1452.     UNUSED(to);
  1453.     return EINVFN;
  1454. }
  1455.  
  1456. long cdecl noreadlink(fcookie *dir,char *buf,int buflen)
  1457. {
  1458.     DEBUG("noreadlink");
  1459.     UNUSED(dir); UNUSED(buf);
  1460.     UNUSED(buflen);
  1461.     return EINVFN;
  1462. }
  1463.  
  1464. long cdecl nohardlink(fcookie *fromdir,fcookie *todir,const char *fromname,    const char *toname)
  1465. {
  1466.     DEBUG("nohardlink");
  1467.     UNUSED(fromdir); UNUSED(todir);
  1468.     UNUSED(fromname); UNUSED(toname);
  1469.     return EINVFN;
  1470. }
  1471.  
  1472. /* dummy routine for file systems with no Fscntl commands */
  1473.  
  1474. long cdecl nofscntl(fcookie *dir,const char *name,int cmd,long arg)
  1475. {
  1476.     DEBUG("nofscntl");
  1477.     UNUSED(dir); UNUSED(name);
  1478.     UNUSED(cmd); UNUSED(arg);
  1479.     return EINVFN;
  1480. }
  1481.  
  1482. /*
  1483.  * Did the disk change? Not on this drive!
  1484.  * However, we have to do Getbpb anyways, because someone has decided
  1485.  * to force a media change on our (non-existent) drive.
  1486.  */
  1487. long cdecl nodskchng(int drv)
  1488. {
  1489.     DEBUG("nodskchng");
  1490.     UNUSED(drv);
  1491.     return 0;
  1492. }
  1493.  
  1494. long cdecl null_select(FILEPTR *f, long p,int mode)
  1495. {
  1496.     FATAL("null_select");
  1497.     UNUSED(f); UNUSED(p);
  1498.     UNUSED(mode);
  1499.     return 1;    /* we're always ready to read/write */
  1500. }
  1501.  
  1502. void cdecl null_unselect(FILEPTR *f,long p,int mode)
  1503. {
  1504.     DEBUG("null_unselect");
  1505.     UNUSED(f); UNUSED(p);
  1506.     UNUSED(mode);
  1507.     /* nothing to do */
  1508. }
  1509.  
  1510. static int semaphore=0;
  1511.  
  1512. void cdecl pausen(int *i)
  1513. {
  1514. /*  while (*i>0) { Sleep(READY_Q,0L);};*/
  1515.   while (*i>0) { Sleep(IO_Q,1234L);};
  1516. }
  1517.  
  1518. void set_semaphore(void)
  1519. {
  1520.  while (semaphore>0) {pausen(&semaphore);};
  1521.  semaphore=1;
  1522. };
  1523.  
  1524. void free_semaphore(void)
  1525. {
  1526.  semaphore=0;
  1527.  Wake(IO_Q,1234L);
  1528. };
  1529.  
  1530. static char h_path[PATH_MAX+1];
  1531.  
  1532. long MC_Fsfirst(char *filename, int attr,DTABUF *dta )
  1533. {
  1534.     para *parm=getmc_cookie();
  1535.     
  1536. DEBUG("MC_FSFIRST");
  1537.     if (parm)
  1538.     {
  1539.         set_semaphore();
  1540.         parm->retcode=-4;
  1541.         parm->fktn=78;
  1542.         
  1543.         strcpy(h_path,filename);
  1544.         parm->mix.fu78.PFAD=h_path;
  1545.         parm->mix.fu78.ATTR=attr;
  1546.         parm->mix.fu78.dta=dta;
  1547.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1548.         free_semaphore();
  1549.         return(parm->retcode);
  1550.     }
  1551.     return(EFILNF);    /* file not found */
  1552. }
  1553.  
  1554. long MC_Fsnext(DTABUF *dta)
  1555. {
  1556.     para *parm=getmc_cookie();
  1557.     
  1558. DEBUG("MC_FSNEXT");
  1559.     if (parm)
  1560.     {
  1561.         set_semaphore();
  1562.         parm->retcode=-4;
  1563.         parm->fktn=79;
  1564.         parm->mix.dta=dta;
  1565.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1566.         free_semaphore();
  1567.         return(parm->retcode);
  1568.     }
  1569.     return(EFILNF);    /* file not found */
  1570. }
  1571.  
  1572. long  MC_Fopen(char *name,int tosmode )
  1573. {
  1574.     para *parm=getmc_cookie();
  1575.     
  1576. DEBUG("MC_FOPEN");
  1577.     if (parm)
  1578.     {
  1579.         set_semaphore();
  1580.         parm->retcode=-4;
  1581.         parm->fktn=61;
  1582.         strcpy(h_path,name);
  1583.         parm->mix.fu78.PFAD=h_path;
  1584.         parm->mix.fu78.ATTR=tosmode;
  1585.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1586.         free_semaphore();
  1587.         return(parm->retcode);
  1588.     }
  1589.     return(EFILNF);    /* file not found */
  1590. }
  1591.  
  1592. long MC_Fread( int handle, long count, void *buf )
  1593. {
  1594.     para *parm=getmc_cookie();
  1595.     
  1596. DEBUG("MC_FREAD");
  1597.     if (parm)
  1598.     {
  1599.         set_semaphore();
  1600.         parm->retcode=-4;
  1601.         parm->fktn=63;
  1602.         parm->mix.fu63.handle=handle;
  1603.         parm->mix.fu63.count=count;
  1604.         parm->mix.fu63.buffer=buf;
  1605.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1606.         free_semaphore();
  1607.         return(parm->retcode);
  1608.     }
  1609.     return(EFILNF);    /* file not found */
  1610. }
  1611.  
  1612. long MC_Fcreate(char *name,int tosmode )
  1613. {
  1614.     para *parm=getmc_cookie();
  1615.     
  1616. DEBUG("MC_FCREATE");
  1617.     if (parm)
  1618.     {
  1619.         set_semaphore();
  1620.         parm->retcode=-4;
  1621.         parm->fktn=60;
  1622.         strcpy(h_path,name);
  1623.         parm->mix.fu78.PFAD=h_path;
  1624.         parm->mix.fu78.ATTR=tosmode;
  1625.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1626.         free_semaphore();
  1627.         return(parm->retcode);
  1628.     }
  1629.     return(EFILNF);    /* file not found */
  1630. }
  1631.  
  1632. long MC_Fclose(int handle)
  1633. {
  1634.     para *parm=getmc_cookie();
  1635.     
  1636. DEBUG("MC_FCLOSE");
  1637.     if (parm)
  1638.     {
  1639.         set_semaphore();
  1640.         parm->retcode=-4;
  1641.         parm->fktn=62;
  1642.         parm->mix.LEER=handle;
  1643.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1644.         free_semaphore();
  1645.         return(parm->retcode);
  1646.     }
  1647.     return(EFILNF);    /* file not found */
  1648. }
  1649.  
  1650. long MC_Dcreate(char *path )
  1651. {
  1652.     para *parm=getmc_cookie();
  1653.     
  1654. DEBUG("MC_DCREATE");
  1655.     if (parm)
  1656.     {
  1657.         set_semaphore();
  1658.         parm->retcode=-4;
  1659.         parm->fktn=57;
  1660.         strcpy(h_path,path);
  1661.         parm->mix.fu78.PFAD=h_path;
  1662.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1663.         free_semaphore();
  1664.         return(parm->retcode);
  1665.     }
  1666.     return(EFILNF);    /* file not found */
  1667. }
  1668.  
  1669. long MC_Dfree(long *buf, int driveno)
  1670. {
  1671.     para *parm=getmc_cookie();
  1672.     
  1673.     UNUSED(driveno);
  1674. DEBUG("MC_FFREE");
  1675.     if (parm)
  1676.     {
  1677.         set_semaphore();
  1678.         parm->retcode=-4;
  1679.         parm->fktn=54;
  1680.         parm->mix.fu54.info=(diskinfo *)buf;
  1681.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1682.         free_semaphore();
  1683.         return(parm->retcode);
  1684.     }
  1685.     return(EFILNF);    /* file not found */
  1686. }
  1687.  
  1688. long MC_Ddelete(char *path )
  1689. {
  1690.     para *parm=getmc_cookie();
  1691.     
  1692. DEBUG("MC_DDELETE");
  1693.     if (parm)
  1694.     {
  1695.         set_semaphore();
  1696.         parm->retcode=-4;
  1697.         parm->fktn=58;
  1698.         strcpy(h_path,path);
  1699.         parm->mix.fu78.PFAD=h_path;
  1700.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1701.         free_semaphore();
  1702.         return(parm->retcode);
  1703.     }
  1704.     return(EFILNF);    /* file not found */
  1705. }
  1706.  
  1707. long MC_Fseek( long offset, int handle, int seekmode )
  1708. {
  1709.     para *parm=getmc_cookie();
  1710.     
  1711. DEBUG("MC_FSEEK");
  1712.     if (parm)
  1713.     {
  1714.         set_semaphore();
  1715.         parm->retcode=-4;
  1716.         parm->fktn=66;
  1717.         parm->mix.fu66.hndl=handle;
  1718.         parm->mix.fu66.skmod=seekmode;
  1719.         parm->mix.fu66.offs=offset;
  1720.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1721.         free_semaphore();
  1722.         return(parm->retcode);
  1723.     }
  1724.     return(EFILNF);    /* file not found */
  1725. }
  1726.  
  1727. long    MC_Fattrib(char *filename, int wflag, int attrib )
  1728. {
  1729.     para *parm=getmc_cookie();
  1730.     
  1731. DEBUG("MC_FATTRIB");
  1732.     if (parm)
  1733.     {
  1734.         set_semaphore();
  1735.         parm->retcode=-4;
  1736.         parm->fktn=67;
  1737.         strcpy(h_path,filename);
  1738.         parm->mix.fu67.fnm=h_path;
  1739.         parm->mix.fu67.fattr=attrib;
  1740.         parm->mix.fu67.wflag=wflag;
  1741.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1742.         free_semaphore();
  1743.         return(parm->retcode);
  1744.     }
  1745.     return(EFILNF);    /* file not found */
  1746. }
  1747.  
  1748. long MC_Fdelete(char *filename )
  1749. {
  1750.     para *parm=getmc_cookie();
  1751.     
  1752. DEBUG("MC_FDELETE");
  1753.     if (parm)
  1754.     {
  1755.         set_semaphore();
  1756.         parm->retcode=-4;
  1757.         parm->fktn=65;
  1758.         strcpy(h_path,filename);
  1759.         parm->mix.fu78.PFAD=h_path;
  1760.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1761.         free_semaphore();
  1762.         return(parm->retcode);
  1763.     }
  1764.     return(EFILNF);    /* file not found */
  1765. }
  1766.  
  1767. long MC_Frename( int zero,char *oldname,char *newname )
  1768. {
  1769.     para *parm=getmc_cookie();
  1770.  
  1771. DEBUG("MC_FRENAME");
  1772.     UNUSED(zero);
  1773.     if (parm)
  1774.     {
  1775.         set_semaphore();
  1776.         parm->retcode=-4;
  1777.         parm->fktn=86;
  1778.         strcpy(h_path,oldname);
  1779.         parm->mix.fu86.pf1=h_path;
  1780.         parm->mix.fu86.pf2=newname;
  1781.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1782.         free_semaphore();
  1783.         return(parm->retcode);
  1784.     }
  1785.     return(EFILNF);    /* file not found */
  1786. }
  1787.  
  1788. long MC_Fwrite( int handle, long count, void *buf )
  1789. {
  1790.     para *parm=getmc_cookie();
  1791.     
  1792. DEBUG("MC_FWRITE");
  1793.     if (parm)
  1794.     {
  1795.         set_semaphore();
  1796.         parm->retcode=-4;
  1797.         parm->fktn=64;
  1798.         parm->mix.fu63.handle=handle;
  1799.         parm->mix.fu63.count=count;
  1800.         parm->mix.fu63.buffer=buf;
  1801.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1802.         free_semaphore();
  1803.         return(parm->retcode);
  1804.     }
  1805.     return(EFILNF);    /* file not found */
  1806. }
  1807.  
  1808. long  MC_Fdatime( int *timeptr, int handle, int wflag )
  1809. {
  1810.     para *parm=getmc_cookie();
  1811.     
  1812. DEBUG("MC_FDATIME");
  1813.     if (parm)
  1814.     {
  1815.         set_semaphore();
  1816.         parm->retcode=-4;
  1817.         parm->fktn=87;
  1818.         parm->mix.fu87.handl=handle;
  1819.         parm->mix.fu87.wf=wflag;
  1820.         parm->mix.fu87.dostme=(long *)timeptr;
  1821.         while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
  1822.         free_semaphore();
  1823.         return(parm->retcode);
  1824.     }
  1825.     return(EFILNF);    /* file not found */
  1826. }
  1827.  
  1828.