home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / diskutil / xfsys / xfs.c next >
C/C++ Source or Header  |  1993-08-06  |  23KB  |  935 lines

  1. /*
  2.  * xfs.c -- extended file system for master v5.7
  3.  * Author          : Edgar Röder
  4.  * Created On      : Mon Apr 30 13:18:06 1990
  5.  * Last Modified By: Edgar Roeder
  6.  * Last Modified On: Mon Sep  3 19:25:16 1990
  7.  * Update Count    : 134
  8.  * Status          : should work now, needs some speedup
  9.  *
  10.  * HISTORY 
  11.  * 25-May-1990        Edgar Röder    
  12.  *    Last Modified: Fri May 25 22:31:12 1990 #127 (Edgar Röder)
  13.  *    removed almost all debug output and canonicalize()-calls
  14.  *    put dta_getname in module_header, so other programs (!= Master)
  15.  *    can find it there
  16.  *
  17.  * 8-May-1990        Edgar Röder    
  18.  *    Last Modified: Tue May  8 21:11:36 1990 #114 (Edgar Röder)
  19.  *    disable dta_getname while dispatcher is active
  20.  *
  21.  * 8-May-1990        Edgar Röder    
  22.  *    Last Modified: Tue May  8 15:29:08 1990 #107 (Edgar Röder)
  23.  *    reset magic number in dta at the end of Fsnext
  24.  *    add glob to do filename matching
  25.  *    removed some debugging output and made cacheing configurable
  26.  *
  27.  * 7-May-1990        Edgar Röder    
  28.  *    Last Modified: Sun May  6 23:04:48 1990 #91 (Edgar Röder)
  29.  *    added Fforce and Fdup support
  30.  *
  31.  * 6-May-1990        Edgar Röder    
  32.  *    Last Modified: Sun May  6 00:21:32 1990 #90 (Edgar Röder)
  33.  *    added _unx2dos call in xfs_opendir to get an absolute path
  34.  *    use XFSMODE environment variable to allow different unixmodes
  35.  *    for xfs and application programs (they could use mode == "cu")
  36.  *
  37.  * 4-May-1990        Edgar Röder    
  38.  *    Last Modified: Fri May  4 14:55:46 1990 #74 (Edgar Röder)
  39.  *    added rewinddir if directory was already open
  40.  *    added read/write/lseek for device manipulation
  41.  *
  42.  * 4-May-1990        Edgar Röder    
  43.  *    Last Modified: Fri May  4 02:13:34 1990 #71 (Edgar Röder)
  44.  *    if directory was already open, use that structure
  45.  *
  46.  * 4-May-1990        Edgar Röder    
  47.  *    Last Modified: Fri May  4 01:57:04 1990 #69 (Edgar Röder)
  48.  *    added special case for deleted files (pattern is 0xE5)
  49.  *
  50.  * 4-May-1990        Edgar Röder    
  51.  *    changed data structure to record pattern and search attribute
  52.  *
  53.  */ 
  54. #include <signal.h>
  55. #include <stdlib.h>
  56. #include <basepage.h>
  57. #include <string.h>
  58. #include <osbind.h>
  59. #include <xbra.h>
  60. #include <sysvars.h>
  61. #include <errno.h>
  62. #include <dirent.h>
  63. #include <stdio.h>
  64. #include <setjmp.h>
  65. #include <stat.h>
  66. #include <device.h>
  67.  
  68. /* to enable debug output define TRACING to 1 */
  69. #define    TRACING    1    /* enable debug output */
  70. /* if you use the GNU-malloc */
  71. /*undef    GNU_MALLOC    /* enable malloc statistics */
  72. /* directory cacheing might interfere with Ddelete and Fdelete */
  73. /*undef    DIR_CACHE    /* enable directory cacheing */
  74. /* if we don't use glob, we pretend that Fsfirst is either called with */
  75. /* a full filename or with *.* */
  76. #define    USE_GLOB    /* enable complex search patterns */
  77.  
  78. #ifdef bool
  79. #undef bool
  80. #endif
  81.  
  82. typedef short    bool;
  83.  
  84. BASEPAGE    *master = (BASEPAGE *) 0;
  85. char    *master_var;
  86.  
  87. #define kByte    * 1024L
  88.  
  89. static char    __patch_stack[] = "{PatchVar}stack = %ld bytes";
  90. extern long    _initial_stack = 100 kByte;
  91. static char    __patch_var_format[] = "{PatchVar}default for unixmode = %15s";
  92. static char    __default_unixmode[16] = "/.,LAHdb\0\0\0\0\0\0\0";
  93. extern char    *_default_unixmode = __default_unixmode;
  94. extern char    _tCASE;
  95. extern char    _tDOTS;
  96. extern char    _tSLASH;
  97. extern char    _tUNLIMITED;
  98. extern char    *_ltoa();
  99. extern long    modul(const char *);
  100. extern char    *dta_getname(struct _dta *);
  101.  
  102. typedef struct {
  103.     char    *master_name;
  104.     short    function_type;
  105.     long    (*function_entry)(const char *cmdline);
  106. } func;
  107.  
  108. func    module_entries[] = {
  109.     { "XFS", 0, modul }
  110. };
  111.  
  112. #define _MODUL_MAGIC    0x58465332L    /* 'XFS1' */
  113. #define _MMX_MAGIC    0x4D4D5845L    /* 'MMXE' */
  114. #define _XFS_VERSION    2
  115.  
  116. typedef char    *(dta_func)(struct _dta *);
  117.  
  118. struct head {
  119.     char        *module_description;
  120.     short        module_version;
  121.     short        number_of_functions;
  122.     func        *jump_table;
  123.     long        module_magic;
  124.     long        xbra_magic;    /* 'XBRA' */
  125.     long        mmx_magic;    /* 'MMXE' */
  126.     xptr        next;
  127.     short        jump;
  128.     dta_func    *this;
  129. } module_header = {
  130.     "    Master-Module-eXtension eXtended File System V1.1 ("
  131.     __DATE__ " " __TIME__ ")\r\n"
  132.     "\n"
  133.     "        Usage        |    Explanation\r\n"
  134.     "    ------------------------+--------------------------\r\n"
  135.     "    xfs help        | print this help message\r\n"
  136. #ifdef GNU_MALLOC
  137.     "    xfs stat        | show memory statistics\r\n"
  138. #endif
  139. #if TRACING
  140.     "    xfs debug        | enable/disable debug\r\n"
  141. #endif
  142.     "    xfs start        | start new file system\r\n"
  143.     "                | and read $XFSMODE\r\n"
  144.     "    xfs stop        | stop new file system\r\n"
  145.     "    xfs ln <new> <old>    | install a symbolic link\r\n"
  146.     "\n"
  147.     "    You should enable the file system with 'virgin 64'!\r\n"
  148.     "",
  149.     _XFS_VERSION,
  150.     1,
  151.     module_entries,
  152.     _MODUL_MAGIC,
  153.     _XBRA_MAGIC,
  154.     _MMX_MAGIC,
  155.     (xptr) 0,
  156.     _JMP_OPCODE,
  157.     dta_getname
  158. };
  159.  
  160. static char    dospath[FILENAME_MAX];
  161. static char    dospath2[FILENAME_MAX];
  162.  
  163. #define WRITE(f, text)    write(f, text, strlen(text))
  164.  
  165. #ifdef GNU_MALLOC
  166. /* Statistics available to the user.  */
  167. struct mstats
  168.   {
  169.     size_t bytes_total;        /* Total size of the heap. */
  170.     size_t chunks_used;        /* Chunks allocated by the user. */
  171.     size_t bytes_used;        /* Byte total of user-allocated chunks. */
  172.     size_t chunks_free;        /* Chunks in the free list. */
  173.     size_t bytes_free;        /* Byte total of chunks in the free list. */
  174.   };
  175.  
  176. /* Pick up the current statistics. */
  177. extern struct mstats mstats();
  178.  
  179. void
  180. memory_statistics()
  181. {
  182.     struct mstats    ms;
  183.     char    output[30];
  184.  
  185.     ms = mstats();
  186.     WRITE(1, "Memory-Statistics:\r\n\theapsize\t= ");
  187.     _ltoa(ms.bytes_total, output, 10);
  188.     WRITE(1, output);
  189.     WRITE(1, "\r\n\tchunks used\t= ");
  190.     _ltoa(ms.chunks_used, output, 10);
  191.     WRITE(1, output);
  192.     WRITE(1, "\r\n\tbytes used\t= ");
  193.     _ltoa(ms.bytes_used, output, 10);
  194.     WRITE(1, output);
  195.     WRITE(1, "\r\n\tchunks free\t= ");
  196.     _ltoa(ms.chunks_free, output, 10);
  197.     WRITE(1, output);
  198.     WRITE(1, "\r\n\tbytes free\t= ");
  199.     _ltoa(ms.bytes_free, output, 10);
  200.     WRITE(1, output);
  201.     write(1, "\r\n", 2);
  202. }
  203. #endif
  204.  
  205. #if TRACING
  206. /* use BIOS i/o for debugging output since we might get called from GEM */
  207. static short debugging = 0;
  208. static char output[80];
  209.  
  210. void
  211. Bconws(const char *str)
  212. {
  213.     if(!debugging) return;
  214.     while(*str) {
  215.         if(*str == '\n') Bconout(CON, '\r');
  216.         Bconout(CON, *str++);
  217.     }
  218. }
  219. #endif
  220.  
  221. #define DIR_MAGIC    0x4653    /* 'FS' */
  222. #define DIR_STRUCT    0
  223. #define SINGLE_FILE    1
  224.  
  225. struct Directory {
  226.     short    magic;
  227.     char    type;
  228.     unsigned char    search_attribute;
  229.     char    *path;
  230.     char    *pattern;
  231.     union {
  232.         DIR    *dir;
  233.         struct stat    *statbuf;
  234.     }    contents;
  235. };
  236.  
  237. static bool    dispatcher_active = 1;
  238.  
  239. /*
  240.  * The reserved part of the dta buffer is used to pass information
  241.  * from Fsfirst to Fsnext and dta_getname.
  242.  * The layout is as follows:
  243.  *
  244.  *   0     +--------+
  245.  *    | 'XFS1' | ---> validate information
  246.  *   4    +--------+
  247.  *    | DIRECT | ---> pointer to directory structure
  248.  *   8     +--------+
  249.  *    |     |    
  250.  *  12     +--------+
  251.  *    | OFFSET | ---> current position in directory
  252.  *  16    +--------+
  253.  *        :
  254.  *  43    +--------+
  255.  *    |   'x'  | ---> validate information
  256.  *  44    +--------+
  257.  *
  258.  * All other fields are unchanged.
  259.  */
  260.  
  261. char *
  262. dta_getname(struct _dta *dta)
  263. {
  264.     struct Directory    *dir;
  265.     off_t    dirpos;
  266.     struct dirent    *file;
  267.  
  268.     if(dispatcher_active & 1) return(dta->dta_name);
  269. #if TRACING
  270.     if(*((long *) &(dta->dta_buf[0])) != _MODUL_MAGIC) {
  271.         Bconws("dta_getname: magic num XFS1 not found\n");
  272.         goto go_out;
  273.     }
  274.     if(dta->dta_name[13] != 'x') {
  275.         Bconws("dta_getname: name[13] != 'x'\n");
  276.         goto go_out;
  277.     }
  278.     if(!(dir = *((struct Directory **) &(dta->dta_buf[4])))) {
  279.         Bconws("dta_getname: no Directory struct\n");
  280.         goto go_out;
  281.     }
  282.     if(dir->magic != DIR_MAGIC) {
  283.         Bconws("dta_getname: magic num FS not found\n");
  284.           go_out:
  285.         return(dta->dta_name);
  286.     }
  287. #else
  288.     if(*((long *) &(dta->dta_buf[0])) != _MODUL_MAGIC ||
  289.        (dta->dta_name[13] != 'x') ||
  290.        !(dir = *((struct Directory **) &(dta->dta_buf[4]))) ||
  291.        (dir->magic != DIR_MAGIC))
  292.         return(dta->dta_name);
  293. #endif
  294.     if(dir->type == SINGLE_FILE) return(dir->pattern);
  295.     dirpos = *((short *) &(dta->dta_buf[12]));
  296.     seekdir(dir->contents.dir, dirpos);
  297.     file = readdir(dir->contents.dir);
  298.     if(!file) return(dta->dta_name);
  299.     return(file->d_name);
  300. }
  301.  
  302. extern xptr    m_set_dtaname(void (*)());
  303. extern char    *m_getenv(const char *);
  304.  
  305. void
  306. start_xfs()
  307. {
  308.     char    *unixmode = m_getenv("XFSMODE");
  309.  
  310.     if(unixmode) _set_unixmode(unixmode);
  311.     else if(errno == EINVAL) _set_unixmode(_default_unixmode);
  312.     errno = ENOERR;
  313.     if(!dispatcher_active) return;
  314.     module_header.next = m_set_dtaname(_XBRA_VEC(module_header));
  315.     dispatcher_active = 0;
  316. }
  317.  
  318. void
  319. stop_xfs()
  320. {
  321.     if(dispatcher_active) return;
  322.     dispatcher_active = 1;
  323.     m_set_dtaname((void (*)()) module_header.next);
  324. }
  325.  
  326. long
  327. modul(const char *cmdlin)
  328. {
  329.     int    retval;
  330.  
  331.     if(!*cmdlin) {
  332.         return(0);
  333.     } else if(!strcmp(cmdlin, "help")) {
  334.         WRITE(1, module_header.module_description);
  335. #ifdef GNU_MALLOC
  336.     } else if(!strcmp(cmdlin, "stat")) {
  337.         memory_statistics();
  338. #endif
  339. #if TRACING
  340.     } else if(!strcmp(cmdlin, "debug")) {
  341.         debugging = !debugging;
  342. #endif
  343.     } else if(!strcmp(cmdlin, "start")) {
  344.         start_xfs();
  345.     } else if(!strcmp(cmdlin, "stop")) {
  346.         stop_xfs();
  347.     } else if(!strcmp(cmdlin, "ln")) {
  348.         char    *old, *new;
  349.  
  350.         strcpy(dospath, cmdlin);
  351.         new = strtok(dospath, " \t");
  352.         old = strtok(NULL, " \t");
  353.         if(!old || !new) return(1);
  354.         if(symlink(old, new)) {
  355.             retval = -errno;
  356.             errno = ENOERR;
  357.             return(retval);
  358.         }
  359.     }
  360.     return(0);
  361. }
  362.  
  363. struct head    *current;
  364.  
  365. static long    my_cookies[16] = {
  366.     _MODUL_MAGIC, (long) &module_header,
  367.     0L, 8L
  368. };
  369.  
  370. void
  371. remove_cookies()
  372. {
  373.     set_sysvar_to_long(_p_cookies, 0L);
  374. }
  375.  
  376. void
  377. remove_cookie()
  378. {
  379.     long    *cp;
  380.  
  381.     if(cp = (long *) get_sysvar(_p_cookies)) {
  382.         while(*cp && *cp != _MODUL_MAGIC) cp += 2;
  383.         while(*cp) {
  384.             cp[0] = cp[2];
  385.             cp[1] = cp[3];
  386.             cp += 2;
  387.         }
  388.     }
  389. }
  390.  
  391. #define SUPERBIT    (1L << 13)
  392. #define DCREATE        57
  393. #define DDELETE        58
  394. #define DSETPATH    59
  395. #define FCREATE        60
  396. #define FOPEN        61
  397. #define FCLOSE        62
  398. #define FREAD        63
  399. #define FWRITE        64
  400. #define FDELETE        65
  401. #define FSEEK        66
  402. #define FATTRIB        67
  403. #define FDUP        69
  404. #define FFORCE        70
  405. #define DGETPATH    71
  406. #define PEXEC        75
  407. #define FSFIRST        78
  408. #define FSNEXT        79
  409. #define FRENAME        86
  410. #define FDATIME        87
  411.  
  412. static long    trap1_dispatcher(char *);
  413. static long    new_trap1(long);
  414.  
  415. static xbra_struct    Trap1 = _TRAP_INIT(new_trap1);
  416.  
  417. static jmp_buf    oldTrap;
  418.  
  419. static long
  420. new_trap1(long arg)
  421. {
  422.     char    *sp;
  423.     register long    ret;
  424.  
  425.     if(dispatcher_active & 1) goto old_trap1;
  426.     /* ATTENTION: setjmp uses trap #1, so we have to disable this now */
  427.     dispatcher_active = 1;
  428.     if(setjmp(oldTrap)) {
  429.         dispatcher_active = 0;
  430.           old_trap1:
  431.         asm("movel %0, sp" :: "g" (&arg));
  432.         asm("jmp %0@" :: "a" (Trap1.next));
  433.     }
  434.     if(*((short *) &arg) & SUPERBIT) {
  435.         sp = ((char *) &arg) + 6;
  436.     } else {
  437.         asm("movel usp, %0" : "=a" (sp));
  438.     }
  439.     /* now sp points to our argument list */
  440.     ret = trap1_dispatcher(sp);
  441.     dispatcher_active = 0;
  442.     asm("movel %0, sp" :: "g" (&arg));
  443.     /* for the next asm to work,*/
  444.     /* ret should better not be */
  445.     /* addressed relative to sp */
  446.     asm("movel %0, d0" :: "d" (ret));
  447.     asm("rte");
  448. }
  449.  
  450. extern int    _unx2dos(const char * const, char * const); 
  451. extern int    _dos2unx(const char * const, char * const); 
  452.  
  453. #ifdef strcpy
  454. #undef strcpy
  455. #endif
  456.  
  457. extern DIR    *__opendir_chain;
  458.  
  459. static void
  460. xfs_closedir(struct Directory *dir)
  461. {
  462.     if(!dir || dir->magic != DIR_MAGIC) return;
  463.     free(dir->path);
  464.     free(dir->pattern);
  465.     if(dir->type == SINGLE_FILE) free(dir->contents.statbuf);
  466.     else closedir(dir->contents.dir);
  467. }
  468.  
  469. static inline struct Directory *
  470. xfs_opendir(const char *path, struct Directory *old_dir)
  471. {
  472.     char    *pattern;
  473.     struct Directory    *dd;
  474.     struct stat    *st;
  475.  
  476.     if((!(dd = old_dir) || (old_dir->magic != DIR_MAGIC)) &&
  477.        !(dd = malloc((size_t)sizeof(struct Directory)))) {
  478.         errno = ENOMEM;
  479.         return NULL;
  480.     }
  481.     strcpy(dospath, path);
  482.     do {
  483.         if(!(pattern = strrchr(dospath, '\\')) &&
  484.            !(pattern = strrchr(dospath, '/'))) {
  485.             pattern = dospath;
  486.         } else {
  487.             *pattern++ = '\0';
  488.         }
  489.     } while(pattern != dospath && !*pattern);
  490. #ifdef CACHE_DIR
  491.     /* this cacheing of open directories is problematic, since */
  492.     /* deleted files will still be listed */
  493.     if((dd == old_dir) && !strcmp(dospath, dd->path)
  494.        && !strcmp(pattern, dd->pattern)) {
  495.         if(dd->type == DIR_STRUCT) rewinddir(dd->contents.dir);
  496.         return(dd);
  497.     } else
  498. #endif
  499.         xfs_closedir(old_dir);
  500.     dd->magic = DIR_MAGIC;
  501.     dd->path = strdup(dospath);
  502.     dd->pattern = strdup(pattern);
  503. #ifdef USE_GLOB
  504.     /* look for glob-metacharacters in pattern */
  505.     if(glob(pattern, "*[*?[\\]{}]*"))
  506. #else
  507.     if(!strcmp(pattern, "*.*"))
  508. #endif
  509.     {
  510.         if(pattern == dospath) strcpy(dospath, ".");
  511.         if(!*dospath) strcpy(dospath, "\\");
  512.         dd->type = DIR_STRUCT;
  513.         if(!(dd->contents.dir = opendir(dospath))) {
  514.             xfs_closedir(dd);
  515.             free(dd);
  516.             return(NULL);
  517.         }
  518.     } else {
  519. #ifndef USE_GLOB
  520.         /* FIXME: for now assume that pattern is either *.* or */
  521.         /* a normal filename (exclude things like a*.b), could */
  522.         /* be done with glob()                       */
  523. #endif
  524.         dd->type = SINGLE_FILE;
  525.         if(!(st = malloc((size_t)sizeof(struct stat)))) {
  526.             errno = ENOMEM;
  527.             free(dd->path);
  528.             free(dd->pattern);
  529.             free(dd);
  530.             return NULL;
  531.         }
  532.         dd->contents.statbuf = st;
  533.         if(pattern != dospath) pattern[-1] = '\\';
  534.         if(stat(dospath, st) < 0) {
  535.             errno = ENOENT;
  536.             xfs_closedir(dd);
  537.             return NULL;
  538.         }
  539.     }
  540.     return(dd);
  541. }
  542.  
  543. static dev_t    forced_standard_handle[3];
  544.  
  545. static long
  546. trap1_dispatcher(char *sp)
  547. {
  548.     long    ret;
  549.     int    save_errno;
  550.     char    *path;
  551.     char    save_tSLASH;
  552.     struct _device    *device;
  553.     struct _dta    *dtabuf;
  554.  
  555.     save_errno = errno;
  556.     errno = ENOERR;
  557.     path = *((char **) &sp[2]);
  558.     switch(*((short *) sp)) {
  559.           case DCREATE :
  560.               ret = mkdir(path);
  561.               break;
  562.           case DDELETE :
  563.               ret = rmdir(path);
  564.               break;
  565.           case DSETPATH :
  566.               ret = chdir(path);
  567.               break;
  568.           case FCREATE :
  569.               ret = creat(path, 0644);
  570.               break;    /* does not support file modes */
  571.           case FOPEN :
  572.               ret = open(path, *((short *) &sp[6]));
  573.               break;
  574.           case FCLOSE : {
  575.               short    fd;
  576.  
  577.               fd = *((short *) &sp[2]);
  578.               if(fd >= 0 && fd <= 2 && forced_standard_handle[fd])
  579.                   fd = forced_standard_handle[fd];
  580.               ret = close(fd);
  581.               break;
  582.           }
  583.           case FREAD : {
  584.               short    fd;
  585.  
  586.               fd = *((short *) &sp[2]);
  587.               if(fd >= 0 && fd <= 2 && forced_standard_handle[fd])
  588.                   fd = forced_standard_handle[fd];
  589.               ret = read(fd, *((void **) &sp[8]), *((long *) &sp[4]));
  590.               break;
  591.           }
  592.           case FWRITE : {
  593.               short    fd;
  594.  
  595.               fd = *((short *) &sp[2]);
  596.               if(fd >= 0 && fd <= 2 && forced_standard_handle[fd])
  597.                   fd = forced_standard_handle[fd];
  598.               ret = write(fd, *((void **) &sp[8]), *((long *) &sp[4]));
  599.               break;
  600.           }
  601.           case FDELETE :    /* may get trouble if file is open */
  602.               ret = unlink(path);
  603.               break;
  604.           case FSEEK : {
  605.               short    fd;
  606.  
  607.               fd = *((short *) &sp[2]);
  608.               if(fd >= 0 && fd <= 2 && forced_standard_handle[fd])
  609.                   fd = forced_standard_handle[fd];
  610.               ret = lseek(*((short *) &sp[6]), fd,
  611.                   *((short *) &sp[8]));
  612.               break;
  613.           }
  614.           case FATTRIB :
  615.               _unx2dos(path, dospath);
  616.               *((char **) &sp[2]) = dospath;
  617.               goto do_old_trap;
  618.           case FDUP : {
  619.               short    fd;
  620.  
  621.               fd = *((short *) &sp[2]);
  622.               if(fd >= 0 && fd <= 2 &&
  623.              (ret = forced_standard_handle[fd])) break;
  624.               goto do_old_trap;
  625.           }
  626.           case FFORCE : {
  627.               short    std_fd = *((short *) &sp[2]);
  628.               short    nstd_fd = *((short *) &sp[4]);
  629.  
  630.               if(std_fd == 0) {
  631.                   if((device = _dev_devnum(nstd_fd)) &&
  632.                  device->d_read) {
  633.                       forced_standard_handle[0] = nstd_fd;
  634.                       ret = 0;
  635.                       break;
  636.                   } else {
  637.                       forced_standard_handle[0] = 0;
  638.                       goto do_old_trap;
  639.                   }
  640.               } else if(std_fd == 1 || std_fd == 2) {
  641.                   if((device = _dev_devnum(nstd_fd)) &&
  642.                  device->d_write) {
  643.                       forced_standard_handle[std_fd] = nstd_fd;
  644.                       ret = 0;
  645.                       break;
  646.                   } else {
  647.                       forced_standard_handle[std_fd] = 0;
  648.                       goto do_old_trap;
  649.                   }
  650.               }
  651.               goto do_old_trap;
  652.           }
  653.           case DGETPATH : {
  654.               short    drive;
  655.               short    save_drive;
  656.  
  657.               drive = *((short *) &sp[6]);
  658.               if (!drive) dospath[0] = Dgetdrv() + 'A';
  659.               else dospath[0] = drive - 1 + 'A';
  660.               dospath[1] = ':';
  661.               ret = Dgetpath(dospath+2, drive);
  662.               save_tSLASH = _tSLASH;
  663.               _tSLASH = 0;
  664.               _dos2unx(dospath, dospath2);
  665.               _tSLASH = save_tSLASH;
  666.               if (dospath2[0] && dospath2[1] == ':')
  667.                   strcpy(path, dospath2+2);
  668.               else
  669.                   strcpy(path, dospath2);
  670.               break;
  671.           }
  672.           case PEXEC : {
  673.               char    *path;
  674.  
  675.               path = *((char **) &sp[4]);
  676.               _unx2dos(path, dospath);
  677.               *((char **) &sp[4]) = dospath;
  678.               goto do_old_trap;
  679.           }
  680.           case FSFIRST : {
  681.               struct Directory    *dir;
  682.  
  683.               if((*path == '\345') || (*((short *) &sp[6]) & 0x08))
  684.                   goto do_old_trap;
  685.               dtabuf = (struct _dta *) Fgetdta();
  686.               if(*((long *) &(dtabuf->dta_buf[0])) == _MODUL_MAGIC)
  687.                   dir = *((struct Directory **)
  688.                       &(dtabuf->dta_buf[4]));
  689.               else dir = NULL;
  690.               if(!(dir = xfs_opendir(path, dir))) break;
  691.               dir->search_attribute = (*((short *) &sp[6]) | 0x21)
  692.                   & 0xFF;
  693.               dtabuf = (struct _dta *) Fgetdta();
  694.               *((long *) &(dtabuf->dta_buf[0])) = _MODUL_MAGIC;
  695.               *((struct Directory **) &(dtabuf->dta_buf[4])) = dir;
  696.               if(dir->type == DIR_STRUCT)
  697.                   *((long *) &(dtabuf->dta_buf[12])) =
  698.                       telldir(dir->contents.dir);
  699.           }
  700.           case FSNEXT : {
  701.               struct Directory    *dir;
  702.               long    dirpos;
  703.  
  704.               dtabuf = (struct _dta *) Fgetdta();
  705.               if(*((long *) &(dtabuf->dta_buf[0])) != _MODUL_MAGIC) {
  706. #if TRACING
  707.                   Bconws("Fsnext: magic num XFS1 not found\n");
  708. #endif
  709.                   errno = EINVAL;
  710.                   break;
  711.               }
  712.               dir = *((struct Directory **) &(dtabuf->dta_buf[4]));
  713.               if(!dir || (dir->magic != DIR_MAGIC)) {
  714. #if TRACING
  715.                   Bconws("Fsnext: directory struct invalid\n");
  716. #endif
  717.                   errno = EINVAL;
  718.                   break;
  719.               }
  720.               if(dir->type == SINGLE_FILE) {
  721.                   union {
  722.                       DOSTIME    dt;
  723.                       time_t    tt;
  724.                   } ft;
  725.                   
  726.                   path = dir->pattern;
  727.                   ft.tt = dostime(dir->contents.statbuf->st_mtime);
  728.                   dtabuf->dta_attribute =
  729.                       dir->contents.statbuf->st_attr;
  730.                   dtabuf->dta_time = ft.dt.time;
  731.                   dtabuf->dta_date = ft.dt.date;
  732.                   dtabuf->dta_size =
  733.                       dir->contents.statbuf->st_size;
  734.               } else {
  735.                   struct dirent    *file;
  736.               
  737.                   if(!dir->contents.dir) {
  738. #if TRACING
  739.                       Bconws("Fsnext: DIR not open\n");
  740. #endif
  741.                       errno = EINVAL;
  742.                       break;
  743.                   }
  744.                   dirpos = *((short *) &(dtabuf->dta_buf[14]));
  745.                   if(dirpos != telldir(dir->contents.dir))
  746.                       seekdir(dir->contents.dir, dirpos);
  747. #ifdef USE_GLOB
  748.                   do {
  749. #endif
  750.                       file = readdir(dir->contents.dir);
  751. #ifdef USE_GLOB
  752.                   /* we try as long as we have a valid */
  753.                   /* file, but no matching file        */
  754.                   } while(
  755.                       file
  756.                       && !(
  757. /* a matching file would be any file */
  758. /* with attribute 0 or an attribute  */       (!file->d_attribute
  759. /* matching the search attribute and */     || (file->d_attribute &
  760.                         dir->search_attribute))
  761. /* a name matching the searchpattern */    && (!strcmp(dir->pattern, "*.*") ||
  762.                            glob(file->d_name, dir->pattern)
  763.                            )
  764.                        )
  765.                       );
  766. #endif
  767.                   if(!file) {
  768.                       errno = ENMFILES;
  769.                       break;
  770.                   }
  771.                   path = file->d_name;
  772.                   dtabuf->dta_attribute = file->d_attribute;
  773.                   dtabuf->dta_time = file->d_time;
  774.                   dtabuf->dta_date = file->d_date;
  775.                   dtabuf->dta_size = file->d_size;
  776.               }
  777.               if(!strcmp(path, ".") || !strcmp(path, "..")) {
  778.                   strcpy(dtabuf->dta_name, path);
  779.               } else {
  780.                   _unx2dos(path, dospath);
  781.                   strcpy(dtabuf->dta_name,
  782.                      strrchr(dospath, '\\') + 1);
  783.               }
  784.               *((long *) &(dtabuf->dta_buf[0])) = _MODUL_MAGIC;
  785.               *((struct Directory **) &(dtabuf->dta_buf[4])) = dir;
  786.               if(dir->type == DIR_STRUCT) {
  787.                   dirpos = (dirpos << 16) |
  788.                       telldir(dir->contents.dir) & 0x0000FFFFL;
  789.                   /* offset 12 used to make st_inode() happy */
  790.                   *((long *) &(dtabuf->dta_buf[12])) = dirpos;
  791.               }
  792.               dtabuf->dta_name[13] = 'x';
  793.               ret = 0;
  794.               errno = ENOERR;
  795.               break;
  796.           }
  797.           case FRENAME :
  798.               ret = rename(path, *((char **) &sp[6]));
  799.               break;
  800.           default :
  801. do_old_trap:          errno = save_errno;
  802.               longjmp(oldTrap, 1);
  803.     }
  804.     if(errno) ret = - errno;
  805.     errno = save_errno;
  806.     return(ret);
  807. }
  808.  
  809. #define TRAP1    33
  810.  
  811. void
  812. init_module(void)
  813. {
  814.     signal(SIGINT, SIG_IGN);
  815.     signal(SIGQUIT, SIG_IGN);
  816.     signal(SIGTSTP, SIG_IGN);
  817.     Trap1.gnuc_magic = _MODUL_MAGIC;
  818.     Trap1.next = (xptr) Setexc(TRAP1, _TRAP_VEC(TRAP1, Trap1));
  819. }
  820.  
  821. void
  822. finish_module(void)
  823. {
  824.     stop_xfs();
  825.     unlink_handler(&Trap1, TRAP1);
  826. }
  827.  
  828. void
  829. install_cookie(int resident)
  830. {
  831.     long    *cp;
  832.     long    cookies_used = 0;
  833.     long    tmp;
  834.  
  835.     if(!(cp = (long *) get_sysvar(_p_cookies))) {
  836.         if(!resident) {
  837.             write(2, "Unable to install cookie!\r\n", 27);
  838.             exit(1);
  839.         }
  840.         signal(SIGRESET, remove_cookies);
  841.         set_sysvar_to_long(_p_cookies, (long)(cp = my_cookies));
  842.     }
  843.     while(*cp && *cp != _MODUL_MAGIC) {
  844.         cp += 2;
  845.         cookies_used++;
  846.     }
  847.     if(*cp) {
  848.         current = (struct head *) cp[1];
  849.         if(current == &module_header) init_module();
  850.         return;
  851.     }
  852.     if(!(cp[1] - cookies_used - 1)) {
  853.         write(2, "No room for cookie!\r\n", 21);
  854.         exit(1);
  855.     }
  856.     *cp++ = _MODUL_MAGIC;
  857.     tmp = *cp;
  858.     *cp++ = (long) (current = &module_header);
  859.     *cp++ = 0L;
  860.     *cp = tmp;
  861.     init_module();
  862.     return;
  863. }
  864.  
  865. void
  866. install_module(int resident, char *firstcmd)
  867. {
  868.     long    keep;
  869.  
  870.     install_cookie(resident);
  871.     if(master) {
  872.         strcpy(master_var, "Master-Module ");
  873.         _ltoa(current, master_var+14, 10);
  874.     }
  875.     if(current != &module_header) {
  876.         (*(current->jump_table[0].function_entry))(firstcmd);
  877.         exit(0);
  878.     }
  879.     if(!*firstcmd) modul("help");
  880.     else modul(firstcmd);
  881.     if(!resident) return;
  882.     keep = _base->p_tlen + _base->p_dlen + _base->p_blen
  883.         + sizeof(BASEPAGE) + _initial_stack;
  884.     _base -= 2;
  885.     Ptermres(keep, 0);
  886. }
  887.  
  888. void
  889. remove_module()
  890. {
  891.     finish_module();
  892.     remove_cookie();
  893. }
  894.  
  895. void
  896. usage(char *prog)
  897. {
  898.     write(2, "Usage: [ module ] ", 18);
  899.     WRITE(2, prog);
  900.     write(2, " [ <cmd> ]\r\n", 12);
  901.     exit(2);
  902. }
  903.  
  904. main(int argc, char *argv[])
  905. {
  906.     char    *mmx;
  907.     BASEPAGE    *caller;
  908.     char    *prog;
  909.     char    *firstcmd;
  910.  
  911.     if(**argv) prog = *argv;
  912.     else prog = "xfs";
  913.     argc--;
  914.     argv++;
  915.     if(argc) {
  916.         firstcmd = *argv;
  917.         argc--;
  918.         argv++;
  919.     } else firstcmd = "";
  920.     if(argc) usage(prog);
  921.     if(mmx = getenv("MMX")) {
  922.         if(strncmp(mmx, "Master-Call", 11)) exit(1);
  923.         mmx += 11;
  924.         if(!(master = (BASEPAGE *) strtol(mmx, &mmx, 10)) ||
  925.            !(master_var = (char *) strtol(mmx, &mmx, 10)) ||
  926.            !(caller = (BASEPAGE *) strtol(mmx, &mmx, 10)) ||
  927.            (caller != _base->p_parent))
  928.             exit(1);
  929.         install_module(1, firstcmd);
  930.     } else if(!system(NULL)) install_module(1, firstcmd);
  931.     install_module(0, firstcmd);
  932.     system("-i");
  933.     remove_module();
  934. }
  935.