home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD1.iso / Emulatoren / UAE061.LZH / uae-0.6.1 / filesys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  36.8 KB  |  1,703 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Unix file system handler for AmigaDOS
  5.   *
  6.   * (c) 1996 Ed Hanway
  7.   *
  8.   * Version 0.1: 28-Jan-1996
  9.   *
  10.   * Based on example code (c) 1988 The Software Distillery
  11.   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
  12.   * (May - August 1989)
  13.   *
  14.   * Known limitations:
  15.   * Does not support ACTION_INHIBIT (big deal).
  16.   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
  17.   * Does not actually enforce exclusive locks.
  18.   * Does not support removable volumes.
  19.   * May not return the correct error code in some cases.
  20.   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
  21.   * if passed garbage values.
  22.   *
  23.   * TODO someday:
  24.   * Support booting.
  25.   * Implement real locking using flock.  Needs test cases.
  26.   */
  27.  
  28. #include "sysconfig.h"
  29. #include "sysdeps.h"
  30.  
  31. #include "config.h"
  32. #include "options.h"
  33. #include "memory.h"
  34. #include "custom.h"
  35. #include "newcpu.h"
  36. #include "xwin.h"
  37. #include "autoconf.h"
  38. #include "filesys.h"
  39.  
  40. #define MAKE_CASE_INSENSITIVE
  41.  
  42. typedef struct {
  43.     char *devname; /* device name, e.g. UAE0: */
  44.     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
  45.     char *rootdir; /* root unix directory */
  46.     int readonly; /* disallow write access? */
  47. } UnitInfo;
  48.  
  49. #define MAX_UNITS 20
  50. static int num_units = 0;
  51. static UnitInfo ui[MAX_UNITS];
  52.  
  53. static ULONG devnameaddr[100];
  54.  
  55. static ULONG doslibname, fsdevname, filesysseglist;
  56.  
  57. void
  58. add_filesys_unit(char *volname, char *rootdir, int readonly)
  59. {
  60.     UnitInfo* u;
  61.     static char buf[80];
  62.  
  63.     if (num_units >= MAX_UNITS) {
  64.     fprintf(stderr, "Maximum number of unix file systems mounted.\n");
  65.     return;
  66.     }
  67.  
  68.     u = &ui[num_units];
  69.     sprintf(buf, "UAE%d", num_units);
  70.     u->devname = my_strdup(buf);
  71.     u->volname = my_strdup(volname);
  72.     u->rootdir = my_strdup(rootdir);
  73.     u->readonly = readonly;
  74.  
  75.     num_units++;
  76. }
  77.  
  78. #ifdef TRACING_ENABLED
  79. #define TRACE(x)    printf x;
  80. #define DUMPLOCK(x)    dumplock(x)
  81. #else
  82. #define TRACE(x)
  83. #define DUMPLOCK(x)
  84. #endif
  85.  
  86. /* minimal AmigaDOS definitions */
  87.  
  88. /* field offsets in DosPacket */
  89. #define dp_Type (8)
  90. #define dp_Res1    (12)
  91. #define dp_Res2 (16)
  92. #define dp_Arg1 (20)
  93. #define dp_Arg2 (24)
  94. #define dp_Arg3 (28)
  95. #define dp_Arg4 (32)
  96.  
  97. /* result codes */
  98. #define DOS_TRUE (-1L)
  99. #define DOS_FALSE (0L)
  100.  
  101. /* packet types */
  102. #define ACTION_CURRENT_VOLUME    7
  103. #define ACTION_LOCATE_OBJECT    8
  104. #define ACTION_RENAME_DISK    9
  105. #define ACTION_FREE_LOCK    15
  106. #define ACTION_DELETE_OBJECT    16
  107. #define ACTION_RENAME_OBJECT    17
  108. #define ACTION_COPY_DIR        19
  109. #define ACTION_SET_PROTECT    21
  110. #define ACTION_CREATE_DIR    22
  111. #define ACTION_EXAMINE_OBJECT    23
  112. #define ACTION_EXAMINE_NEXT    24
  113. #define ACTION_DISK_INFO    25
  114. #define ACTION_INFO        26
  115. #define ACTION_FLUSH        27
  116. #define ACTION_SET_COMMENT    28
  117. #define ACTION_PARENT        29
  118. #define ACTION_SET_DATE        34
  119. #define ACTION_SAME_LOCK    40
  120. #define ACTION_FIND_WRITE    1004
  121. #define ACTION_FIND_INPUT    1005
  122. #define ACTION_FIND_OUTPUT    1006
  123. #define ACTION_END        1007
  124. #define ACTION_SEEK        1008
  125. #define ACTION_IS_FILESYSTEM    1027
  126. #define ACTION_READ        'R'
  127. #define ACTION_WRITE        'W'
  128.  
  129. #define DISK_TYPE        (0x444f5301) /* DOS\1 */
  130.  
  131. /* errors */
  132. #define ERROR_NO_FREE_STORE     103
  133. #define ERROR_OBJECT_IN_USE    202
  134. #define ERROR_OBJECT_EXISTS     203
  135. #define ERROR_DIR_NOT_FOUND     204
  136. #define ERROR_OBJECT_NOT_FOUND  205
  137. #define ERROR_ACTION_NOT_KNOWN  209
  138. #define ERROR_OBJECT_WRONG_TYPE 212
  139. #define ERROR_DISK_WRITE_PROTECTED 214
  140. #define ERROR_DIRECTORY_NOT_EMPTY 216
  141. #define ERROR_DEVICE_NOT_MOUNTED 218
  142. #define ERROR_SEEK_ERROR    219
  143. #define ERROR_DISK_FULL        221
  144. #define ERROR_WRITE_PROTECTED 223
  145. #define ERROR_NO_MORE_ENTRIES  232
  146. #define ERROR_NOT_IMPLEMENTED    236
  147.  
  148. static long dos_errno(void)
  149. {
  150.     int e = errno;
  151.  
  152.     switch(e) {
  153.      case ENOMEM:    return ERROR_NO_FREE_STORE;
  154.      case EEXIST:    return ERROR_OBJECT_EXISTS;
  155.      case EACCES:    return ERROR_WRITE_PROTECTED;
  156.      case ENOENT:    return ERROR_OBJECT_NOT_FOUND;
  157.      case ENOTDIR:    return ERROR_OBJECT_WRONG_TYPE;
  158.      case ENOSPC:    return ERROR_DISK_FULL;
  159.      case EBUSY:           return ERROR_OBJECT_IN_USE;
  160.      case EISDIR:    return ERROR_OBJECT_WRONG_TYPE;
  161. #if !defined(__bebox__) && !defined(__DOS__)
  162.      case ETXTBSY:    return ERROR_OBJECT_IN_USE;
  163. #endif
  164.      case EROFS:           return ERROR_DISK_WRITE_PROTECTED;
  165.      case ENOTEMPTY:    return ERROR_DIRECTORY_NOT_EMPTY;
  166.  
  167.      default:
  168.     TRACE(("Unimplemented error %s\n", strerror(e)));
  169.     return ERROR_NOT_IMPLEMENTED;
  170.     }
  171. }
  172.  
  173. /* handler state info */
  174.  
  175. typedef struct _unit {
  176.     struct _unit *next;
  177.  
  178.     /* Amiga stuff */
  179.     CPTR    dosbase;
  180.     CPTR    volume;
  181.     CPTR    port;    /* Our port */
  182.  
  183.     /* Native stuff */
  184.     long    unit;    /* unit number */
  185.     UnitInfo    ui;    /* unit startup info */
  186. } Unit;
  187.  
  188. typedef struct {
  189.     CPTR addr; /* addr of real packet */
  190.     long type;
  191.     long res1;
  192.     long res2;
  193.     long arg1;
  194.     long arg2;
  195.     long arg3;
  196.     long arg4;
  197. } DosPacket;
  198.  
  199. static char *
  200. bstr(CPTR addr)
  201. {
  202.     static char buf[256];
  203.     int n = get_byte(addr++);
  204.     int i;
  205.     for(i = 0; i < n; i++)
  206.     buf[i] = get_byte(addr++);
  207.     buf[i] = 0;
  208.     return buf;
  209. }
  210.  
  211. static Unit *units = NULL;
  212. static int unit_num = 0;
  213.  
  214. static Unit*
  215. find_unit(CPTR port)
  216. {
  217.     Unit* u;
  218.     for(u = units; u; u = u->next)
  219.     if(u->port == port)
  220.         break;
  221.  
  222.     return u;
  223. }
  224.  
  225. static CPTR DosAllocMem(ULONG len)
  226. {
  227.     ULONG i;
  228.     CPTR addr;
  229.  
  230.     regs.d[0] = len + 4;
  231.     regs.d[1] = 1; /* MEMF_PUBLIC */
  232.     addr = CallLib(regs.a[6], -198); /* AllocMem */
  233.  
  234.     if(addr) {
  235.     put_long(addr, len);
  236.     addr += 4;
  237.  
  238.     /* faster to clear memory here rather than use MEMF_CLEAR */
  239.     for(i = 0; i < len; i += 4)
  240.         put_long(addr + i, 0);
  241.     }
  242.  
  243.     return addr;
  244. }
  245.  
  246. static void DosFreeMem(CPTR addr)
  247. {
  248.     addr -= 4;
  249.     regs.d[0] = get_long(addr) + 4;
  250.     regs.a[1] = addr;
  251.     CallLib(regs.a[6], -210); /* FreeMem */
  252. }
  253.  
  254. static void
  255. startup(DosPacket* packet)
  256. {
  257.     int i, namelen;
  258.     char* devname = bstr(packet->arg1 << 2);
  259.     char* s;
  260.     Unit* unit;
  261.  
  262.     /* find UnitInfo with correct device name */
  263.     s = strchr(devname, ':');
  264.     if(s) *s = '\0';
  265.  
  266.     if (num_units > 1)
  267.     for(i = 0; i < num_units; i++) {
  268.         if(0 == strcmp(ui[i].devname, devname))
  269.         break;
  270.     }
  271.     else
  272.     i = 0;
  273.  
  274.     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
  275.     fprintf(stderr, "Failed attempt to mount device %s\n", devname);
  276.     packet->res1 = DOS_FALSE;
  277.     packet->res2 = ERROR_DEVICE_NOT_MOUNTED;
  278.     return;
  279.     }
  280.  
  281.     unit = (Unit *) malloc(sizeof(Unit));
  282.     unit->next = units;
  283.     units = unit;
  284.  
  285.     unit->volume = 0;
  286.     unit->port = regs.a[5];
  287.     unit->unit = unit_num++;
  288.  
  289.     unit->ui.devname = ui[i].devname;
  290.     unit->ui.volname = my_strdup(ui[i].volname); /* might free later for rename */
  291.     unit->ui.rootdir = ui[i].rootdir;
  292.     unit->ui.readonly = ui[i].readonly;
  293.  
  294.     TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
  295.  
  296.     /* fill in our process in the device node */
  297.     put_long((packet->arg3 << 2) + 8, unit->port);
  298.  
  299.     /* open dos.library */
  300.     regs.d[0] = 0;
  301.     regs.a[1] = doslibname;
  302.     unit->dosbase = CallLib(regs.a[6], -552); /* OpenLibrary */
  303.  
  304.     {
  305.     CPTR rootnode = get_long(unit->dosbase + 34);
  306.     CPTR dos_info = get_long(rootnode + 24) << 2;
  307.     /* make new volume */
  308.     unit->volume = DosAllocMem(80 + 1 + 44);
  309.     put_long(unit->volume + 4, 2); /* Type = dt_volume */
  310.     put_long(unit->volume + 12, 0); /* Lock */
  311.     put_long(unit->volume + 16, 3800); /* Creation Date */
  312.     put_long(unit->volume + 20, 0);
  313.     put_long(unit->volume + 24, 0);
  314.     put_long(unit->volume + 28, 0); /* lock list */
  315.     put_long(unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
  316.     namelen = strlen(unit->ui.volname);
  317.     put_byte(unit->volume + 44, namelen);
  318.     for(i = 0; i < namelen; i++)
  319.         put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  320.     
  321.     /* link into DOS list */
  322.     put_long(unit->volume, get_long(dos_info + 4));
  323.     put_long(dos_info + 4, unit->volume >> 2);
  324.     }
  325.     
  326.     put_long(unit->volume + 8, unit->port);
  327.     put_long(unit->volume + 32, DISK_TYPE);
  328.  
  329.     packet->res1 = DOS_TRUE;
  330. }
  331.  
  332. #ifdef HAVE_STATFS
  333. static void
  334. do_info(Unit* unit, DosPacket* packet, CPTR info)
  335. {
  336.     struct statfs statbuf;
  337. #if STATFS_NO_ARGS == 2
  338.     if(-1 == statfs(unit->ui.rootdir, &statbuf))
  339. #else
  340.     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
  341. #endif
  342.     {
  343.     packet->res1 = DOS_FALSE;
  344.     packet->res2 = dos_errno();
  345.     }
  346.  
  347.     put_long(info, 0); /* errors */
  348.     put_long(info + 4, unit->unit); /* unit number */
  349.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  350.     put_long(info + 12, statbuf.f_blocks); /* numblocks */
  351.     put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */
  352.     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
  353.     put_long(info + 24, DISK_TYPE); /* disk type */
  354.     put_long(info + 28, unit->volume >> 2); /* volume node */
  355.     put_long(info + 32, 0); /* inuse */
  356.     packet->res1 = DOS_TRUE;
  357. }
  358. #else
  359. static void
  360. do_info(Unit* unit, DosPacket* packet, CPTR info)
  361. {
  362.     put_long(info, 0); /* errors */
  363.     put_long(info + 4, unit->unit); /* unit number */
  364.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  365.     put_long(info + 12, 256); /* numblocks */
  366.     put_long(info + 16, 128); /* inuse */
  367.     put_long(info + 20, 512); /* bytesperblock */
  368.     put_long(info + 24, DISK_TYPE); /* disk type */
  369.     put_long(info + 28, unit->volume >> 2); /* volume node */
  370.     put_long(info + 32, 0); /* inuse */
  371.     packet->res1 = DOS_TRUE;
  372. }
  373. #endif
  374.  
  375. static void
  376. action_disk_info(Unit* unit, DosPacket* packet)
  377. {
  378.     TRACE(("ACTION_DISK_INFO\n"));
  379.     do_info(unit, packet, packet->arg1 << 2);
  380. }
  381.  
  382. static void
  383. action_info(Unit* unit, DosPacket* packet)
  384. {
  385.     TRACE(("ACTION_INFO\n"));
  386.     do_info(unit, packet, packet->arg2 << 2);
  387. }
  388.  
  389. typedef struct key {
  390.     struct key *next;
  391.     ULONG uniq;
  392.     char *path;
  393.     int fd;
  394. } Key;
  395.  
  396. static struct key* keys = NULL;
  397.  
  398. static void
  399. free_key(Key*k)
  400. {
  401.     Key *k1;
  402.     Key *prev = NULL;
  403.     for(k1 = keys; k1; k1 = k1->next) {
  404.         if(k == k1) {
  405.             if(prev)
  406.                 prev->next = k->next;
  407.             else
  408.                 keys = k->next;
  409.             break;
  410.         }
  411.         prev = k1;
  412.     }
  413.  
  414.     if (k->fd >= 0)
  415.     close(k->fd);
  416.     free(k->path);
  417.     free(k);
  418. }
  419.  
  420. static Key*
  421. lookup_key(ULONG uniq)
  422. {
  423.     Key *k;
  424.     for(k = keys; k; k = k->next) {
  425.         if(uniq == k->uniq)
  426.             return k;
  427.     }
  428.     fprintf(stderr, "Error: couldn't find key %ld\n", uniq);
  429.     exit(1);
  430.     /* NOTREACHED */
  431.     return NULL;
  432. }
  433.  
  434. static Key*
  435. new_key(void)
  436. {
  437.     static ULONG uniq = 0;
  438.     Key *k = (Key*) malloc(sizeof(Key));
  439.     k->uniq = ++uniq;
  440.     k->fd = -1;
  441.  
  442.     k->next = keys;
  443.     keys = k;
  444.  
  445.     return k;
  446. }
  447.  
  448. static void
  449. dumplock(CPTR lock)
  450. {
  451.     if(!lock) {
  452.     fprintf(stderr, "LOCK: 0x0\n");
  453.     return;
  454.     }
  455.     fprintf(stderr,
  456.         "LOCK: 0x%lx { next=0x%lx, key=%s, mode=%ld, handler=0x%lx, volume=0x%lx }\n",
  457.         lock,
  458.         get_long(lock)<<2, lookup_key(get_long(lock+4))->path, get_long(lock+8),
  459.         get_long(lock+12), get_long(lock+16));
  460. }
  461.  
  462. static char*
  463. get_path(Unit* unit, const char *base, const char *rel)
  464. {
  465.     static char buf[1024];
  466.     char *s = buf;
  467.     char *p;
  468.     char *r;
  469.  
  470.     int i;
  471.  
  472.     TRACE(("get_path(%s,%s)\n", base, rel));
  473.  
  474.     /* root-relative path? */
  475.     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++);
  476.     if(':' == rel[i]) {
  477.     /*base = unit->ui.rootdir;*/ rel += i+1;
  478.     }
  479.  
  480.     while(*base) {
  481.     *s++ = *base++;
  482.     }
  483.     *s = 0;
  484.     p = s; /* start of relative path */
  485.     r = buf + strlen(unit->ui.rootdir); /* end of fixed path */
  486.  
  487.     while(*rel) {
  488.     /* start with a slash? go up a level. */
  489.     if('/' == *rel) {
  490.         while(s > r && '/' != *s)
  491.         s--;
  492.         *s = 0;
  493.         rel++;
  494.     } else {
  495.         *s++ = '/';
  496.         while(*rel && '/' != *rel) {
  497.         *s++ = *rel++;
  498.         }
  499.         *s = 0;
  500.         if('/' == *rel)
  501.         rel++;
  502.     }
  503.     }
  504.     *s = 0;
  505.  
  506. #ifdef MAKE_CASE_INSENSITIVE
  507.     TRACE(("path=\"%s\"\n", buf));
  508.     /* go through each section of the path and if it does not exist,
  509.      * scan its directory for any case insensitive matches
  510.      */
  511.     while(*p) {
  512.     char *p2 = strchr(p+1, '/');
  513.     char oldp2;
  514.     if(!p2) {
  515.         p2 = p+1;
  516.         while(*p2) p2++;
  517.     }
  518.     oldp2 = *p2;
  519.     *p2 = '\0';
  520.     if(0 != access(buf, F_OK|R_OK)) {
  521.         DIR* dir;
  522.         struct dirent* de;
  523.         /* does not exist -- check dir for case insensitive match */
  524.         *p++ = '\0'; /* was '/' */
  525.         dir = opendir(buf);
  526.         if (dir) {
  527.         while((de = readdir(dir))) {
  528. #if 0
  529.             if(0 == stricmp(de->d_name, p))    /* OLSEN */
  530. #endif
  531.             if(0 == strcasecmp(de->d_name, p))
  532.             break;
  533.         }
  534.         if(de) {
  535.             strcpy(p, de->d_name);
  536.         }
  537.         closedir(dir);
  538.         }
  539.         *--p = '/';
  540.     }
  541.     *p2 = oldp2;
  542.     p = p2;
  543.     }
  544. #endif
  545.     TRACE(("path=\"%s\"\n", buf));
  546.  
  547.     return my_strdup(buf);
  548. }
  549.  
  550. static Key*
  551. make_key(Unit* unit, CPTR lock, const char *name)
  552. {
  553.     Key *k = new_key();
  554.  
  555.     if(!lock) {
  556.     k->path = get_path(unit, unit->ui.rootdir, name);
  557.     } else {
  558.     Key*oldk = lookup_key(get_long(lock + 4));
  559. #if 0
  560.     const char *nm = strchr (name, ':');
  561.     if (nm == NULL) {
  562.         nm = name;
  563.     } else
  564.         nm++;
  565. #else
  566.     const char *nm = name;
  567. #endif
  568.     TRACE(("key: 0x%08lx", oldk->uniq));
  569.     TRACE((" \"%s\"\n", oldk->path));
  570.     k->path = get_path(unit, oldk->path, nm);
  571.     }
  572.  
  573.     TRACE(("key=\"%s\"\n", k->path));
  574.     return k;
  575. }
  576.  
  577. static Key*
  578. dup_key(Key*k)
  579. {
  580.     Key *newk = new_key();
  581.     newk->path = my_strdup(k->path);
  582.     return newk;
  583. }
  584.  
  585. static CPTR
  586. make_lock(Unit* unit, Key *key, long mode)
  587. {
  588.     /* allocate lock */
  589.     CPTR lock = DosAllocMem(20);
  590.  
  591.     put_long(lock + 4, key->uniq);
  592.     put_long(lock + 8, mode);
  593.     put_long(lock + 12, unit->port);
  594.     put_long(lock + 16, unit->volume >> 2);
  595.  
  596.     /* prepend to lock chain */
  597.     put_long(lock, get_long(unit->volume + 28));
  598.     put_long(unit->volume + 28, lock >> 2);
  599.  
  600.     DUMPLOCK(lock);
  601.     return lock;
  602. }
  603.  
  604. static void
  605. free_lock(Unit* unit, CPTR lock)
  606. {
  607.     if(!lock)
  608.     return;
  609.  
  610.     if(lock == get_long(unit->volume + 28) << 2) {
  611.     put_long(unit->volume + 28, get_long(lock));
  612.     } else {
  613.     CPTR current = get_long(unit->volume + 28);
  614.     CPTR next = 0;
  615.     while(current) {
  616.         next = get_long(current << 2);
  617.         if(lock == next << 2)
  618.         break;
  619.         current = next;
  620.     }
  621.     put_long(current << 2, get_long(lock));
  622.     }
  623.     free_key(lookup_key(get_long(lock + 4)));
  624.     DosFreeMem(lock);
  625. }
  626.  
  627. static void
  628. action_lock(Unit* unit, DosPacket* packet)
  629. {
  630.     CPTR lock = packet->arg1 << 2;
  631.     CPTR name = packet->arg2 << 2;
  632.     long mode = packet->arg3;
  633.     int access_mode = (mode == -2) ? R_OK : R_OK|W_OK;
  634.     Key *k;
  635.  
  636.     TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n",lock, bstr(name), mode));
  637.     DUMPLOCK(lock);
  638.  
  639.     k = make_key(unit, lock, bstr(name));
  640.  
  641.     if(k && 0 == access(k->path, access_mode)) {
  642.     packet->res1 = make_lock(unit, k, mode) >> 2;
  643.     } else {
  644.     if(k)
  645.         free_key(k);
  646.     packet->res1 = 0;
  647.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  648.     }
  649. }
  650.  
  651. static void
  652. action_free_lock(Unit* unit, DosPacket* packet)
  653. {
  654.     CPTR lock = packet->arg1 << 2;
  655.     TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
  656.     DUMPLOCK(lock);
  657.  
  658.     free_lock(unit, lock);
  659.  
  660.     packet->res1 = DOS_TRUE;
  661. }
  662.  
  663. static void
  664. action_dup_lock(Unit* unit, DosPacket* packet)
  665. {
  666.     CPTR lock = packet->arg1 << 2;
  667.  
  668.     TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
  669.     DUMPLOCK(lock);
  670.  
  671.     if(!lock) {
  672.     packet->res1 = 0;
  673.     return;
  674.     }
  675.  
  676.     {
  677.     CPTR oldkey = get_long(lock + 4);
  678.     CPTR oldmode = get_long(lock + 8);
  679.     packet->res1 = make_lock(unit, dup_key(lookup_key(oldkey)), oldmode) >> 2;
  680.     }
  681. }
  682.  
  683. /* convert time_t to/from AmigaDOS time */
  684. const int secs_per_day = 24 * 60 * 60;
  685. const int diff = (8 * 365 + 2) * (24 * 60 * 60);
  686.  
  687. static void
  688. get_time(time_t t, long* days, long* mins, long* ticks)
  689. {
  690.     /* time_t is secs since 1-1-1970 */
  691.     /* days since 1-1-1978 */
  692.     /* mins since midnight */
  693.     /* ticks past minute @ 50Hz */
  694.  
  695.     t -= diff;
  696.     *days = t / secs_per_day;
  697.     t -= *days * secs_per_day;
  698.     *mins = t / 60;
  699.     t -= *mins * 60;
  700.     *ticks = t * 50;
  701. }
  702.  
  703. static time_t
  704. put_time(long days, long mins, long ticks)
  705. {
  706.     time_t t;
  707.     t = ticks / 50;
  708.     t += mins * 60;
  709.     t += days * secs_per_day;
  710.     t += diff;
  711.  
  712.     return t;
  713. }
  714.  
  715.  
  716. typedef struct {
  717.     ULONG uniq;
  718.     char *path;
  719.     DIR* dir;
  720. } ExamineKey;
  721.  
  722. /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
  723.  * some of these around
  724.  */
  725.  
  726. #define EXKEYS 100
  727. static ExamineKey examine_keys[EXKEYS];
  728. static int next_exkey = 0;
  729.  
  730. static void
  731. free_exkey(ExamineKey* ek)
  732. {
  733.     free(ek->path);
  734.     ek->path = 0;
  735.     if(ek->dir)
  736.     closedir(ek->dir);
  737. }
  738.  
  739. static ExamineKey*
  740. new_exkey(char *path)
  741. {
  742.     ULONG uniq = next_exkey;
  743.     ExamineKey* ek= &examine_keys[next_exkey++];
  744.     if(next_exkey==EXKEYS)
  745.     next_exkey = 0;
  746.     if(ek->path) {
  747.     free_exkey(ek);
  748.     }
  749.     ek->path = my_strdup(path);
  750.     ek->dir = 0;
  751.     ek->uniq = uniq;
  752.     return ek;
  753. }
  754.  
  755. static void
  756. get_fileinfo(DosPacket* packet, CPTR info, char *buf)
  757. {
  758.     struct stat statbuf;
  759.     long days, mins, ticks;
  760.  
  761.     if(-1 == stat(buf, &statbuf)) {
  762.     packet->res1 = DOS_FALSE;
  763.     packet->res2 = dos_errno();
  764.     } else {
  765.     put_long(info + 4, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  766.     {
  767.         /* file name */
  768.         int i = 8;
  769.         int n;
  770.         char *x = strrchr(buf,'/');
  771.         if(x)
  772.         x++;
  773.         else
  774.         x = buf;
  775.         TRACE(("name=\"%s\"\n", x));
  776.         n = strlen(x);
  777.         if(n > 106) n = 106;
  778.         put_byte(info + i++, n);
  779.         while(n--)
  780.         put_byte(info + i++, *x++);
  781.         while(i < 108)
  782.         put_byte(info + i++, 0);
  783.     }
  784. #ifndef __DOS__
  785.     put_long(info + 116,
  786.          (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
  787.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
  788.          (S_IXUSR & statbuf.st_mode ? 0 : (1<<1)) |
  789.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)));
  790. #else
  791.     put_long(info + 116,
  792.          (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
  793.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
  794.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)) |
  795.          (1<<6));
  796. #endif
  797.     put_long(info + 120, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  798.     put_long(info + 124, statbuf.st_size);
  799. #ifdef HAVE_ST_BLOCKS
  800.     put_long(info + 128, statbuf.st_blocks);
  801. #else
  802.     put_long(info + 128, statbuf.st_size / 512 + 1);
  803. #endif
  804.     get_time(statbuf.st_mtime, &days, &mins, &ticks);
  805.     put_long(info + 132, days);
  806.     put_long(info + 136, mins);
  807.     put_long(info + 140, ticks);
  808.     put_long(info + 144, 0); /* no comment */
  809.     packet->res1 = DOS_TRUE;
  810.     }
  811. }
  812.  
  813. static void
  814. do_examine(DosPacket* packet, ExamineKey* ek, CPTR info)
  815. {
  816.     static char buf[1024];
  817.     struct dirent* de;
  818.  
  819.     if(!ek->dir) {
  820.     ek->dir = opendir(ek->path);
  821.     }
  822.     if(!ek->dir) {
  823.     free_exkey(ek);
  824.     packet->res1 = DOS_FALSE;
  825.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  826.     return;
  827.     }
  828.  
  829.     de = readdir(ek->dir);
  830.  
  831.     while(de && (0 == strcmp(".", de->d_name) 
  832.          || 0 == strcmp("..", de->d_name)))
  833.     {
  834.     de = readdir(ek->dir);
  835.     }
  836.  
  837.     if(!de) {
  838.     TRACE(("no more entries\n"));
  839.     free_exkey(ek);
  840.     packet->res1 = DOS_FALSE;
  841.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  842.     return;
  843.     }
  844.  
  845.     TRACE(("entry=\"%s\"\n", de->d_name));
  846.  
  847.     sprintf(buf, "%s/%s", ek->path, de->d_name);
  848.  
  849.     get_fileinfo(packet, info, buf);
  850. }
  851.  
  852. static void
  853. action_examine_object(Unit* unit, DosPacket* packet)
  854. {
  855.     CPTR lock = packet->arg1 << 2;
  856.     CPTR info = packet->arg2 << 2;
  857.     char *path;
  858.     ExamineKey* ek;
  859.  
  860.     TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
  861.     DUMPLOCK(lock);
  862.  
  863.     if(!lock) {
  864.     path = unit->ui.rootdir;
  865.     } else {
  866.     Key*k = lookup_key(get_long(lock + 4));
  867.     path = k->path;
  868.     }
  869.  
  870.     get_fileinfo(packet, info, path);
  871.     ek = new_exkey(path);
  872.     put_long(info, ek->uniq);
  873. }
  874.  
  875. static void
  876. action_examine_next(Unit* unit, DosPacket* packet)
  877. {
  878.     CPTR lock = packet->arg1 << 2;
  879.     CPTR info = packet->arg2 << 2;
  880.  
  881.     TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
  882.     DUMPLOCK(lock);
  883.  
  884.     do_examine(packet, &examine_keys[get_long(info)], info);
  885. }
  886.  
  887. static void
  888. do_find(Unit* unit, DosPacket* packet, mode_t mode)
  889. {
  890.     CPTR fh = packet->arg1 << 2;
  891.     CPTR lock = packet->arg2 << 2;
  892.     CPTR name = packet->arg3 << 2;
  893.     Key *k;
  894.     struct stat st;
  895.  
  896.     TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n",fh,lock,bstr(name),mode));
  897.     DUMPLOCK(lock);
  898.  
  899.     k = make_key(unit, lock, bstr(name));
  900.     if(!k) {
  901.     packet->res1 = DOS_FALSE;
  902.     packet->res2 = ERROR_NO_FREE_STORE;
  903.     return;
  904.     }
  905.  
  906.     /* Fixme: may not quite be right */
  907.     if (0 == stat (k->path, &st)) {
  908.     if (S_ISDIR (st.st_mode)) {
  909.         packet->res1 = DOS_FALSE;
  910.         packet->res2 = ERROR_OBJECT_WRONG_TYPE;
  911.         return;
  912.     }
  913.     }
  914.  
  915.     k->fd = open(k->path, mode | O_BINARY, 0777);
  916.  
  917.     if(k->fd < 0) {
  918.     packet->res1 = DOS_FALSE;
  919.     packet->res2 = dos_errno();
  920.     free_key(k);
  921.     return;
  922.     }
  923.     success:
  924.     put_long(fh+36, k->uniq);
  925.  
  926.     packet->res1 = DOS_TRUE;
  927. }
  928.  
  929. static void
  930. action_find_input(Unit* unit, DosPacket* packet)
  931. {
  932.     do_find(unit, packet, O_RDONLY);
  933. }
  934.  
  935. static void
  936. action_find_output(Unit* unit, DosPacket* packet)
  937. {
  938.     if(unit->ui.readonly) {
  939.     packet->res1 = DOS_FALSE;
  940.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  941.     return;
  942.     }
  943.     do_find(unit, packet, O_WRONLY|O_CREAT|O_TRUNC);
  944. }
  945.  
  946. static void
  947. action_find_write(Unit* unit, DosPacket* packet)
  948. {
  949.     if(unit->ui.readonly) {
  950.     packet->res1 = DOS_FALSE;
  951.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  952.     return;
  953.     }
  954.     do_find(unit, packet, O_RDWR);
  955. }
  956.  
  957. static void
  958. action_end(Unit* unit, DosPacket* packet)
  959. {
  960.     Key*k;
  961.     TRACE(("ACTION_END(0x%lx)\n", packet->arg1));
  962.  
  963.     k = lookup_key(packet->arg1);
  964.     free_key(k);
  965.     packet->res1 = DOS_TRUE;
  966. }
  967.  
  968. static void
  969. action_read(Unit* unit, DosPacket* packet)
  970. {
  971.     Key*k = lookup_key(packet->arg1);
  972.     CPTR addr = packet->arg2;
  973.     long size = packet->arg3;
  974.     int actual;
  975.     char *buf;
  976.  
  977.     TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->path,addr,size));
  978.  
  979.     /* ugh this is inefficient but easy */
  980.     buf = (char *)malloc(size);
  981.     if(!buf) {
  982.     packet->res1 = -1;
  983.     packet->res2 = ERROR_NO_FREE_STORE;
  984.     return;
  985.     }
  986.  
  987.     actual = read(k->fd, buf, size);
  988.  
  989.     packet->res1 = actual;
  990.  
  991.     if(actual > 0) {
  992.     int i;
  993.     unsigned char *bp = (unsigned char *)buf;
  994.     UWORD *realpt;
  995.     if (addr & 1) { /* Eeek! */
  996.         actual--;
  997.         put_byte(addr, *bp++);
  998.         addr++;
  999.     }
  1000.     if (valid_address (addr, actual)) {
  1001.         realpt = get_real_address (addr);
  1002.         for (i = 0; i < (actual & ~1); i+=2) {
  1003.         UWORD data = ((UWORD)(*bp++) << 8);
  1004.         data |= *bp++;
  1005.         *realpt++ = data;
  1006.         }
  1007.         if (actual & 1)
  1008.         put_byte (addr + actual - 1, *bp);
  1009.     } else {
  1010.        /* fprintf (stderr, "unixfs warning: Bad pointer passed for read\n");*/
  1011.         for(i = 0; i < actual; i++)
  1012.         put_byte(addr + i, buf[i]);
  1013.     }
  1014.     } else {
  1015.     packet->res2 = dos_errno();
  1016.     }
  1017.     free(buf);
  1018. }
  1019.  
  1020. static void
  1021. action_write(Unit* unit, DosPacket* packet)
  1022. {
  1023.     Key*k = lookup_key(packet->arg1);
  1024.     CPTR addr = packet->arg2;
  1025.     long size = packet->arg3;
  1026.     char *buf;
  1027.     int i;
  1028.  
  1029.     TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->path,addr,size));
  1030.  
  1031.     if(unit->ui.readonly) {
  1032.     packet->res1 = DOS_FALSE;
  1033.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1034.     return;
  1035.     }
  1036.  
  1037.     /* ugh this is inefficient but easy */
  1038.     buf = (char *)malloc(size);
  1039.     if(!buf) {
  1040.     packet->res1 = -1;
  1041.     packet->res2 = ERROR_NO_FREE_STORE;
  1042.     return;
  1043.     }
  1044.  
  1045.     for(i = 0; i < size; i++)
  1046.     buf[i] = get_byte(addr + i);
  1047.  
  1048.     packet->res1 = write(k->fd, buf, size);
  1049.     if(packet->res1 != size)
  1050.     packet->res2 = dos_errno();
  1051.  
  1052.     free(buf);
  1053. }
  1054.  
  1055. static void
  1056. action_seek(Unit* unit, DosPacket* packet)
  1057. {
  1058.     Key* k = lookup_key(packet->arg1);
  1059.     long pos = packet->arg2;
  1060.     long mode = packet->arg3;
  1061.     off_t res;
  1062.     long old;
  1063.     int whence = SEEK_CUR;
  1064.     if(mode > 0) whence = SEEK_END;
  1065.     if(mode < 0) whence = SEEK_SET;
  1066.  
  1067.     TRACE(("ACTION_SEEK(%s,%d,%d)\n",k->path,pos,mode));
  1068.  
  1069.     old = lseek(k->fd, 0, SEEK_CUR);
  1070.     res = lseek(k->fd, pos, whence);
  1071.  
  1072.     if(-1 == res)
  1073.     packet->res1 = res;
  1074.     else
  1075.     packet->res1 = old;
  1076. }
  1077.  
  1078. static void
  1079. action_set_protect(Unit* unit, DosPacket* packet)
  1080. {
  1081.     CPTR lock = packet->arg2 << 2;
  1082.     CPTR name = packet->arg3 << 2;
  1083.     ULONG mask = packet->arg4;
  1084.     struct stat statbuf;
  1085.     mode_t mode;
  1086.     Key *k;
  1087.  
  1088.     TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n",lock,bstr(name),mask));
  1089.  
  1090.     if(unit->ui.readonly) {
  1091.     packet->res1 = DOS_FALSE;
  1092.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1093.     return;
  1094.     }
  1095.  
  1096.     k = make_key(unit, lock, bstr(name));
  1097.     if(!k) {
  1098.     packet->res1 = DOS_FALSE;
  1099.     packet->res2 = ERROR_NO_FREE_STORE;
  1100.     return;
  1101.     }
  1102.  
  1103.     if(-1 == stat(k->path, &statbuf)) {
  1104.     free_key(k);
  1105.     packet->res1 = DOS_FALSE;
  1106.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  1107.     return;
  1108.     }
  1109.  
  1110.     mode = statbuf.st_mode;
  1111.  
  1112.     if(mask & (1 << 3))
  1113.     mode &= ~S_IRUSR;
  1114.     else
  1115.     mode |= S_IRUSR;
  1116.  
  1117.     if(mask & (1 << 2) || mask & (1 << 0))
  1118.     mode &= ~S_IWUSR;
  1119.     else
  1120.     mode |= S_IWUSR;
  1121.  
  1122.     if(mask & (1 << 1))
  1123.     mode &= ~S_IXUSR;
  1124.     else
  1125.     mode |= S_IXUSR;
  1126.  
  1127.     if(-1 == chmod(k->path, mode)) {
  1128.     packet->res1 = DOS_FALSE;
  1129.     packet->res2 = dos_errno();
  1130.     } else {
  1131.     packet->res1 = DOS_TRUE;
  1132.     }
  1133.     free_key(k);
  1134. }
  1135.  
  1136. static void
  1137. action_same_lock(Unit* unit, DosPacket* packet)
  1138. {
  1139.     CPTR lock1 = packet->arg1 << 2;
  1140.     CPTR lock2 = packet->arg2 << 2;
  1141.  
  1142.     TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
  1143.     DUMPLOCK(lock1); DUMPLOCK(lock2);
  1144.  
  1145.     if(!lock1 || !lock2) {
  1146.     packet->res1 = (lock1 == lock2) ? DOS_TRUE : DOS_FALSE;
  1147.     } else {
  1148.     Key* key1 = lookup_key(get_long(lock1 + 4));
  1149.     Key* key2 = lookup_key(get_long(lock2 + 4));
  1150.     packet->res1 = (0 == strcmp(key1->path, key2->path)) ? DOS_TRUE : DOS_FALSE;
  1151.     }
  1152. }
  1153.  
  1154. static void
  1155. action_parent(Unit* unit, DosPacket* packet)
  1156. {
  1157.     CPTR lock = packet->arg1 << 2;
  1158.     Key*k;
  1159.  
  1160.     TRACE(("ACTION_PARENT(0x%lx)\n",lock));
  1161.  
  1162.     if(!lock) {
  1163.     packet->res1 = 0;
  1164.     packet->res2 = 0;
  1165.     return;
  1166.     }
  1167.  
  1168.     k = dup_key(lookup_key(get_long(lock + 4)));
  1169.     if(0 == strcmp(k->path, unit->ui.rootdir)) {
  1170.     free_key(k);
  1171.     packet->res1 = 0;
  1172.     packet->res2 = 0;
  1173.     return;
  1174.     }
  1175.     {
  1176.     char *x = strrchr(k->path,'/');
  1177.     if(!x) {
  1178.         free_key(k);
  1179.         packet->res1 = 0;
  1180.         packet->res2 = 0;
  1181.         return;
  1182.     } else {
  1183.         *x = '\0';
  1184.     }
  1185.     }
  1186.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1187. }
  1188.  
  1189. static void
  1190. action_create_dir(Unit* unit, DosPacket* packet)
  1191. {
  1192.     CPTR lock = packet->arg1 << 2;
  1193.     CPTR name = packet->arg2 << 2;
  1194.     Key* k;
  1195.  
  1196.     TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n",lock,bstr(name)));
  1197.  
  1198.     if(unit->ui.readonly) {
  1199.     packet->res1 = DOS_FALSE;
  1200.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1201.     return;
  1202.     }
  1203.  
  1204.     k = make_key(unit, lock, bstr(name));
  1205.  
  1206.     if(!k) {
  1207.     packet->res1 = DOS_FALSE;
  1208.     packet->res2 = ERROR_NO_FREE_STORE;
  1209.     return;
  1210.     }
  1211.     if(-1 == mkdir(k->path, 0777)) {
  1212.     packet->res1 = DOS_FALSE;
  1213.     packet->res2 = dos_errno();
  1214.     free_key(k);
  1215.     return;
  1216.     }
  1217.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1218. }
  1219.  
  1220. static void
  1221. action_delete_object(Unit* unit, DosPacket* packet)
  1222. {
  1223.     CPTR lock = packet->arg1 << 2;
  1224.     CPTR name = packet->arg2 << 2;
  1225.     Key* k;
  1226.     struct stat statbuf;
  1227.  
  1228.     TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n",lock,bstr(name)));
  1229.  
  1230.     if(unit->ui.readonly) {
  1231.     packet->res1 = DOS_FALSE;
  1232.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1233.     return;
  1234.     }
  1235.  
  1236.     k = make_key(unit, lock, bstr(name));
  1237.  
  1238.     if(!k) {
  1239.     packet->res1 = DOS_FALSE;
  1240.     packet->res2 = ERROR_NO_FREE_STORE;
  1241.     return;
  1242.     }
  1243.     if(-1 == stat(k->path, &statbuf)) {
  1244.     packet->res1 = DOS_FALSE;
  1245.     packet->res2 = dos_errno();
  1246.     free_key(k);
  1247.     return;
  1248.     }
  1249.     if(S_ISDIR(statbuf.st_mode)) {
  1250.     if(-1 == rmdir(k->path)) {
  1251.         packet->res1 = DOS_FALSE;
  1252.         packet->res2 = dos_errno();
  1253.         free_key(k);
  1254.         return;
  1255.     }
  1256.     } else {
  1257.     if(-1 == unlink(k->path)) {
  1258.         packet->res1 = DOS_FALSE;
  1259.         packet->res2 = dos_errno();
  1260.         free_key(k);
  1261.         return;
  1262.     }
  1263.     }
  1264.     free_key(k);
  1265.     packet->res1 = DOS_TRUE;
  1266. }
  1267.  
  1268. static void
  1269. action_set_date(Unit* unit, DosPacket* packet)
  1270. {
  1271.     CPTR lock = packet->arg2 << 2;
  1272.     CPTR name = packet->arg3 << 2;
  1273.     CPTR date = packet->arg4;
  1274.     Key* k;
  1275.     struct utimbuf ut;
  1276.  
  1277.     TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n",lock,bstr(name)));
  1278.  
  1279.     if(unit->ui.readonly) {
  1280.     packet->res1 = DOS_FALSE;
  1281.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1282.     return;
  1283.     }
  1284.  
  1285.     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
  1286.     k = make_key(unit, lock, bstr(name));
  1287.  
  1288.     if(!k) {
  1289.     packet->res1 = DOS_FALSE;
  1290.     packet->res2 = ERROR_NO_FREE_STORE;
  1291.     return;
  1292.     }
  1293.     if(-1 == utime(k->path, &ut)) {
  1294.     packet->res1 = DOS_FALSE;
  1295.     packet->res2 = dos_errno();
  1296.     free_key(k);
  1297.     return;
  1298.     }
  1299.     free_key(k);
  1300.     packet->res1 = DOS_TRUE;
  1301. }
  1302.  
  1303. static void
  1304. action_rename_object(Unit* unit, DosPacket* packet)
  1305. {
  1306.     CPTR lock1 = packet->arg1 << 2;
  1307.     CPTR name1 = packet->arg2 << 2;
  1308.     Key* k1;
  1309.     CPTR lock2 = packet->arg3 << 2;
  1310.     CPTR name2 = packet->arg4 << 2;
  1311.     Key* k2;
  1312.  
  1313.     TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",",lock1,bstr(name1)));
  1314.     TRACE(("0x%lx,\"%s\")\n",lock2,bstr(name2)));
  1315.  
  1316.     if(unit->ui.readonly) {
  1317.     packet->res1 = DOS_FALSE;
  1318.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1319.     return;
  1320.     }
  1321.  
  1322.     k1 = make_key(unit, lock1, bstr(name1));
  1323.     if(!k1) {
  1324.     packet->res1 = DOS_FALSE;
  1325.     packet->res2 = ERROR_NO_FREE_STORE;
  1326.     return;
  1327.     }
  1328.     k2 = make_key(unit, lock2, bstr(name2));
  1329.     if(!k2) {
  1330.     free_key(k1);
  1331.     packet->res1 = DOS_FALSE;
  1332.     packet->res2 = ERROR_NO_FREE_STORE;
  1333.     return;
  1334.     }
  1335.  
  1336.     if(-1 == rename(k1->path, k2->path)) {
  1337.     packet->res1 = DOS_FALSE;
  1338.     packet->res2 = dos_errno();
  1339.     free_key(k1);
  1340.     free_key(k2);
  1341.     return;
  1342.     }
  1343.     free_key(k1);
  1344.     free_key(k2);
  1345.     packet->res1 = DOS_TRUE;
  1346. }
  1347.  
  1348. static void
  1349. action_current_volume(Unit* unit, DosPacket* packet)
  1350. {
  1351.     packet->res1 = unit->volume >> 2;
  1352. }
  1353.  
  1354. static void
  1355. action_rename_disk(Unit* unit, DosPacket* packet)
  1356. {
  1357.     CPTR name = packet->arg1 << 2;
  1358.     int i;
  1359.     int namelen;
  1360.  
  1361.     TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr(name)));
  1362.  
  1363.     if(unit->ui.readonly) {
  1364.     packet->res1 = DOS_FALSE;
  1365.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1366.     return;
  1367.     }
  1368.  
  1369.     /* get volume name */
  1370.     namelen = get_byte(name++);
  1371.     free(unit->ui.volname);
  1372.     unit->ui.volname = (char *) malloc(namelen + 1);
  1373.     for(i = 0; i < namelen; i++)
  1374.     unit->ui.volname[i] = get_byte(name++);
  1375.     unit->ui.volname[i] = 0;
  1376.  
  1377.     put_byte(unit->volume + 44, namelen);
  1378.     for(i = 0; i < namelen; i++)
  1379.     put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  1380.  
  1381.     packet->res1 = DOS_TRUE;
  1382. }
  1383.  
  1384. static void
  1385. action_is_filesystem(Unit* unit, DosPacket* packet)
  1386. {
  1387.     packet->res1 = DOS_TRUE;
  1388. }
  1389.  
  1390. static void
  1391. action_flush(Unit* unit, DosPacket* packet)
  1392. {
  1393.     /* sync(); */ /* pretty drastic, eh */
  1394.     packet->res1 = DOS_TRUE;
  1395. }
  1396.  
  1397. static ULONG
  1398. filesys_handler(void)
  1399. {
  1400.     DosPacket packet;
  1401.     Unit *unit = find_unit(regs.a[5]);
  1402.  
  1403.     /* got DosPacket in A4 */
  1404.     packet.addr = regs.a[4];
  1405.     packet.type = get_long(packet.addr + dp_Type);
  1406.     packet.res1 = get_long(packet.addr + dp_Res1);
  1407.     packet.res2 = get_long(packet.addr + dp_Res2);
  1408.     packet.arg1 = get_long(packet.addr + dp_Arg1);
  1409.     packet.arg2 = get_long(packet.addr + dp_Arg2);
  1410.     packet.arg3 = get_long(packet.addr + dp_Arg3);
  1411.     packet.arg4 = get_long(packet.addr + dp_Arg4);
  1412.  
  1413.     if(!unit) {
  1414.     startup(&packet);
  1415.     put_long(packet.addr + dp_Res1, packet.res1);
  1416.     put_long(packet.addr + dp_Res2, packet.res2);
  1417.     return 0;
  1418.     }
  1419.  
  1420.     if(!unit->volume) {
  1421.     printf("no volume\n");
  1422.     return 0;
  1423.     }
  1424.  
  1425.     switch(packet.type) {
  1426.      case ACTION_LOCATE_OBJECT:
  1427.     action_lock(unit, &packet);
  1428.     break;
  1429.  
  1430.      case ACTION_FREE_LOCK:
  1431.     action_free_lock(unit, &packet);
  1432.     break;
  1433.  
  1434.      case ACTION_COPY_DIR:
  1435.     action_dup_lock(unit, &packet);
  1436.     break;
  1437.  
  1438.      case ACTION_DISK_INFO:
  1439.     action_disk_info(unit, &packet);
  1440.     break;
  1441.  
  1442.      case ACTION_INFO:
  1443.     action_info(unit, &packet);
  1444.     break;
  1445.  
  1446.      case ACTION_EXAMINE_OBJECT:
  1447.     action_examine_object(unit, &packet);
  1448.     break;
  1449.  
  1450.      case ACTION_EXAMINE_NEXT:
  1451.     action_examine_next(unit, &packet);
  1452.     break;
  1453.  
  1454.      case ACTION_FIND_INPUT:
  1455.     action_find_input(unit, &packet);
  1456.     break;
  1457.  
  1458.      case ACTION_FIND_WRITE:
  1459.     action_find_write(unit, &packet);
  1460.     break;
  1461.  
  1462.      case ACTION_FIND_OUTPUT:
  1463.     action_find_output(unit, &packet);
  1464.     break;
  1465.  
  1466.      case ACTION_END:
  1467.     action_end(unit, &packet);
  1468.     break;
  1469.  
  1470.      case ACTION_READ:
  1471.     action_read(unit, &packet);
  1472.     break;
  1473.  
  1474.      case ACTION_WRITE:
  1475.     action_write(unit, &packet);
  1476.     break;
  1477.  
  1478.      case ACTION_SEEK:
  1479.     action_seek(unit, &packet);
  1480.     break;
  1481.  
  1482.      case ACTION_SET_PROTECT:
  1483.     action_set_protect(unit, &packet);
  1484.     break;
  1485.  
  1486.      case ACTION_SAME_LOCK:
  1487.     action_same_lock(unit, &packet);
  1488.     break;
  1489.  
  1490.      case ACTION_PARENT:
  1491.     action_parent(unit, &packet);
  1492.     break;
  1493.  
  1494.      case ACTION_CREATE_DIR:
  1495.     action_create_dir(unit, &packet);
  1496.     break;
  1497.  
  1498.      case ACTION_DELETE_OBJECT:
  1499.     action_delete_object(unit, &packet);
  1500.     break;
  1501.  
  1502.      case ACTION_RENAME_OBJECT:
  1503.     action_rename_object(unit, &packet);
  1504.     break;
  1505.  
  1506.      case ACTION_SET_DATE:
  1507.     action_set_date(unit, &packet);
  1508.     break;
  1509.  
  1510.      case ACTION_CURRENT_VOLUME:
  1511.     action_current_volume(unit, &packet);
  1512.     break;
  1513.  
  1514.      case ACTION_RENAME_DISK:
  1515.     action_rename_disk(unit, &packet);
  1516.     break;
  1517.  
  1518.      case ACTION_IS_FILESYSTEM:
  1519.     action_is_filesystem(unit, &packet);
  1520.     break;
  1521.  
  1522.      case ACTION_FLUSH:
  1523.     action_flush(unit, &packet);
  1524.     break;
  1525.  
  1526.      default:
  1527.     TRACE(("*** UNSUPPORTED PACKET %ld\n", packet.type));
  1528.     packet.res1 = DOS_FALSE;
  1529.     packet.res2 = ERROR_ACTION_NOT_KNOWN;
  1530.     break;
  1531.     }
  1532.  
  1533.     put_long(packet.addr + dp_Res1, packet.res1);
  1534.     put_long(packet.addr + dp_Res2, packet.res2);
  1535.     TRACE(("reply: %8lx, %ld\n", packet.res1, packet.res2));
  1536.  
  1537.     return 0;
  1538. }
  1539.  
  1540. static ULONG
  1541. filesys_init(void)
  1542. {
  1543.     ULONG tmp1, tmp2, configdev;
  1544.     int have36 = 0;
  1545.     int i;
  1546.  
  1547.     regs.d[0] = 88; regs.d[1] = 1; /* MEMF_PUBLIC */
  1548.     tmp1 = CallLib (regs.a[6], -198); /* AllocMem() */
  1549.     if (tmp1 == 0) {
  1550.     fprintf(stderr, "Not enough memory for filesystem!\n");
  1551.     return 0;
  1552.     }
  1553.  
  1554.     /* Open expansion.lib */
  1555.     regs.d[0] = 36; /* Let's try this... */
  1556.     regs.a[1] = explibname;
  1557.     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
  1558.     if (regs.a[4])
  1559.     have36 = 1;
  1560.     else {
  1561.     regs.d[0] = 0;
  1562.     regs.a[1] = explibname;
  1563.     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
  1564.     }
  1565.     put_long (tmp1+4, fsdevname);
  1566.     put_long (tmp1+12, 0); /* Device flags */
  1567.     put_long (tmp1+16, 16); /* Env. size */
  1568.     put_long (tmp1+20, 128); /* 512 bytes/block */
  1569.     put_long (tmp1+24, 0); /* unused */
  1570.     put_long (tmp1+28, 1); /* heads */
  1571.     put_long (tmp1+32, 1); /* unused */
  1572.     put_long (tmp1+36, 32); /* secs per track */
  1573.     put_long (tmp1+40, 1); /* reserved blocks */
  1574.     put_long (tmp1+44, 0); /* unused */
  1575.     put_long (tmp1+48, 0); /* interleave */
  1576.     put_long (tmp1+52, 0); /* lowCyl */
  1577.     put_long (tmp1+56, 511); /* upperCyl */
  1578.     put_long (tmp1+60, 0); /* Number of buffers */
  1579.     put_long (tmp1+64, 0); /* Buffer mem type */
  1580.     put_long (tmp1+68, 0x7FFFFFFF); /* largest transfer */
  1581.     put_long (tmp1+72, ~1); /* addMask (?) */
  1582.     put_long (tmp1+76, (ULONG)-1); /* bootPri */
  1583.     if (have36)
  1584.     put_long (tmp1+80, 0x444f5301); /* DOS\1 */
  1585.     else
  1586.     put_long (tmp1+80, 0x444f5300); /* DOS\0 */
  1587.  
  1588.     put_long (tmp1+84, 0); /* pad */
  1589.  
  1590.     /* re-use the same parameter packet to make each
  1591.      * dos node, which will then get tweaked
  1592.      */
  1593.     for(i = 0; i < num_units; i++) {
  1594.     put_long (tmp1, devnameaddr[i]);
  1595.     put_long (tmp1+8, i); /* Unit no. (not really necessary) */
  1596.     regs.a[0] = tmp1;
  1597.     tmp2 = CallLib (regs.a[4], -144); /* MakeDosNode() */
  1598.     put_long(tmp2+8, 0x0); /* dn_Task */
  1599.     put_long(tmp2+16, 0x0); /* dn_Handler */
  1600.     put_long(tmp2+20, 4000); /* dn_StackSize */
  1601.     put_long(tmp2+32, filesysseglist >> 2); /* dn_SegList */
  1602.     put_long(tmp2+36, (ULONG)-1); /* dn_GlobalVec */
  1603. #if 0 /* Not 1.3 compatible */
  1604.         configdev = CallLib(regs.a[4], -48); /* AllocConfigDev() */
  1605.  
  1606.         /* hier init der Configdev */
  1607.  
  1608.  
  1609.     regs.a[0] = tmp2;
  1610.     regs.d[0] = (ULONG)-1;
  1611.     regs.a[1] = configdev;
  1612.     regs.d[1] = 0;        /* Flags */
  1613.     CallLib (regs.a[4], -36); /* AddBootNode() */
  1614. #else
  1615.     regs.a[0] = tmp2;
  1616.     regs.d[0] = (ULONG)-1;
  1617.     regs.a[1] = 0;
  1618.     regs.d[1] = 0;        /* Flags */
  1619.     CallLib (regs.a[4], -150); /* AddDosNode() */
  1620. #endif
  1621.     }
  1622.  
  1623.     regs.a[1] = tmp1;
  1624.     regs.d[0] = 88;
  1625.     CallLib (regs.a[6], -210); /* FreeMem() */
  1626.  
  1627.     regs.a[1] = regs.a[4];
  1628.     CallLib (regs.a[6], -414); /* CloseLibrary() */
  1629.  
  1630.     return 0;
  1631. }
  1632.  
  1633. void
  1634. filesys_install(void)
  1635. {
  1636.     ULONG begin, end, resname, resid;
  1637.     int i;
  1638.  
  1639.     if(0 == num_units)
  1640.     return;
  1641.  
  1642.     resname = ds("UAEunixfs.resource");
  1643.     resid = ds("UAE unixfs 0.1");
  1644.  
  1645.     doslibname = ds("dos.library");
  1646.     fsdevname = ds("unixfs.device"); /* does not really exist */
  1647.  
  1648.     for(i = 0; i < num_units; i++) {
  1649.     devnameaddr[i] = ds(ui[i].devname);
  1650.     }
  1651.  
  1652.     begin = here();
  1653.     dw(0x4AFC); /* RTC_MATCHWORD */
  1654.     dl(begin); /* our start address */
  1655.     dl(0); /* Continue scan here */
  1656.     dw(0x0101); /* RTF_COLDSTART; Version 1 */
  1657.     dw(0x0805); /* NT_RESOURCE; pri 5 */
  1658.     dl(resname); /* name */
  1659.     dl(resid); /* ID */
  1660.     dl(here() + 4); /* Init area: directly after this */
  1661.  
  1662.     calltrap(deftrap(filesys_init)); dw(RTS);
  1663.  
  1664.     /* align */
  1665.     align(4);
  1666.     /* Fake seglist */
  1667.     dl(16);
  1668.     filesysseglist = here();
  1669.     dl(0); /* NextSeg */
  1670.  
  1671.     /* start of code */
  1672.  
  1673.     /* I don't trust calling functions that Wait() directly,
  1674.      * so here's a little bit of 68000 code to receive and send our
  1675.      * DosPackets
  1676.      */
  1677.     dw(0x2c79); dl(4);        /* move.l    $4,a6 */
  1678.     dw(0x2279); dl(0);        /* move.l    0,a1 */
  1679.     dw(0x4eae); dw(0xfeda);    /* jsr        FindTask(a6) */
  1680.     dw(0x2040);            /* move.l    d0,a0 */
  1681.     dw(0x4be8); dw(0x005c);    /* lea.l    pr_MsgPort(a0),a5 */
  1682.                 /* loop: */
  1683.     dw(0x204d);            /* move.l    a5,a0 */
  1684.     dw(0x4eae); dw(0xfe80);    /* jsr        WaitPort(a6) */
  1685.     dw(0x204d);            /* move.l    a5,a0 */
  1686.     dw(0x4eae); dw(0xfe8c);    /* jsr        GetMsg(a6) */
  1687.     dw(0x2840);            /* move.l    d0,a4 */
  1688.     dw(0x286c); dw(10);        /* move.l    LN_NAME(a4),a4 */
  1689.     calltrap(deftrap(filesys_handler));
  1690.     dw(0x226c);    dw(0);        /* move.l    dp_Link(a4),a1 */
  1691.     dw(0x206c); dw(4);        /* move.l    dp_Port(a4),a0 */
  1692.     dw(0x294d); dw(4);        /* move.l    a5,dp_Port(a4) */
  1693.     dw(0x4eae); dw(0xfe92);    /* jsr        PutMsg(a6) */
  1694.     dw(0x60d6);         /* bra.s    loop */
  1695.  
  1696.     end = here();
  1697.     org(begin + 6);
  1698.     dl(end);
  1699.  
  1700.     org(end);
  1701. }
  1702.  
  1703.