home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / extfs.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-31  |  64.7 KB  |  2,194 lines

  1. /*
  2.  *  extfs.cpp - MacOS file system for native file system access
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. /*
  22.  *  SEE ALSO
  23.  *    Guide to the File System Manager (from FSM 1.2 SDK)
  24.  *
  25.  *  TODO
  26.  *    LockRng
  27.  *    UnlockRng
  28.  *    (CatSearch)
  29.  *    (MakeFSSpec)
  30.  *    (GetVolMountInfoSize)
  31.  *    (GetVolMountInfo)
  32.  *    (GetForeignPrivs)
  33.  *    (SetForeignPrivs)
  34.  */
  35.  
  36. #include "sysdeps.h"
  37.  
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <string.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <fcntl.h>
  44. #include <errno.h>
  45.  
  46. #ifndef WIN32
  47. #include <unistd.h>
  48. #include <dirent.h>
  49. #endif
  50.  
  51. #include "cpu_emulation.h"
  52. #include "emul_op.h"
  53. #include "main.h"
  54. #include "disk.h"
  55. #include "prefs.h"
  56. #include "user_strings.h"
  57. #include "extfs.h"
  58. #include "extfs_defs.h"
  59.  
  60. #ifdef WIN32
  61. # include "posix_emu.h"
  62. #endif
  63.  
  64. #define DEBUG 0
  65. #include "debug.h"
  66.  
  67.  
  68. // File system global data and 68k routines
  69. enum {
  70.     fsCommProcStub = 0,
  71.     fsHFSProcStub = 6,
  72.     fsDrvStatus = 12,                // Drive Status record
  73.     fsFSD = 42,                        // File system descriptor
  74.     fsPB = 238,                        // IOParam (for mounting and renaming), also used for temporary storage
  75.     fsVMI = 288,                    // VoumeMountInfoHeader (for mounting)
  76.     fsParseRec = 296,                // ParsePathRec struct
  77.     fsReturn = 306,                    // Area for return data of 68k routines
  78.     fsAllocateVCB = 562,            // UTAllocateVCB(uint16 *sysVCBLength{a0}, uint32 *vcb{a1})
  79.     fsAddNewVCB = 578,                // UTAddNewVCB(int drive_number{d0}, int16 *vRefNum{a1}, uint32 vcb{a1})
  80.     fsDetermineVol = 594,            // UTDetermineVol(uint32 pb{a0}, int16 *status{a1}, int16 *more_matches{a2}, int16 *vRefNum{a3}, uint32 *vcb{a4})
  81.     fsResolveWDCB = 614,            // UTResolveWDCB(uint32 procID{d0}, int16 index{d1}, int16 vRefNum{d0}, uint32 *wdcb{a0})
  82.     fsGetDefaultVol = 632,            // UTGetDefaultVol(uint32 wdpb{a0})
  83.     fsGetPathComponentName = 644,    // UTGetPathComponentName(uint32 rec{a0})
  84.     fsParsePathname = 656,            // UTParsePathname(uint32 *start{a0}, uint32 name{a1})
  85.     fsDisposeVCB = 670,                // UTDisposeVCB(uint32 vcb{a0})
  86.     fsCheckWDRefNum = 682,            // UTCheckWDRefNum(int16 refNum{d0})
  87.     fsSetDefaultVol = 694,            // UTSetDefaultVol(uint32 dummy{d0}, int32 dirID{d1}, int16 refNum{d2})
  88.     fsAllocateFCB = 710,            // UTAllocateFCB(int16 *refNum{a0}, uint32 *fcb{a1})
  89.     fsReleaseFCB = 724,                // UTReleaseFCB(int16 refNum{d0})
  90.     fsIndexFCB = 736,                // UTIndexFCB(uint32 vcb{a0}, int16 *refNum{a1}, uint32 *fcb{a2})
  91.     fsResolveFCB = 752,                // UTResolveFCB(int16 refNum{d0}, uint32 *fcb{a0})
  92.     fsAdjustEOF = 766,                // UTAdjustEOF(int16 refNum{d0})
  93.     fsAllocateWDCB = 778,            // UTAllocateWDCB(uint32 pb{a0})
  94.     fsReleaseWDCB = 790,            // UTReleaseWDCB(int16 vRefNum{d0})
  95.     SIZEOF_fsdat = 802
  96. };
  97.  
  98. static uint32 fs_data = 0;        // Mac address of global data
  99.  
  100.  
  101. // File system and volume name
  102. static char FS_NAME[32], VOLUME_NAME[32];
  103.  
  104. // This directory is our root (read from prefs)
  105. static const char *RootPath;
  106. static bool ready = false;
  107. static struct stat root_stat;
  108.  
  109. // File system ID/media type
  110. const int16 MY_FSID = EMULATOR_ID_2;
  111. const uint32 MY_MEDIA_TYPE = EMULATOR_ID_4;
  112.  
  113. // CNID of root and root's parent
  114. const uint32 ROOT_ID = 2;
  115. const uint32 ROOT_PARENT_ID = 1;
  116.  
  117. // File system stack size
  118. const int STACK_SIZE = 0x10000;
  119.  
  120. // Allocation block and clump size as reported to MacOS (these are of course
  121. // not the real values and have no meaning on the host OS)
  122. const int AL_BLK_SIZE = 0x4000;
  123. const int CLUMP_SIZE = 0x4000;
  124.  
  125. // Drive number of our pseudo-drive
  126. static int drive_number;
  127.  
  128.  
  129. // Disk/drive icon
  130. const uint8 ExtFSIcon[256] = {
  131.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  132.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  133.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  134.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  135.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
  136.     0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x01, 0x21, 0x80, 0x00, 0x01, 0x21,
  137.     0x80, 0x00, 0x02, 0x41, 0x8c, 0x00, 0x02, 0x41, 0x80, 0x00, 0x04, 0x81, 0x80, 0x00, 0x04, 0x81,
  138.     0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  139.  
  140.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  141.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  142.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  143.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  144.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
  145.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  146.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  147.     0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  148. };
  149.  
  150.  
  151. // These objects are used to map CNIDs to path names
  152. struct FSItem {
  153.     FSItem *next;            // Pointer to next FSItem in list
  154.     uint32 id;                // CNID of this file/dir
  155.     uint32 parent_id;        // CNID of parent file/dir
  156.     FSItem *parent;            // Pointer to parent
  157.     char name[32];            // Object name (C string)
  158.     time_t mtime;            // Modification time for get_cat_info caching
  159.     int cache_dircount;        // Cached number of files in directory
  160. };
  161.  
  162. static FSItem *first_fs_item, *last_fs_item;
  163.  
  164. static uint32 next_cnid = fsUsrCNID;    // Next available CNID
  165.  
  166.  
  167. /*
  168.  *  Find FSItem for given CNID
  169.  */
  170.  
  171. static FSItem *find_fsitem_by_id(uint32 cnid)
  172. {
  173.     FSItem *p = first_fs_item;
  174.     while (p) {
  175.         if (p->id == cnid)
  176.             return p;
  177.         p = p->next;
  178.     }
  179.     return NULL;
  180. }
  181.  
  182.  
  183. /*
  184.  *  Find FSItem for given name and parent, construct new FSItem if not found
  185.  */
  186.  
  187. static FSItem *find_fsitem(const char *name, FSItem *parent)
  188. {
  189.     FSItem *p = first_fs_item;
  190.     while (p) {
  191.         if (p->parent == parent && !strcmp(p->name, name))
  192.             return p;
  193.         p = p->next;
  194.     }
  195.  
  196.     // Not found, construct new FSItem
  197.     p = new FSItem;
  198.     last_fs_item->next = p;
  199.     p->next = NULL;
  200.     last_fs_item = p;
  201.     p->id = next_cnid++;
  202.     p->parent_id = parent->id;
  203.     p->parent = parent;
  204.     strncpy(p->name, name, 31);
  205.     p->name[31] = 0;
  206.     p->mtime = 0;
  207.     return p;
  208. }
  209.  
  210.  
  211. /*
  212.  *  Get full path (->full_path) for given FSItem
  213.  */
  214.  
  215. static char full_path[MAX_PATH_LENGTH];
  216.  
  217. static void add_path_comp(const char *s)
  218. {
  219.     add_path_component(full_path, s);
  220. }
  221.  
  222. static void get_path_for_fsitem(FSItem *p)
  223. {
  224.     if (p->id == ROOT_PARENT_ID) {
  225.         full_path[0] = 0;
  226.     } else if (p->id == ROOT_ID) {
  227.         strncpy(full_path, RootPath, MAX_PATH_LENGTH-1);
  228.         full_path[MAX_PATH_LENGTH-1] = 0;
  229.     } else {
  230.         get_path_for_fsitem(p->parent);
  231.         add_path_comp(p->name);
  232.     }
  233. }
  234.  
  235.  
  236. /*
  237.  *  Exchange parent CNIDs in all FSItems
  238.  */
  239.  
  240. static void swap_parent_ids(uint32 parent1, uint32 parent2)
  241. {
  242.     FSItem *p = first_fs_item;
  243.     while (p) {
  244.         if (p->parent_id == parent1)
  245.             p->parent_id = parent2;
  246.         else if (p->parent_id == parent2)
  247.             p->parent_id = parent1;
  248.         p = p->next;
  249.     }
  250. }
  251.  
  252.  
  253. /*
  254.  *  String handling functions
  255.  */
  256.  
  257. // Copy pascal string
  258. static void pstrcpy(char *dst, const char *src)
  259. {
  260.     int size = *dst++ = *src++;
  261.     while (size--)
  262.         *dst++ = *src++;
  263. }
  264.  
  265. // Convert C string to pascal string
  266. static void cstr2pstr(char *dst, const char *src)
  267. {
  268.     *dst++ = strlen(src);
  269.     char c;
  270.     while ((c = *src++) != 0) {
  271.         // Note: we are converting host ':' characters to Mac '/' characters here
  272.         // '/' is not a path separator as this function is only used on object names
  273.         if (c == ':')
  274.             c = '/';
  275.         *dst++ = c;
  276.     }
  277. }
  278.  
  279. // Convert string (no length byte) to C string, length given separately
  280. static void strn2cstr(char *dst, const char *src, int size)
  281. {
  282.     while (size--) {
  283.         char c = *src++;
  284.         // Note: we are converting Mac '/' characters to host ':' characters here
  285.         // '/' is not a path separator as this function is only used on object names
  286.         if (c == '/')
  287.             c = ':';
  288.         *dst++ = c;
  289.     }
  290.     *dst = 0;
  291. }
  292.  
  293.  
  294. /*
  295.  *  Convert errno to MacOS error code
  296.  */
  297.  
  298. static int16 errno2oserr(void)
  299. {
  300.     D(bug(" errno %08x\n", errno));
  301.     switch (errno) {
  302.         case 0:
  303.             return noErr;
  304.         case ENOENT:
  305.         case EISDIR:
  306.             return fnfErr;
  307.         case EACCES:
  308.         case EPERM:
  309.             return permErr;
  310.         case EEXIST:
  311.             return dupFNErr;
  312.         case EBUSY:
  313.         case ENOTEMPTY:
  314.             return fBsyErr;
  315.         case ENOSPC:
  316.             return dskFulErr;
  317.         case EROFS:
  318.             return wPrErr;
  319.         case EMFILE:
  320.             return tmfoErr;
  321.         case ENOMEM:
  322.             return -108;
  323.         case EIO:
  324.         default:
  325.             return ioErr;
  326.     }
  327. }
  328.  
  329.  
  330. /*
  331.  *  Initialization
  332.  */
  333.  
  334. void ExtFSInit(void)
  335. {
  336.     // System specific initialization
  337.     extfs_init();
  338.  
  339.     // Get file system and volume name
  340.     cstr2pstr(FS_NAME, GetString(STR_EXTFS_NAME));
  341.     cstr2pstr(VOLUME_NAME, GetString(STR_EXTFS_VOLUME_NAME));
  342.  
  343.     // Create root's parent FSItem
  344.     FSItem *p = new FSItem;
  345.     first_fs_item = last_fs_item = p;
  346.     p->next = NULL;
  347.     p->id = ROOT_PARENT_ID;
  348.     p->parent_id = 0;
  349.     p->parent = NULL;
  350.     p->name[0] = 0;
  351.  
  352.     // Create root FSItem
  353.     p = new FSItem;
  354.     last_fs_item->next = p;
  355.     p->next = NULL;
  356.     last_fs_item = p;
  357.     p->id = ROOT_ID;
  358.     p->parent_id = ROOT_PARENT_ID;
  359.     p->parent = first_fs_item;
  360.     strncpy(p->name, GetString(STR_EXTFS_VOLUME_NAME), 32);
  361.     p->name[31] = 0;
  362.  
  363.     // Find path for root
  364.     if ((RootPath = PrefsFindString("extfs")) != NULL) {
  365.         if (stat(RootPath, &root_stat))
  366.             return;
  367.         if (!S_ISDIR(root_stat.st_mode))
  368.             return;
  369.         ready = true;
  370.     }
  371. }
  372.  
  373.  
  374. /*
  375.  *  Deinitialization
  376.  */
  377.  
  378. void ExtFSExit(void)
  379. {
  380.     // Delete all FSItems
  381.     FSItem *p = first_fs_item, *next;
  382.     while (p) {
  383.         next = p->next;
  384.         delete p;
  385.         p = next;
  386.     }
  387.     first_fs_item = last_fs_item = NULL;
  388.  
  389.     // System specific deinitialization
  390.     extfs_exit();
  391. }
  392.  
  393.  
  394. /*
  395.  *  Install file system
  396.  */
  397.  
  398. void InstallExtFS(void)
  399. {
  400.     int num_blocks = 0xffff;    // Fake number of blocks of our drive
  401.     M68kRegisters r;
  402.  
  403.     D(bug("InstallExtFS\n"));
  404.     if (!ready)
  405.         return;
  406.  
  407.     // FSM present?
  408.     r.d[0] = gestaltFSAttr;
  409.     Execute68kTrap(0xa1ad, &r);    // Gestalt()
  410.     D(bug("FSAttr %d, %08x\n", r.d[0], r.a[0]));
  411.     if ((r.d[0] & 0xffff) || !(r.a[0] & (1 << gestaltHasFileSystemManager))) {
  412.         printf("WARNING: No FSM present, disabling ExtFS\n");
  413.         return;
  414.     }
  415.  
  416.     // Yes, version >=1.2?
  417.     r.d[0] = gestaltFSMVersion;
  418.     Execute68kTrap(0xa1ad, &r);    // Gestalt()
  419.     D(bug("FSMVersion %d, %08x\n", r.d[0], r.a[0]));
  420.     if ((r.d[0] & 0xffff) || (r.a[0] < 0x0120)) {
  421.         printf("WARNING: FSM <1.2 found, disabling ExtFS\n");
  422.         return;
  423.     }
  424.  
  425.     D(bug("FSM present\n"));
  426.  
  427.     // Yes, allocate file system stack
  428.     r.d[0] = STACK_SIZE;
  429.     Execute68kTrap(0xa71e, &r);        // NewPtrSysClear()
  430.     if (r.a[0] == 0)
  431.         return;
  432.     uint32 fs_stack = r.a[0];
  433.  
  434.     // Allocate memory for our data structures and 68k code
  435.     r.d[0] = SIZEOF_fsdat;
  436.     Execute68kTrap(0xa71e, &r);        // NewPtrSysClear()
  437.     if (r.a[0] == 0)
  438.         return;
  439.     fs_data = r.a[0];
  440.  
  441.     // Set up 68k code fragments
  442.     int p = fs_data + fsCommProcStub;
  443.     WriteMacInt16(p, M68K_EMUL_OP_EXTFS_COMM); p += 2;
  444.     WriteMacInt16(p, M68K_RTD); p += 2;
  445.     WriteMacInt16(p, 10); p += 2;
  446.     if (p - fs_data != fsHFSProcStub)
  447.         goto fsdat_error;
  448.     WriteMacInt16(p, M68K_EMUL_OP_EXTFS_HFS); p += 2;
  449.     WriteMacInt16(p, M68K_RTD); p += 2;
  450.     WriteMacInt16(p, 16);
  451.     p = fs_data + fsAllocateVCB;
  452.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  453.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  454.     WriteMacInt16(p, 0x2f09); p+= 2;    // move.l a1,-(sp)
  455.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  456.     WriteMacInt16(p, 0x7006); p+= 2;    // UTAllocateVCB
  457.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  458.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  459.     WriteMacInt16(p, M68K_RTS); p+= 2;
  460.     if (p - fs_data != fsAddNewVCB)
  461.         goto fsdat_error;
  462.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  463.     WriteMacInt16(p, 0x3f00); p+= 2;    // move.w d0,-(sp)
  464.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(a7)
  465.     WriteMacInt16(p, 0x2f09); p+= 2;    // move.l a1,-(a7)
  466.     WriteMacInt16(p, 0x7007); p+= 2;    // UTAddNewVCB
  467.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  468.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  469.     WriteMacInt16(p, M68K_RTS); p+= 2;
  470.     if (p - fs_data != fsDetermineVol)
  471.         goto fsdat_error;
  472.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  473.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  474.     WriteMacInt16(p, 0x2f09); p+= 2;    // move.l a1,-(sp)
  475.     WriteMacInt16(p, 0x2f0a); p+= 2;    // move.l a2,-(sp)
  476.     WriteMacInt16(p, 0x2f0b); p+= 2;    // move.l a3,-(sp)
  477.     WriteMacInt16(p, 0x2f0c); p+= 2;    // move.l a4,-(sp)
  478.     WriteMacInt16(p, 0x701d); p+= 2;    // UTDetermineVol
  479.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  480.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  481.     WriteMacInt16(p, M68K_RTS); p+= 2;
  482.     if (p - fs_data != fsResolveWDCB)
  483.         goto fsdat_error;
  484.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  485.     WriteMacInt16(p, 0x2f00); p+= 2;    // move.l d0,-(sp)
  486.     WriteMacInt16(p, 0x3f01); p+= 2;    // move.w d1,-(sp)
  487.     WriteMacInt16(p, 0x3f02); p+= 2;    // move.w d2,-(sp)
  488.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  489.     WriteMacInt16(p, 0x700e); p+= 2;    // UTResolveWDCB
  490.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  491.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  492.     WriteMacInt16(p, M68K_RTS); p+= 2;
  493.     if (p - fs_data != fsGetDefaultVol)
  494.         goto fsdat_error;
  495.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  496.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  497.     WriteMacInt16(p, 0x7012); p+= 2;    // UTGetDefaultVol
  498.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  499.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  500.     WriteMacInt16(p, M68K_RTS); p+= 2;
  501.     if (p - fs_data != fsGetPathComponentName)
  502.         goto fsdat_error;
  503.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  504.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  505.     WriteMacInt16(p, 0x701c); p+= 2;    // UTGetPathComponentName
  506.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  507.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  508.     WriteMacInt16(p, M68K_RTS); p+= 2;
  509.     if (p - fs_data != fsParsePathname)
  510.         goto fsdat_error;
  511.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  512.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  513.     WriteMacInt16(p, 0x2f09); p+= 2;    // move.l a1,-(sp)
  514.     WriteMacInt16(p, 0x701b); p+= 2;    // UTParsePathname
  515.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  516.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  517.     WriteMacInt16(p, M68K_RTS); p+= 2;
  518.     if (p - fs_data != fsDisposeVCB)
  519.         goto fsdat_error;
  520.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  521.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  522.     WriteMacInt16(p, 0x7008); p+= 2;    // UTDisposeVCB
  523.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  524.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  525.     WriteMacInt16(p, M68K_RTS); p+= 2;
  526.     if (p - fs_data != fsCheckWDRefNum)
  527.         goto fsdat_error;
  528.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  529.     WriteMacInt16(p, 0x3f00); p+= 2;    // move.w d0,-(sp)
  530.     WriteMacInt16(p, 0x7013); p+= 2;    // UTCheckWDRefNum
  531.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  532.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  533.     WriteMacInt16(p, M68K_RTS); p+= 2;
  534.     if (p - fs_data != fsSetDefaultVol)
  535.         goto fsdat_error;
  536.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  537.     WriteMacInt16(p, 0x2f00); p+= 2;    // move.l d0,-(sp)
  538.     WriteMacInt16(p, 0x2f01); p+= 2;    // move.l d1,-(sp)
  539.     WriteMacInt16(p, 0x3f02); p+= 2;    // move.w d2,-(sp)
  540.     WriteMacInt16(p, 0x7011); p+= 2;    // UTSetDefaultVol
  541.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  542.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  543.     WriteMacInt16(p, M68K_RTS); p+= 2;
  544.     if (p - fs_data != fsAllocateFCB)
  545.         goto fsdat_error;
  546.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  547.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  548.     WriteMacInt16(p, 0x2f09); p+= 2;    // move.l a1,-(sp)
  549.     WriteMacInt16(p, 0x7000); p+= 2;    // UTAllocateFCB
  550.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  551.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  552.     WriteMacInt16(p, M68K_RTS); p+= 2;
  553.     if (p - fs_data != fsReleaseFCB)
  554.         goto fsdat_error;
  555.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  556.     WriteMacInt16(p, 0x3f00); p+= 2;    // move.w d0,-(sp)
  557.     WriteMacInt16(p, 0x7001); p+= 2;    // UTReleaseFCB
  558.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  559.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  560.     WriteMacInt16(p, M68K_RTS); p+= 2;
  561.     if (p - fs_data != fsIndexFCB)
  562.         goto fsdat_error;
  563.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  564.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  565.     WriteMacInt16(p, 0x2f09); p+= 2;    // move.l a1,-(sp)
  566.     WriteMacInt16(p, 0x2f0a); p+= 2;    // move.l a2,-(sp)
  567.     WriteMacInt16(p, 0x7004); p+= 2;    // UTIndexFCB
  568.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  569.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  570.     WriteMacInt16(p, M68K_RTS); p+= 2;
  571.     if (p - fs_data != fsResolveFCB)
  572.         goto fsdat_error;
  573.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  574.     WriteMacInt16(p, 0x3f00); p+= 2;    // move.w d0,-(sp)
  575.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  576.     WriteMacInt16(p, 0x7005); p+= 2;    // UTResolveFCB
  577.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  578.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  579.     WriteMacInt16(p, M68K_RTS); p+= 2;
  580.     if (p - fs_data != fsAdjustEOF)
  581.         goto fsdat_error;
  582.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  583.     WriteMacInt16(p, 0x3f00); p+= 2;    // move.w d0,-(sp)
  584.     WriteMacInt16(p, 0x7010); p+= 2;    // UTAdjustEOF
  585.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  586.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  587.     WriteMacInt16(p, M68K_RTS); p+= 2;
  588.     if (p - fs_data != fsAllocateWDCB)
  589.         goto fsdat_error;
  590.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  591.     WriteMacInt16(p, 0x2f08); p+= 2;    // move.l a0,-(sp)
  592.     WriteMacInt16(p, 0x700c); p+= 2;    // UTAllocateWDCB
  593.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  594.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  595.     WriteMacInt16(p, M68K_RTS); p+= 2;
  596.     if (p - fs_data != fsReleaseWDCB)
  597.         goto fsdat_error;
  598.     WriteMacInt16(p, 0x4267); p+= 2;    // clr.w -(sp)
  599.     WriteMacInt16(p, 0x3f00); p+= 2;    // move.w d0,-(sp)
  600.     WriteMacInt16(p, 0x700d); p+= 2;    // UTReleaseWDCB
  601.     WriteMacInt16(p, 0xa824); p+= 2;    // FSMgr
  602.     WriteMacInt16(p, 0x301f); p+= 2;    // move.w (sp)+,d0
  603.     WriteMacInt16(p, M68K_RTS); p+= 2;
  604.     if (p - fs_data != SIZEOF_fsdat)
  605.         goto fsdat_error;
  606.  
  607.     // Set up drive status
  608.     WriteMacInt8(fs_data + fsDrvStatus + dsDiskInPlace, 8);    // Fixed disk
  609.     WriteMacInt8(fs_data + fsDrvStatus + dsInstalled, 1);
  610.     WriteMacInt16(fs_data + fsDrvStatus + dsQType, hard20);
  611.     WriteMacInt16(fs_data + fsDrvStatus + dsDriveSize, num_blocks & 0xffff);
  612.     WriteMacInt16(fs_data + fsDrvStatus + dsDriveS1, num_blocks >> 16);
  613.     WriteMacInt16(fs_data + fsDrvStatus + dsQFSID, MY_FSID);
  614.  
  615.     // Add drive to drive queue
  616.     drive_number = FindFreeDriveNumber(1);
  617.     D(bug(" adding drive %d\n", drive_number));
  618.     r.d[0] = (drive_number << 16) | (DiskRefNum & 0xffff);
  619.     r.a[0] = fs_data + fsDrvStatus + dsQLink;
  620.     Execute68kTrap(0xa04e, &r);    // AddDrive()
  621.  
  622.     // Init FSDRec and install file system
  623.     D(bug(" installing file system\n"));
  624.     WriteMacInt16(fs_data + fsFSD + fsdLength, SIZEOF_FSDRec);
  625.     WriteMacInt16(fs_data + fsFSD + fsdVersion, fsdVersion1);
  626.     WriteMacInt16(fs_data + fsFSD + fileSystemFSID, MY_FSID);
  627.     Host2Mac_memcpy(fs_data + fsFSD + fileSystemName, FS_NAME, 32);
  628.     WriteMacInt32(fs_data + fsFSD + fileSystemCommProc, fs_data + fsCommProcStub);
  629.     WriteMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfProc, fs_data + fsHFSProcStub);
  630.     WriteMacInt32(fs_data + fsFSD + fsdHFSCI + stackTop, fs_stack + STACK_SIZE);
  631.     WriteMacInt32(fs_data + fsFSD + fsdHFSCI + stackSize, STACK_SIZE);
  632.     WriteMacInt32(fs_data + fsFSD + fsdHFSCI + idSector, (uint32)-1);
  633.     r.a[0] = fs_data + fsFSD;
  634.     r.d[0] = 0;                    // InstallFS
  635.     Execute68kTrap(0xa0ac, &r);    // FSMDispatch()
  636.     D(bug(" InstallFS() returned %d\n", r.d[0]));
  637.  
  638.     // Enable HFS component
  639.     D(bug(" enabling HFS component\n"));
  640.     WriteMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfMask, ReadMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfMask) | (fsmComponentEnableMask | hfsCIResourceLoadedMask | hfsCIDoesHFSMask));
  641.     r.a[0] = fs_data + fsFSD;
  642.     r.d[3] = SIZEOF_FSDRec;
  643.     r.d[4] = MY_FSID;
  644.     r.d[0] = 5;                    // SetFSInfo
  645.     Execute68kTrap(0xa0ac, &r);    // FSMDispatch()
  646.     D(bug(" SetFSInfo() returned %d\n", r.d[0]));
  647.  
  648.     // Mount volume
  649.     D(bug(" mounting volume\n"));
  650.     WriteMacInt32(fs_data + fsPB + ioBuffer, fs_data + fsVMI);
  651.     WriteMacInt16(fs_data + fsVMI + vmiLength, SIZEOF_VolumeMountInfoHeader);
  652.     WriteMacInt32(fs_data + fsVMI + vmiMedia, MY_MEDIA_TYPE);
  653.     r.a[0] = fs_data + fsPB;
  654.     r.d[0] = 0x41;                // PBVolumeMount
  655.     Execute68kTrap(0xa260, &r);    // HFSDispatch()
  656.     D(bug(" PBVolumeMount() returned %d\n", r.d[0]));
  657.     return;
  658.  
  659. fsdat_error:
  660.     printf("FATAL: ExtFS data block initialization error\n");
  661.     QuitEmulator();
  662. }
  663.  
  664.  
  665. /*
  666.  *  FS communications function
  667.  */
  668.  
  669. int16 ExtFSComm(uint16 message, uint32 paramBlock, uint32 globalsPtr)
  670. {
  671.     D(bug("ExtFSComm(%d, %08lx, %08lx)\n", message, paramBlock, globalsPtr));
  672.  
  673.     switch (message) {
  674.         case ffsNopMessage:
  675.         case ffsLoadMessage:
  676.         case ffsUnloadMessage:
  677.             return noErr;
  678.  
  679.         case ffsGetIconMessage: {        // Get disk/drive icon
  680.             if (ReadMacInt8(paramBlock + iconType) == kLargeIcon && ReadMacInt32(paramBlock + requestSize) >= sizeof(ExtFSIcon)) {
  681.                 Host2Mac_memcpy(ReadMacInt32(paramBlock + iconBufferPtr), ExtFSIcon, sizeof(ExtFSIcon));
  682.                 WriteMacInt32(paramBlock + actualSize, sizeof(ExtFSIcon));
  683.                 return noErr;
  684.             } else
  685.                 return -5012;    // afpItemNotFound
  686.         }
  687.  
  688.         case ffsIDDiskMessage: {        // Check if volume is handled by our FS
  689.             if ((int16)ReadMacInt16(paramBlock + ioVRefNum) == drive_number)
  690.                 return noErr;
  691.             else
  692.                 return extFSErr;
  693.         }
  694.  
  695.         case ffsIDVolMountMessage: {    // Check if volume can be mounted by our FS
  696.             if (ReadMacInt32(ReadMacInt32(paramBlock + ioBuffer) + vmiMedia) == MY_MEDIA_TYPE)
  697.                 return noErr;
  698.             else
  699.                 return extFSErr;
  700.         }
  701.  
  702.         default:
  703.             return fsmUnknownFSMMessageErr;
  704.     }
  705. }
  706.  
  707.  
  708. /*
  709.  *  Get current directory specified by given ParamBlock/dirID
  710.  */
  711.  
  712. static int16 get_current_dir(uint32 pb, uint32 dirID, uint32 ¤t_dir, bool no_vol_name = false)
  713. {
  714.     M68kRegisters r;
  715.     int16 result;
  716.  
  717.     // Determine volume
  718.     D(bug("  determining volume, dirID %d\n", dirID));
  719.     r.a[0] = pb;
  720.     r.a[1] = fs_data + fsReturn;
  721.     r.a[2] = fs_data + fsReturn + 2;
  722.     r.a[3] = fs_data + fsReturn + 4;
  723.     r.a[4] = fs_data + fsReturn + 6;
  724.     uint32 name_ptr = 0;
  725.     if (no_vol_name) {
  726.         name_ptr = ReadMacInt32(pb + ioNamePtr);
  727.         WriteMacInt32(pb + ioNamePtr, 0);
  728.     }
  729.     Execute68k(fs_data + fsDetermineVol, &r);
  730.     if (no_vol_name)
  731.         WriteMacInt32(pb + ioNamePtr, name_ptr);
  732.     int16 status = ReadMacInt16(fs_data + fsReturn);
  733.     int16 more_matches = ReadMacInt16(fs_data + fsReturn + 2);
  734.     int16 vRefNum = ReadMacInt16(fs_data + fsReturn + 4);
  735.     uint32 vcb = ReadMacInt32(fs_data + fsReturn + 6);
  736.     D(bug("  UTDetermineVol() returned %d, status %d\n", r.d[0], status));
  737.     result = (int16)(r.d[0] & 0xffff);
  738.  
  739.     if (result == noErr) {
  740.         switch (status) {
  741.             case dtmvFullPathname:    // Determined by full pathname
  742.                 current_dir = ROOT_ID;
  743.                 break;
  744.  
  745.             case dtmvVRefNum:        // Determined by refNum or by drive number
  746.             case dtmvDriveNum:
  747.                 current_dir = dirID ? dirID : ROOT_ID;
  748.                 break;
  749.  
  750.             case dtmvWDRefNum:        // Determined by working directory refNum
  751.                 if (dirID)
  752.                     current_dir = dirID;
  753.                 else {
  754.                     D(bug("  resolving WDCB\n"));
  755.                     r.d[0] = 0;
  756.                     r.d[1] = 0;
  757.                     r.d[2] = ReadMacInt16(pb + ioVRefNum);
  758.                     r.a[0] = fs_data + fsReturn;
  759.                     Execute68k(fs_data + fsResolveWDCB, &r);
  760.                     uint32 wdcb = ReadMacInt32(fs_data + fsReturn);
  761.                     D(bug("  UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID)));
  762.                     result = (int16)(r.d[0] & 0xffff);
  763.                     if (result == noErr)
  764.                         current_dir = ReadMacInt32(wdcb + wdDirID);
  765.                 }
  766.                 break;
  767.  
  768.             case dtmvDefault:        // Determined by default volume
  769.                 if (dirID)
  770.                     current_dir = dirID;
  771.                 else {
  772.                     uint32 wdpb = fs_data + fsReturn;
  773.                     WriteMacInt32(wdpb + ioNamePtr, 0);
  774.                     D(bug("  getting default volume\n"));
  775.                     r.a[0] = wdpb;
  776.                     Execute68k(fs_data + fsGetDefaultVol, &r);
  777.                     D(bug("  UTGetDefaultVol() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdpb + ioWDDirID)));
  778.                     result = (int16)(r.d[0] & 0xffff);
  779.                     if (result == noErr)
  780.                         current_dir = ReadMacInt32(wdpb + ioWDDirID);
  781.                 }
  782.                 break;
  783.  
  784.             default:
  785.                 result = paramErr;
  786.                 break;
  787.         }
  788.     }
  789.     return result;
  790. }
  791.  
  792.  
  793. /*
  794.  *  Get path component name
  795.  */
  796.  
  797. static int16 get_path_component_name(uint32 rec)
  798. {
  799. //    D(bug("  getting path component\n"));
  800.     M68kRegisters r;
  801.     r.a[0] = rec;
  802.     Execute68k(fs_data + fsGetPathComponentName, &r);
  803. //    D(bug("  UTGetPathComponentName returned %d\n", r.d[0]));
  804.     return (int16)(r.d[0] & 0xffff);
  805. }
  806.  
  807.  
  808. /*
  809.  *  Get FSItem and full path (->full_path) for file/dir specified in ParamBlock
  810.  */
  811.  
  812. static int16 get_item_and_path(uint32 pb, uint32 dirID, FSItem *&item, bool no_vol_name = false)
  813. {
  814.     M68kRegisters r;
  815.  
  816.     // Find FSItem for parent directory
  817.     int16 result;
  818.     uint32 current_dir;
  819.     if ((result = get_current_dir(pb, dirID, current_dir, no_vol_name)) != noErr)
  820.         return result;
  821.     D(bug("  current dir %08x\n", current_dir));
  822.     FSItem *p = find_fsitem_by_id(current_dir);
  823.     if (p == NULL)
  824.         return dirNFErr;
  825.  
  826.     // Start parsing
  827.     uint32 parseRec = fs_data + fsParseRec;
  828.     WriteMacInt32(parseRec + ppNamePtr, ReadMacInt32(pb + ioNamePtr));
  829.     WriteMacInt16(parseRec + ppStartOffset, 0);
  830.     WriteMacInt16(parseRec + ppComponentLength, 0);
  831.     WriteMacInt8(parseRec + ppMoreName, false);
  832.     WriteMacInt8(parseRec + ppFoundDelimiter, false);
  833.  
  834.     // Get length of volume name
  835.     D(bug("  parsing pathname\n"));
  836.     r.a[0] = parseRec + ppStartOffset;
  837.     r.a[1] = ReadMacInt32(parseRec + ppNamePtr);
  838.     Execute68k(fs_data + fsParsePathname, &r);
  839.     D(bug("  UTParsePathname() returned %d, startOffset %d\n", r.d[0], ReadMacInt16(parseRec + ppStartOffset)));
  840.     result = (int16)(r.d[0] & 0xffff);
  841.     if (result == noErr) {
  842.  
  843.         // Check for leading delimiter of the partial pathname
  844.         result = get_path_component_name(parseRec);
  845.         if (result == noErr) {
  846.             if (ReadMacInt16(parseRec + ppComponentLength) == 0 && ReadMacInt8(parseRec + ppFoundDelimiter)) {
  847.                 // Get past initial delimiter
  848.                 WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + 1);
  849.             }
  850.  
  851.             // Parse until there is no more pathname to parse
  852.             while ((result == noErr) && ReadMacInt8(parseRec + ppMoreName)) {
  853.  
  854.                 // Search for the next delimiter from startOffset
  855.                 result = get_path_component_name(parseRec);
  856.                 if (result == noErr) {
  857.                     if (ReadMacInt16(parseRec + ppComponentLength) == 0) {
  858.  
  859.                         // Delimiter immediately following another delimiter, get parent
  860.                         if (current_dir != ROOT_ID) {
  861.                             p = p->parent;
  862.                             current_dir = p->id;
  863.                         } else
  864.                             result = bdNamErr;
  865.  
  866.                         // startOffset = start of next component
  867.                         WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + 1);
  868.  
  869.                     } else if (ReadMacInt8(parseRec + ppMoreName)) {
  870.  
  871.                         // Component found and isn't the last, so it must be a directory, enter it
  872.                         char name[32];
  873.                         strn2cstr(name, (char *)Mac2HostAddr(ReadMacInt32(parseRec + ppNamePtr)) + ReadMacInt16(parseRec + ppStartOffset) + 1, ReadMacInt16(parseRec + ppComponentLength));
  874.                         D(bug("  entering %s\n", name));
  875.                         p = find_fsitem(name, p);
  876.                         current_dir = p->id;
  877.  
  878.                         // startOffset = start of next component
  879.                         WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + ReadMacInt16(parseRec + ppComponentLength) + 1);
  880.                     }
  881.                 }
  882.             }
  883.  
  884.             if (result == noErr) {
  885.  
  886.                 // There is no more pathname to parse
  887.                 if (ReadMacInt16(parseRec + ppComponentLength) == 0) {
  888.  
  889.                     // Pathname ended with '::' or was simply a volume name, so current directory is the object
  890.                     item = p;
  891.  
  892.                 } else {
  893.  
  894.                     // Pathname ended with 'name:' or 'name', so name is the object
  895.                     char name[32];
  896.                     strn2cstr(name, (char *)Mac2HostAddr(ReadMacInt32(parseRec + ppNamePtr)) + ReadMacInt16(parseRec + ppStartOffset) + 1, ReadMacInt16(parseRec + ppComponentLength));
  897.                     D(bug("  object is %s\n", name));
  898.                     item = find_fsitem(name, p);
  899.                 }
  900.             }
  901.         }
  902.  
  903.     } else {
  904.  
  905.         // Default to bad name
  906.         result = bdNamErr;
  907.  
  908.         if (ReadMacInt32(pb + ioNamePtr) == 0 || ReadMacInt8(ReadMacInt32(pb + ioNamePtr)) == 0) {
  909.  
  910.             // Pathname was NULL or a zero length string, so we found a directory at the end of the string
  911.             item = p;
  912.             result = noErr;
  913.         }
  914.     }
  915.  
  916.     // Eat the path
  917.     if (result == noErr) {
  918.         get_path_for_fsitem(item);
  919.         D(bug("  path %s\n", full_path));
  920.     }
  921.     return result;
  922. }
  923.  
  924.  
  925. /*
  926.  *  Find FCB for given file RefNum
  927.  */
  928.  
  929. static uint32 find_fcb(int16 refNum)
  930. {
  931.     D(bug("  finding FCB\n"));
  932.     M68kRegisters r;
  933.     r.d[0] = refNum;
  934.     r.a[0] = fs_data + fsReturn;
  935.     Execute68k(fs_data + fsResolveFCB, &r);
  936.     uint32 fcb = ReadMacInt32(fs_data + fsReturn);
  937.     D(bug("  UTResolveFCB() returned %d, fcb %08lx\n", r.d[0], fcb));
  938.     if (r.d[0] & 0xffff)
  939.         return 0;
  940.     else
  941.         return fcb;
  942. }
  943.  
  944.  
  945. /*
  946.  *  HFS interface functions
  947.  */
  948.  
  949. // Check if volume belongs to our FS
  950. static int16 fs_mount_vol(uint32 pb)
  951. {
  952.     D(bug(" fs_mount_vol(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum)));
  953.     if ((int16)ReadMacInt16(pb + ioVRefNum) == drive_number)
  954.         return noErr;
  955.     else
  956.         return extFSErr;
  957. }
  958.  
  959. // Mount volume
  960. static int16 fs_volume_mount(uint32 pb)
  961. {
  962.     D(bug(" fs_volume_mount(%08lx)\n", pb));
  963.     M68kRegisters r;
  964.  
  965.     // Create new VCB
  966.     D(bug("  creating VCB\n"));
  967.     r.a[0] = fs_data + fsReturn;
  968.     r.a[1] = fs_data + fsReturn + 2;
  969.     Execute68k(fs_data + fsAllocateVCB, &r);
  970.     uint16 sysVCBLength = ReadMacInt16(fs_data + fsReturn);
  971.     uint32 vcb = ReadMacInt32(fs_data + fsReturn + 2);
  972.     D(bug("  UTAllocateVCB() returned %d, vcb %08lx, size %d\n", r.d[0], vcb, sysVCBLength));
  973.     if (r.d[0] & 0xffff)
  974.         return (int16)r.d[0];
  975.  
  976.     // Init VCB
  977.     WriteMacInt16(vcb + vcbSigWord, 0x4244);
  978. #if defined(__BEOS__) || defined(WIN32)
  979.     WriteMacInt32(vcb + vcbCrDate, root_stat.st_crtime + TIME_OFFSET);
  980. #else
  981.     WriteMacInt32(vcb + vcbCrDate, 0);
  982. #endif
  983.     WriteMacInt32(vcb + vcbLsMod, root_stat.st_mtime + TIME_OFFSET);
  984.     WriteMacInt32(vcb + vcbVolBkUp, 0);
  985.     WriteMacInt16(vcb + vcbNmFls, 1);            //!!
  986.     WriteMacInt16(vcb + vcbNmRtDirs, 1);        //!!
  987.     WriteMacInt16(vcb + vcbNmAlBlks, 0xffff);    //!!
  988.     WriteMacInt32(vcb + vcbAlBlkSiz, AL_BLK_SIZE);
  989.     WriteMacInt32(vcb + vcbClpSiz, CLUMP_SIZE);
  990.     WriteMacInt32(vcb + vcbNxtCNID, next_cnid);
  991.     WriteMacInt16(vcb + vcbFreeBks, 0xffff);    //!!
  992.     Host2Mac_memcpy(vcb + vcbVN, VOLUME_NAME, 28);
  993.     WriteMacInt16(vcb + vcbFSID, MY_FSID);
  994.     WriteMacInt32(vcb + vcbFilCnt, 1);            //!!
  995.     WriteMacInt32(vcb + vcbDirCnt, 1);            //!!
  996.  
  997.     // Add VCB to VCB queue
  998.     D(bug("  adding VCB to queue\n"));
  999.     r.d[0] = drive_number;
  1000.     r.a[0] = fs_data + fsReturn;
  1001.     r.a[1] = vcb;
  1002.     Execute68k(fs_data + fsAddNewVCB, &r);
  1003.     int16 vRefNum = (int16)ReadMacInt32(fs_data + fsReturn);
  1004.     D(bug("  UTAddNewVCB() returned %d, vRefNum %d\n", r.d[0], vRefNum));
  1005.     if (r.d[0] & 0xffff)
  1006.         return (int16)r.d[0];
  1007.  
  1008.     // Post diskInsertEvent
  1009.     D(bug("  posting diskInsertEvent\n"));
  1010.     r.d[0] = drive_number;
  1011.     r.a[0] = 7;    // diskEvent
  1012.     Execute68kTrap(0xa02f, &r);        // PostEvent()
  1013.  
  1014.     // Return volume RefNum
  1015.     WriteMacInt16(pb + ioVRefNum, vRefNum);
  1016.     return noErr;
  1017. }
  1018.  
  1019. // Unmount volume
  1020. static int16 fs_unmount_vol(uint32 vcb)
  1021. {
  1022.     D(bug(" fs_unmount_vol(%08lx), vRefNum %d\n", vcb, ReadMacInt16(vcb + vcbVRefNum)));
  1023.     M68kRegisters r;
  1024.  
  1025.     // Remove and free VCB
  1026.     D(bug("  freeing VCB\n"));
  1027.     r.a[0] = vcb;
  1028.     Execute68k(fs_data + fsDisposeVCB, &r);
  1029.     D(bug("  UTDisposeVCB() returned %d\n", r.d[0]));
  1030.     return (int16)r.d[0];
  1031. }
  1032.  
  1033. // Get information about a volume (HVolumeParam)
  1034. static int16 fs_get_vol_info(uint32 pb, bool hfs)
  1035. {
  1036. //    D(bug(" fs_get_vol_info(%08lx)\n", pb));
  1037.  
  1038.     // Fill in struct
  1039.     if (ReadMacInt32(pb + ioNamePtr))
  1040.         pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), VOLUME_NAME);
  1041. #if defined(__BEOS__) || defined(WIN32)
  1042.     WriteMacInt32(pb + ioVCrDate, root_stat.st_crtime + TIME_OFFSET);
  1043. #else
  1044.     WriteMacInt32(pb + ioVCrDate, 0);
  1045. #endif
  1046.     WriteMacInt32(pb + ioVLsMod, root_stat.st_mtime + TIME_OFFSET);
  1047.     WriteMacInt16(pb + ioVAtrb, 0);
  1048.     WriteMacInt16(pb + ioVNmFls, 1);            //!!
  1049.     WriteMacInt16(pb + ioVBitMap, 0);
  1050.     WriteMacInt16(pb + ioAllocPtr, 0);
  1051.     WriteMacInt16(pb + ioVNmAlBlks, 0xffff);    //!!
  1052.     WriteMacInt32(pb + ioVAlBlkSiz, AL_BLK_SIZE);
  1053.     WriteMacInt32(pb + ioVClpSiz, CLUMP_SIZE);
  1054.     WriteMacInt16(pb + ioAlBlSt, 0);
  1055.     WriteMacInt32(pb + ioVNxtCNID, next_cnid);
  1056.     WriteMacInt16(pb + ioVFrBlk, 0xffff);        //!!
  1057.     if (hfs) {
  1058.         WriteMacInt16(pb + ioVDrvInfo, drive_number);
  1059.         WriteMacInt16(pb + ioVDRefNum, ReadMacInt16(fs_data + fsDrvStatus + dsQRefNum));
  1060.         WriteMacInt16(pb + ioVFSID, MY_FSID);
  1061.         WriteMacInt32(pb + ioVBkUp, 0);
  1062.         WriteMacInt16(pb + ioVSeqNum, 0);
  1063.         WriteMacInt32(pb + ioVWrCnt, 0);
  1064.         WriteMacInt32(pb + ioVFilCnt, 1);            //!!
  1065.         WriteMacInt32(pb + ioVDirCnt, 1);            //!!
  1066.         Mac_memset(pb + ioVFndrInfo, 0, 32);
  1067.     }
  1068.     return noErr;
  1069. }
  1070.  
  1071. // Change volume information (HVolumeParam)
  1072. static int16 fs_set_vol_info(uint32 pb)
  1073. {
  1074.     D(bug(" fs_set_vol_info(%08lx)\n", pb));
  1075.  
  1076.     //!! times
  1077.     return noErr;
  1078. }
  1079.  
  1080. // Get volume parameter block
  1081. static int16 fs_get_vol_parms(uint32 pb)
  1082. {
  1083. //    D(bug(" fs_get_vol_parms(%08lx)\n", pb));
  1084.  
  1085.     // Return parameter block
  1086.     uint32 actual = ReadMacInt32(pb + ioReqCount);
  1087.     if (actual > SIZEOF_GetVolParmsInfoBuffer)
  1088.         actual = SIZEOF_GetVolParmsInfoBuffer;
  1089.     WriteMacInt32(pb + ioActCount, actual);
  1090.     uint32 p = ReadMacInt32(pb + ioBuffer);
  1091.     if (actual > vMVersion) WriteMacInt16(p + vMVersion, 2);
  1092.     if (actual > vMAttrib) WriteMacInt32(p + vMAttrib, kNoMiniFndr | kNoVNEdit | kNoLclSync | kTrshOffLine | kNoSwitchTo | kNoBootBlks | kNoSysDir | kHasExtFSVol);
  1093.     if (actual > vMLocalHand) WriteMacInt32(p + vMLocalHand, 0);
  1094.     if (actual > vMServerAdr) WriteMacInt32(p + vMServerAdr, 0);
  1095.     if (actual > vMVolumeGrade) WriteMacInt32(p + vMVolumeGrade, 0);
  1096.     if (actual > vMForeignPrivID) WriteMacInt16(p + vMForeignPrivID, 0);
  1097.     return noErr;
  1098. }
  1099.  
  1100. // Get default volume (WDParam)
  1101. static int16 fs_get_vol(uint32 pb)
  1102. {
  1103.     D(bug(" fs_get_vol(%08lx)\n", pb));
  1104.     M68kRegisters r;
  1105.  
  1106.     // Getting default volume
  1107.     D(bug("  getting default volume\n"));
  1108.     r.a[0] = pb;
  1109.     Execute68k(fs_data + fsGetDefaultVol, &r);
  1110.     D(bug("  UTGetDefaultVol() returned %d\n", r.d[0]));
  1111.     return (int16)r.d[0];
  1112. }
  1113.  
  1114. // Set default volume (WDParam)
  1115. static int16 fs_set_vol(uint32 pb, bool hfs, uint32 vcb)
  1116. {
  1117.     D(bug(" fs_set_vol(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioWDDirID)));
  1118.     M68kRegisters r;
  1119.  
  1120.     // Determine parameters
  1121.     uint32 dirID;
  1122.     int16 refNum;
  1123.     if (hfs) {
  1124.  
  1125.         // Find FSItem for given dir
  1126.         FSItem *fs_item;
  1127.         int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioWDDirID), fs_item);
  1128.         if (result != noErr)
  1129.             return result;
  1130.  
  1131.         // Is it a directory?
  1132.         struct stat st;
  1133.         if (stat(full_path, &st))
  1134.             return dirNFErr;
  1135.         if (!S_ISDIR(st.st_mode))
  1136.             return dirNFErr;
  1137.  
  1138.         // Get dirID and refNum
  1139.         dirID = fs_item->id;
  1140.         refNum = ReadMacInt16(vcb + vcbVRefNum);
  1141.  
  1142.     } else {
  1143.  
  1144.         // Is the given vRefNum a working directory number?
  1145.         D(bug("  checking for WDRefNum\n"));
  1146.         r.d[0] = ReadMacInt16(pb + ioVRefNum);
  1147.         Execute68k(fs_data + fsCheckWDRefNum, &r);
  1148.         D(bug("  UTCheckWDRefNum() returned %d\n", r.d[0]));
  1149.         if (r.d[0] & 0xffff) {
  1150.             // Volume refNum
  1151.             dirID = ROOT_ID;
  1152.             refNum = ReadMacInt16(vcb + vcbVRefNum);
  1153.         } else {
  1154.             // WD refNum
  1155.             dirID = 0;
  1156.             refNum = ReadMacInt16(pb + ioVRefNum);
  1157.         }
  1158.     }
  1159.  
  1160.     // Setting default volume
  1161.     D(bug("  setting default volume\n"));
  1162.     r.d[0] = 0;
  1163.     r.d[1] = dirID;
  1164.     r.d[2] = refNum;
  1165.     Execute68k(fs_data + fsSetDefaultVol, &r);
  1166.     D(bug("  UTSetDefaultVol() returned %d\n", r.d[0]));
  1167.     return (int16)r.d[0];
  1168. }
  1169.  
  1170. // Query file attributes (HFileParam)
  1171. static int16 fs_get_file_info(uint32 pb, bool hfs, uint32 dirID)
  1172. {
  1173.     D(bug(" fs_get_file_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), dirID));
  1174.  
  1175.     FSItem *fs_item;
  1176.     int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
  1177.     if (dir_index <= 0) {        // Query item specified by ioDirID and ioNamePtr
  1178.  
  1179.         // Find FSItem for given file
  1180.         int16 result = get_item_and_path(pb, dirID, fs_item);
  1181.         if (result != noErr)
  1182.             return result;
  1183.  
  1184.     } else {                    // Query item in directory specified by ioDirID by index
  1185.  
  1186.         // Find FSItem for parent directory
  1187.         int16 result;
  1188.         uint32 current_dir;
  1189.         if ((result = get_current_dir(pb, dirID, current_dir, true)) != noErr)
  1190.             return result;
  1191.         FSItem *p = find_fsitem_by_id(current_dir);
  1192.         if (p == NULL)
  1193.             return dirNFErr;
  1194.         get_path_for_fsitem(p);
  1195.  
  1196.         // Look for nth item in directory and add name to path
  1197.         DIR *d = opendir(full_path);
  1198.         if (d == NULL)
  1199.             return dirNFErr;
  1200.         struct dirent *de = NULL;
  1201.         for (int i=0; i<dir_index; i++) {
  1202. read_next_de:
  1203.             de = readdir(d);
  1204.             if (de == NULL) {
  1205.                 closedir(d);
  1206.                 return fnfErr;
  1207.             }
  1208.             if (de->d_name[0] == '.')
  1209.                 goto read_next_de;    // Suppress names beginning with '.' (MacOS could interpret these as driver names)
  1210.             //!! suppress directories
  1211.         }
  1212.         add_path_comp(de->d_name);
  1213.  
  1214.         // Get FSItem for queried item
  1215.         fs_item = find_fsitem(de->d_name, p);
  1216.         closedir(d);
  1217.     }
  1218.  
  1219.     // Get stats
  1220.     struct stat st;
  1221.     if (stat(full_path, &st))
  1222.         return fnfErr;
  1223.     if (S_ISDIR(st.st_mode))
  1224.         return fnfErr;
  1225.  
  1226.     // Fill in struct from fs_item and stats
  1227.     if (ReadMacInt32(pb + ioNamePtr))
  1228.         cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->name);
  1229.     WriteMacInt16(pb + ioFRefNum, 0);
  1230.     WriteMacInt8(pb + ioFlAttrib, access(full_path, W_OK) == 0 ? 0 : faLocked);
  1231.     WriteMacInt32(pb + ioDirID, fs_item->id);
  1232.  
  1233. #if defined(__BEOS__) || defined(WIN32)
  1234.     WriteMacInt32(pb + ioFlCrDat, st.st_crtime + TIME_OFFSET);
  1235. #else
  1236.     WriteMacInt32(pb + ioFlCrDat, 0);
  1237. #endif
  1238.     WriteMacInt32(pb + ioFlMdDat, st.st_mtime + TIME_OFFSET);
  1239.  
  1240.     get_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false);
  1241.  
  1242.     WriteMacInt16(pb + ioFlStBlk, 0);
  1243.     WriteMacInt32(pb + ioFlLgLen, st.st_size);
  1244.     WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
  1245.     WriteMacInt16(pb + ioFlRStBlk, 0);
  1246.     uint32 rf_size = get_rfork_size(full_path);
  1247.     WriteMacInt32(pb + ioFlRLgLen, rf_size);
  1248.     WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1);
  1249.  
  1250.     if (hfs) {
  1251.         WriteMacInt32(pb + ioFlBkDat, 0);
  1252.         WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
  1253.         WriteMacInt32(pb + ioFlClpSiz, 0);
  1254.     }
  1255.     return noErr;
  1256. }
  1257.  
  1258. // Set file attributes (HFileParam)
  1259. static int16 fs_set_file_info(uint32 pb, bool hfs, uint32 dirID)
  1260. {
  1261.     D(bug(" fs_set_file_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), dirID));
  1262.  
  1263.     // Find FSItem for given file/dir
  1264.     FSItem *fs_item;
  1265.     int16 result = get_item_and_path(pb, dirID, fs_item);
  1266.     if (result != noErr)
  1267.         return result;
  1268.  
  1269.     // Get stats
  1270.     struct stat st;
  1271.     if (stat(full_path, &st) < 0)
  1272.         return errno2oserr();
  1273.     if (S_ISDIR(st.st_mode))
  1274.         return fnfErr;
  1275.  
  1276.     // Set Finder info
  1277.     set_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false);
  1278.  
  1279.     //!! times
  1280.     return noErr;
  1281. }
  1282.  
  1283. // Query file/directory attributes
  1284. static int16 fs_get_cat_info(uint32 pb)
  1285. {
  1286.     D(bug(" fs_get_cat_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID)));
  1287.  
  1288.     FSItem *fs_item;
  1289.     int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
  1290.     if (dir_index < 0) {            // Query directory specified by ioDirID
  1291.  
  1292.         // Find FSItem for directory
  1293.         fs_item = find_fsitem_by_id(ReadMacInt32(pb + ioDrDirID));
  1294.         if (fs_item == NULL)
  1295.             return dirNFErr;
  1296.         get_path_for_fsitem(fs_item);
  1297.  
  1298.     } else if (dir_index == 0) {    // Query item specified by ioDirID and ioNamePtr
  1299.  
  1300.         // Find FSItem for given file/dir
  1301.         int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
  1302.         if (result != noErr)
  1303.             return result;
  1304.  
  1305.     } else {                            // Query item in directory specified by ioDirID by index
  1306.  
  1307.         // Find FSItem for parent directory
  1308.         int16 result;
  1309.         uint32 current_dir;
  1310.         if ((result = get_current_dir(pb, ReadMacInt32(pb + ioDirID), current_dir, true)) != noErr)
  1311.             return result;
  1312.         FSItem *p = find_fsitem_by_id(current_dir);
  1313.         if (p == NULL)
  1314.             return dirNFErr;
  1315.         get_path_for_fsitem(p);
  1316.  
  1317.         // Look for nth item in directory and add name to path
  1318.         DIR *d = opendir(full_path);
  1319.         if (d == NULL)
  1320.             return dirNFErr;
  1321.         struct dirent *de = NULL;
  1322.         for (int i=0; i<dir_index; i++) {
  1323. read_next_de:
  1324.             de = readdir(d);
  1325.             if (de == NULL) {
  1326.                 closedir(d);
  1327.                 return fnfErr;
  1328.             }
  1329.             if (de->d_name[0] == '.')
  1330.                 goto read_next_de;    // Suppress names beginning with '.' (MacOS could interpret these as driver names)
  1331.         }
  1332.         add_path_comp(de->d_name);
  1333.  
  1334.         // Get FSItem for queried item
  1335.         fs_item = find_fsitem(de->d_name, p);
  1336.         closedir(d);
  1337.     }
  1338.     D(bug("  path %s\n", full_path));
  1339.  
  1340.     // Get stats
  1341.     struct stat st;
  1342.     if (stat(full_path, &st) < 0)
  1343.         return errno2oserr();
  1344.     if (dir_index == -1 && !S_ISDIR(st.st_mode))
  1345.         return dirNFErr;
  1346.  
  1347.     // Fill in struct from fs_item and stats
  1348.     if (ReadMacInt32(pb + ioNamePtr))
  1349.         cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->name);
  1350.     WriteMacInt16(pb + ioFRefNum, 0);
  1351.     WriteMacInt8(pb + ioFlAttrib, (S_ISDIR(st.st_mode) ? faIsDir : 0) | (access(full_path, W_OK) == 0 ? 0 : faLocked));
  1352.     WriteMacInt8(pb + ioACUser, 0);
  1353.     WriteMacInt32(pb + ioDirID, fs_item->id);
  1354.     WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
  1355. #if defined(__BEOS__) || defined(WIN32)
  1356.     WriteMacInt32(pb + ioFlCrDat, st.st_crtime + TIME_OFFSET);
  1357. #else
  1358.     WriteMacInt32(pb + ioFlCrDat, 0);
  1359. #endif
  1360.     time_t mtime = st.st_mtime;
  1361.     bool cached = true;
  1362.     if (mtime > fs_item->mtime) {
  1363.         fs_item->mtime = mtime;
  1364.         cached = false;
  1365.     }
  1366.     WriteMacInt32(pb + ioFlMdDat, mtime + TIME_OFFSET);
  1367.     WriteMacInt32(pb + ioFlBkDat, 0);
  1368.  
  1369.     get_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode));
  1370.  
  1371.     if (S_ISDIR(st.st_mode)) {
  1372.  
  1373.         // Determine number of files in directory (cached)
  1374.         int count;
  1375.         if (cached)
  1376.             count = fs_item->cache_dircount;
  1377.         else {
  1378.             count = 0;
  1379.             DIR *d = opendir(full_path);
  1380.             if (d) {
  1381.                 struct dirent *de;
  1382.                 for (;;) {
  1383.                     de = readdir(d);
  1384.                     if (de == NULL)
  1385.                         break;
  1386.                     if (de->d_name[0] == '.')
  1387.                         continue;    // Suppress names beginning with '.'
  1388.                     count++;
  1389.                 }
  1390.                 closedir(d);
  1391.             }
  1392.             fs_item->cache_dircount = count;
  1393.         }
  1394.         WriteMacInt16(pb + ioDrNmFls, count);
  1395.     } else {
  1396.         WriteMacInt16(pb + ioFlStBlk, 0);
  1397.         WriteMacInt32(pb + ioFlLgLen, st.st_size);
  1398.         WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
  1399.         WriteMacInt16(pb + ioFlRStBlk, 0);
  1400.         uint32 rf_size = get_rfork_size(full_path);
  1401.         WriteMacInt32(pb + ioFlRLgLen, rf_size);
  1402.         WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1);
  1403.         WriteMacInt32(pb + ioFlClpSiz, 0);
  1404.     }
  1405.     return noErr;
  1406. }
  1407.  
  1408. // Set file/directory attributes
  1409. static int16 fs_set_cat_info(uint32 pb)
  1410. {
  1411.     D(bug(" fs_set_cat_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID)));
  1412.  
  1413.     // Find FSItem for given file/dir
  1414.     FSItem *fs_item;
  1415.     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
  1416.     if (result != noErr)
  1417.         return result;
  1418.  
  1419.     // Get stats
  1420.     struct stat st;
  1421.     if (stat(full_path, &st) < 0)
  1422.         return errno2oserr();
  1423.  
  1424.     // Set Finder info
  1425.     set_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode));
  1426.  
  1427.     //!! times
  1428.     return noErr;
  1429. }
  1430.  
  1431. // Open file
  1432. static int16 fs_open(uint32 pb, uint32 dirID, uint32 vcb, bool resource_fork)
  1433. {
  1434.     D(bug(" fs_open(%08lx), %s, vRefNum %d, name %.31s, dirID %d, perm %d\n", pb, resource_fork ? "rsrc" : "data", ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, ReadMacInt8(pb + ioPermssn)));
  1435.     M68kRegisters r;
  1436.  
  1437.     // Find FSItem for given file
  1438.     FSItem *fs_item;
  1439.     int16 result = get_item_and_path(pb, dirID, fs_item);
  1440.     if (result != noErr)
  1441.         return result;
  1442.  
  1443.     // Convert ioPermssn to open() flag
  1444.     int flag = 0;
  1445.     bool write_ok = (access(full_path, W_OK) == 0);
  1446.     switch (ReadMacInt8(pb + ioPermssn)) {
  1447.         case fsCurPerm:        // Whatever is currently allowed
  1448.             if (write_ok)
  1449.                 flag = O_RDWR;
  1450.             else
  1451.                 flag = O_RDONLY;
  1452.             break;
  1453.         case fsRdPerm:        // Exclusive read
  1454.             flag = O_RDONLY;
  1455.             break;
  1456.         case fsWrPerm:        // Exclusive write
  1457.             flag = O_WRONLY;
  1458.             break;
  1459.         case fsRdWrPerm:    // Exclusive read/write
  1460.         case fsRdWrShPerm:    // Shared read/write
  1461.         default:
  1462.             flag = O_RDWR;
  1463.             break;
  1464.     }
  1465.  
  1466.     // Try to open and stat the file
  1467.     int fd = -1;
  1468.     struct stat st;
  1469.     if (resource_fork) {
  1470.         if (access(full_path, F_OK))
  1471.             return fnfErr;
  1472.         fd = open_rfork(full_path, flag);
  1473.         if (fd >= 0) {
  1474.             if (fstat(fd, &st) < 0) {
  1475.                 close(fd);
  1476.                 return errno2oserr();
  1477.             }
  1478.         } else {    // Resource fork not supported, silently ignore it ("pseudo" resource fork)
  1479.             st.st_size = 0;
  1480.             st.st_mode = 0;
  1481.         }
  1482.     } else {
  1483.         fd = open(full_path, flag);
  1484.         if (fd < 0)
  1485.             return errno2oserr();
  1486.         if (fstat(fd, &st) < 0) {
  1487.             close(fd);
  1488.             return errno2oserr();
  1489.         }
  1490.     }
  1491.  
  1492.     // File open, allocate FCB
  1493.     D(bug("  allocating FCB\n"));
  1494.     r.a[0] = pb + ioRefNum;
  1495.     r.a[1] = fs_data + fsReturn;
  1496.     Execute68k(fs_data + fsAllocateFCB, &r);
  1497.     uint32 fcb = ReadMacInt32(fs_data + fsReturn);
  1498.     D(bug("  UTAllocateFCB() returned %d, fRefNum %d, fcb %08lx\n", r.d[0], ReadMacInt16(pb + ioRefNum), fcb));
  1499.     if (r.d[0] & 0xffff) {
  1500.         close(fd);
  1501.         return (int16)r.d[0];
  1502.     }
  1503.  
  1504.     // Initialize FCB, fd is stored in fcbCatPos
  1505.     WriteMacInt32(fcb + fcbFlNm, fs_item->id);
  1506.     WriteMacInt8(fcb + fcbFlags, ((flag == O_WRONLY || flag == O_RDWR) ? fcbWriteMask : 0) | (resource_fork ? fcbResourceMask : 0) | (write_ok ? 0 : fcbFileLockedMask));
  1507.     WriteMacInt32(fcb + fcbEOF, st.st_size);
  1508.     WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
  1509.     WriteMacInt32(fcb + fcbCrPs, 0);
  1510.     WriteMacInt32(fcb + fcbVPtr, vcb);
  1511.     WriteMacInt32(fcb + fcbClmpSize, CLUMP_SIZE);
  1512.  
  1513.     get_finfo(full_path, fs_data + fsPB, 0, false);
  1514.     WriteMacInt32(fcb + fcbFType, ReadMacInt32(fs_data + fsPB + fdType));
  1515.  
  1516.     WriteMacInt32(fcb + fcbCatPos, fd);
  1517.     WriteMacInt32(fcb + fcbDirID, fs_item->parent_id);
  1518.     cstr2pstr((char *)Mac2HostAddr(fcb + fcbCName), fs_item->name);
  1519.     return noErr;
  1520. }
  1521.  
  1522. // Close file
  1523. static int16 fs_close(uint32 pb)
  1524. {
  1525.     D(bug(" fs_close(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
  1526.     M68kRegisters r;
  1527.  
  1528.     // Find FCB and fd for file
  1529.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1530.     if (fcb == 0)
  1531.         return rfNumErr;
  1532.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1533.         return fnOpnErr;
  1534.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1535.  
  1536.     // Close file
  1537.     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {
  1538.         FSItem *item = find_fsitem_by_id(ReadMacInt32(fcb + fcbFlNm));
  1539.         if (item) {
  1540.             get_path_for_fsitem(item);
  1541.             close_rfork(full_path, fd);
  1542.         }
  1543.     } else
  1544.         close(fd);
  1545.     WriteMacInt32(fcb + fcbCatPos, (uint32)-1);
  1546.  
  1547.     // Release FCB
  1548.     D(bug("  releasing FCB\n"));
  1549.     r.d[0] = ReadMacInt16(pb + ioRefNum);
  1550.     Execute68k(fs_data + fsReleaseFCB, &r);
  1551.     D(bug("  UTReleaseFCB() returned %d\n", r.d[0]));
  1552.     return (int16)r.d[0];
  1553. }
  1554.  
  1555. // Query information about FCB (FCBPBRec)
  1556. static int16 fs_get_fcb_info(uint32 pb, uint32 vcb)
  1557. {
  1558.     D(bug(" fs_get_fcb_info(%08lx), vRefNum %d, refNum %d, idx %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioFCBIndx)));
  1559.     M68kRegisters r;
  1560.  
  1561.     uint32 fcb = 0;
  1562.     if (ReadMacInt16(pb + ioFCBIndx) == 0) {    // Get information about single file
  1563.  
  1564.         // Find FCB for file
  1565.         fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1566.  
  1567.     } else {                    // Get information about file specified by index
  1568.  
  1569.         // Find FCB by index
  1570.         WriteMacInt16(pb + ioRefNum, 0);
  1571.         for (int i=0; i<(int)ReadMacInt16(pb + ioFCBIndx); i++) {
  1572.             D(bug("  indexing FCBs\n"));
  1573.             r.a[0] = vcb;
  1574.             r.a[1] = pb + ioRefNum;
  1575.             r.a[2] = fs_data + fsReturn;
  1576.             Execute68k(fs_data + fsIndexFCB, &r);
  1577.             fcb = ReadMacInt32(fs_data + fsReturn);
  1578.             D(bug("  UTIndexFCB() returned %d, fcb %p\n", r.d[0], fcb));
  1579.             if (r.d[0] & 0xffff)
  1580.                 return (int16)r.d[0];
  1581.         }
  1582.     }
  1583.     if (fcb == 0)
  1584.         return rfNumErr;
  1585.  
  1586.     // Copy information from FCB
  1587.     if (ReadMacInt32(pb + ioNamePtr))
  1588.         pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), (char *)Mac2HostAddr(fcb + fcbCName));
  1589.     WriteMacInt32(pb + ioFCBFlNm, ReadMacInt32(fcb + fcbFlNm));
  1590.     WriteMacInt8(pb + ioFCBFlags, ReadMacInt8(fcb + fcbFlags));
  1591.     WriteMacInt16(pb + ioFCBStBlk, ReadMacInt16(fcb + fcbSBlk));
  1592.     WriteMacInt32(pb + ioFCBEOF, ReadMacInt32(fcb + fcbEOF));
  1593.     WriteMacInt32(pb + ioFCBPLen, ReadMacInt32(fcb + fcbPLen));
  1594.     WriteMacInt32(pb + ioFCBCrPs, ReadMacInt32(fcb + fcbCrPs));
  1595.     WriteMacInt16(pb + ioFCBVRefNum, ReadMacInt16(ReadMacInt32(fcb + fcbVPtr) + vcbVRefNum));
  1596.     WriteMacInt32(pb + ioFCBClpSiz, ReadMacInt32(fcb + fcbClmpSize));
  1597.     WriteMacInt32(pb + ioFCBParID, ReadMacInt32(fcb + fcbDirID));
  1598.     return noErr;
  1599. }
  1600.  
  1601. // Obtain logical size of an open file
  1602. static int16 fs_get_eof(uint32 pb)
  1603. {
  1604.     D(bug(" fs_get_eof(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
  1605.     M68kRegisters r;
  1606.  
  1607.     // Find FCB and fd for file
  1608.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1609.     if (fcb == 0)
  1610.         return rfNumErr;
  1611.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1612.         return fnOpnErr;
  1613.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1614.     if (fd < 0)
  1615.         if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {    // "pseudo" resource fork
  1616.             WriteMacInt32(pb + ioMisc, 0);
  1617.             return noErr;
  1618.         } else
  1619.             return fnOpnErr;
  1620.  
  1621.     // Get file size
  1622.     struct stat st;
  1623.     if (fstat(fd, &st) < 0)
  1624.         return errno2oserr();
  1625.  
  1626.     // Adjust FCBs
  1627.     WriteMacInt32(fcb + fcbEOF, st.st_size);
  1628.     WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
  1629.     WriteMacInt32(pb + ioMisc, st.st_size);
  1630.     D(bug("  adjusting FCBs\n"));
  1631.     r.d[0] = ReadMacInt16(pb + ioRefNum);
  1632.     Execute68k(fs_data + fsAdjustEOF, &r);
  1633.     D(bug("  UTAdjustEOF() returned %d\n", r.d[0]));
  1634.     return noErr;
  1635. }
  1636.  
  1637. // Truncate file
  1638. static int16 fs_set_eof(uint32 pb)
  1639. {
  1640.     D(bug(" fs_set_eof(%08lx), refNum %d, size %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioMisc)));
  1641.     M68kRegisters r;
  1642.  
  1643.     // Find FCB and fd for file
  1644.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1645.     if (fcb == 0)
  1646.         return rfNumErr;
  1647.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1648.         return fnOpnErr;
  1649.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1650.     if (fd < 0)
  1651.         if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask)    // "pseudo" resource fork
  1652.             return noErr;
  1653.         else
  1654.             return fnOpnErr;
  1655.  
  1656.     // Truncate file
  1657.     uint32 size = ReadMacInt32(pb + ioMisc);
  1658.     if (ftruncate(fd, size) < 0)
  1659.         return errno2oserr();
  1660.  
  1661.     // Adjust FCBs
  1662.     WriteMacInt32(fcb + fcbEOF, size);
  1663.     WriteMacInt32(fcb + fcbPLen, (size | (AL_BLK_SIZE - 1)) + 1);
  1664.     D(bug("  adjusting FCBs\n"));
  1665.     r.d[0] = ReadMacInt16(pb + ioRefNum);
  1666.     Execute68k(fs_data + fsAdjustEOF, &r);
  1667.     D(bug("  UTAdjustEOF() returned %d\n", r.d[0]));
  1668.     return noErr;
  1669. }
  1670.  
  1671. // Query current file position
  1672. static int16 fs_get_fpos(uint32 pb)
  1673. {
  1674.     D(bug(" fs_get_fpos(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
  1675.  
  1676.     WriteMacInt32(pb + ioReqCount, 0);
  1677.     WriteMacInt32(pb + ioActCount, 0);
  1678.     WriteMacInt16(pb + ioPosMode, 0);
  1679.  
  1680.     // Find FCB and fd for file
  1681.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1682.     if (fcb == 0)
  1683.         return rfNumErr;
  1684.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1685.         return fnOpnErr;
  1686.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1687.     if (fd < 0)
  1688.         if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {    // "pseudo" resource fork
  1689.             WriteMacInt32(pb + ioPosOffset, 0);
  1690.             return noErr;
  1691.         } else
  1692.             return fnOpnErr;
  1693.  
  1694.     // Get file position
  1695.     uint32 pos = lseek(fd, 0, SEEK_CUR);
  1696.     WriteMacInt32(fcb + fcbCrPs, pos);
  1697.     WriteMacInt32(pb + ioPosOffset, pos);
  1698.     return noErr;
  1699. }
  1700.  
  1701. // Set current file position
  1702. static int16 fs_set_fpos(uint32 pb)
  1703. {
  1704.     D(bug(" fs_set_fpos(%08lx), refNum %d, posMode %d, offset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
  1705.  
  1706.     // Find FCB and fd for file
  1707.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1708.     if (fcb == 0)
  1709.         return rfNumErr;
  1710.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1711.         return fnOpnErr;
  1712.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1713.     if (fd < 0)
  1714.         if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {    // "pseudo" resource fork
  1715.             WriteMacInt32(pb + ioPosOffset, 0);
  1716.             return noErr;
  1717.         } else
  1718.             return fnOpnErr;
  1719.  
  1720.     // Set file position
  1721.     switch (ReadMacInt16(pb + ioPosMode)) {
  1722.         case fsFromStart:
  1723.             if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
  1724.                 return posErr;
  1725.             break;
  1726.         case fsFromLEOF:
  1727.             if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
  1728.                 return posErr;
  1729.             break;
  1730.         case fsFromMark:
  1731.             if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
  1732.                 return posErr;
  1733.             break;
  1734.         default:
  1735.             break;
  1736.     }
  1737.     uint32 pos = lseek(fd, 0, SEEK_CUR);
  1738.     WriteMacInt32(fcb + fcbCrPs, pos);
  1739.     WriteMacInt32(pb + ioPosOffset, pos);
  1740.     return noErr;
  1741. }
  1742.  
  1743. // Read from file
  1744. static int16 fs_read(uint32 pb)
  1745. {
  1746.     D(bug(" fs_read(%08lx), refNum %d, buffer %p, count %d, posMode %d, posOffset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioBuffer), ReadMacInt32(pb + ioReqCount), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
  1747.  
  1748.     // Check parameters
  1749.     if ((int32)ReadMacInt32(pb + ioReqCount) < 0)
  1750.         return paramErr;
  1751.  
  1752.     // Find FCB and fd for file
  1753.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1754.     if (fcb == 0)
  1755.         return rfNumErr;
  1756.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1757.         return fnOpnErr;
  1758.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1759.     if (fd < 0)
  1760.         if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {    // "pseudo" resource fork
  1761.             WriteMacInt32(pb + ioActCount, 0);
  1762.             return eofErr;
  1763.         } else
  1764.             return fnOpnErr;
  1765.  
  1766.     // Seek
  1767.     switch (ReadMacInt16(pb + ioPosMode) & 3) {
  1768.         case fsFromStart:
  1769.             if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
  1770.                 return posErr;
  1771.             break;
  1772.         case fsFromLEOF:
  1773.             if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
  1774.                 return posErr;
  1775.             break;
  1776.         case fsFromMark:
  1777.             if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
  1778.                 return posErr;
  1779.             break;
  1780.     }
  1781.  
  1782.     // Read
  1783.     ssize_t actual = extfs_read(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
  1784.     int16 read_err = errno2oserr();
  1785.     D(bug("  actual %d\n", actual));
  1786.     WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0);
  1787.     uint32 pos = lseek(fd, 0, SEEK_CUR);
  1788.     WriteMacInt32(fcb + fcbCrPs, pos);
  1789.     WriteMacInt32(pb + ioPosOffset, pos);
  1790.     if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount))
  1791.         return actual < 0 ? read_err : eofErr;
  1792.     else
  1793.         return noErr;
  1794. }
  1795.  
  1796. // Write to file
  1797. static int16 fs_write(uint32 pb)
  1798. {
  1799.     D(bug(" fs_write(%08lx), refNum %d, buffer %p, count %d, posMode %d, posOffset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioBuffer), ReadMacInt32(pb + ioReqCount), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
  1800.  
  1801.     // Check parameters
  1802.     if ((int32)ReadMacInt32(pb + ioReqCount) < 0)
  1803.         return paramErr;
  1804.  
  1805.     // Find FCB and fd for file
  1806.     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
  1807.     if (fcb == 0)
  1808.         return rfNumErr;
  1809.     if (ReadMacInt32(fcb + fcbFlNm) == 0)
  1810.         return fnOpnErr;
  1811.     int fd = ReadMacInt32(fcb + fcbCatPos);
  1812.     if (fd < 0)
  1813.         if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {    // "pseudo" resource fork
  1814.             WriteMacInt32(pb + ioActCount, ReadMacInt32(pb + ioReqCount));
  1815.             return noErr;
  1816.         } else
  1817.             return fnOpnErr;
  1818.  
  1819.     // Seek
  1820.     switch (ReadMacInt16(pb + ioPosMode) & 3) {
  1821.         case fsFromStart:
  1822.             if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
  1823.                 return posErr;
  1824.             break;
  1825.         case fsFromLEOF:
  1826.             if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
  1827.                 return posErr;
  1828.             break;
  1829.         case fsFromMark:
  1830.             if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
  1831.                 return posErr;
  1832.             break;
  1833.     }
  1834.  
  1835.     // Write
  1836.     ssize_t actual = extfs_write(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
  1837.     int16 write_err = errno2oserr();
  1838.     D(bug("  actual %d\n", actual));
  1839.     WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0);
  1840.     uint32 pos = lseek(fd, 0, SEEK_CUR);
  1841.     WriteMacInt32(fcb + fcbCrPs, pos);
  1842.     WriteMacInt32(pb + ioPosOffset, pos);
  1843.     if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount))
  1844.         return write_err;
  1845.     else
  1846.         return noErr;
  1847. }
  1848.  
  1849. // Create file
  1850. static int16 fs_create(uint32 pb, uint32 dirID)
  1851. {
  1852.     D(bug(" fs_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID));
  1853.  
  1854.     // Find FSItem for given file
  1855.     FSItem *fs_item;
  1856.     int16 result = get_item_and_path(pb, dirID, fs_item);
  1857.     if (result != noErr)
  1858.         return result;
  1859.  
  1860.     // Does the file already exist?
  1861.     if (access(full_path, F_OK) == 0)
  1862.         return dupFNErr;
  1863.  
  1864.     // Create file
  1865.     int fd = creat(full_path, 0666);
  1866.     if (fd < 0)
  1867.         return errno2oserr();
  1868.     else {
  1869.         close(fd);
  1870.         return noErr;
  1871.     }
  1872. }
  1873.  
  1874. // Create directory
  1875. static int16 fs_dir_create(uint32 pb)
  1876. {
  1877.     D(bug(" fs_dir_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioDirID)));
  1878.  
  1879.     // Find FSItem for given directory
  1880.     FSItem *fs_item;
  1881.     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
  1882.     if (result != noErr)
  1883.         return result;
  1884.  
  1885.     // Does the directory already exist?
  1886.     if (access(full_path, F_OK) == 0)
  1887.         return dupFNErr;
  1888.  
  1889.     // Create directory
  1890.     if (mkdir(full_path, 0777) < 0)
  1891.         return errno2oserr();
  1892.     else {
  1893.         WriteMacInt32(pb + ioDirID, fs_item->id);
  1894.         return noErr;
  1895.     }
  1896. }
  1897.  
  1898. // Delete file/directory
  1899. static int16 fs_delete(uint32 pb, uint32 dirID)
  1900. {
  1901.     D(bug(" fs_delete(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID));
  1902.  
  1903.     // Find FSItem for given file/dir
  1904.     FSItem *fs_item;
  1905.     int16 result = get_item_and_path(pb, dirID, fs_item);
  1906.     if (result != noErr)
  1907.         return result;
  1908.  
  1909.     // Delete file
  1910.     if (!extfs_remove(full_path))
  1911.         return errno2oserr();
  1912.     else
  1913.         return noErr;
  1914. }
  1915.  
  1916. // Rename file/directory
  1917. static int16 fs_rename(uint32 pb, uint32 dirID)
  1918. {
  1919.     D(bug(" fs_rename(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, Mac2HostAddr(ReadMacInt32(pb + ioMisc) + 1)));
  1920.  
  1921.     // Find path of given file/dir
  1922.     FSItem *fs_item;
  1923.     int16 result = get_item_and_path(pb, dirID, fs_item);
  1924.     if (result != noErr)
  1925.         return result;
  1926.  
  1927.     // Save path of existing item
  1928.     char old_path[MAX_PATH_LENGTH];
  1929.     strcpy(old_path, full_path);
  1930.  
  1931.     // Find path for new name
  1932.     Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
  1933.     WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioMisc));
  1934.     FSItem *new_item;
  1935.     result = get_item_and_path(fs_data + fsPB, dirID, new_item);
  1936.     if (result != noErr)
  1937.         return result;
  1938.  
  1939.     // Does the new name already exist?
  1940.     if (access(full_path, F_OK) == 0)
  1941.         return dupFNErr;
  1942.  
  1943.     // Rename item
  1944.     D(bug("  renaming %s -> %s\n", old_path, full_path));
  1945.     if (!extfs_rename(old_path, full_path))
  1946.         return errno2oserr();
  1947.     else {
  1948.         // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems
  1949.         swap_parent_ids(fs_item->id, new_item->id);
  1950.         uint32 t = fs_item->id;
  1951.         fs_item->id = new_item->id;
  1952.         new_item->id = t;
  1953.         return noErr;
  1954.     }
  1955. }
  1956.  
  1957. // Move file/directory (CMovePBRec)
  1958. static int16 fs_cat_move(uint32 pb)
  1959. {
  1960.     D(bug(" fs_cat_move(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s, new dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioDirID), Mac2HostAddr(ReadMacInt32(pb + ioNewName) + 1), ReadMacInt32(pb + ioNewDirID)));
  1961.  
  1962.     // Find path of given file/dir
  1963.     FSItem *fs_item;
  1964.     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
  1965.     if (result != noErr)
  1966.         return result;
  1967.  
  1968.     // Save path of existing item
  1969.     char old_path[MAX_PATH_LENGTH];
  1970.     strcpy(old_path, full_path);
  1971.  
  1972.     // Find path for new directory
  1973.     Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
  1974.     WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioNewName));
  1975.     FSItem *new_dir_item;
  1976.     result = get_item_and_path(fs_data + fsPB, ReadMacInt32(pb + ioNewDirID), new_dir_item);
  1977.     if (result != noErr)
  1978.         return result;
  1979.  
  1980.     // Append old file/dir name
  1981.     add_path_comp(fs_item->name);
  1982.  
  1983.     // Does the new name already exist?
  1984.     if (access(full_path, F_OK) == 0)
  1985.         return dupFNErr;
  1986.  
  1987.     // Move item
  1988.     D(bug("  moving %s -> %s\n", old_path, full_path));
  1989.     if (!extfs_rename(old_path, full_path))
  1990.         return errno2oserr();
  1991.     else {
  1992.         // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems
  1993.         FSItem *new_item = find_fsitem(fs_item->name, new_dir_item);
  1994.         if (new_item) {
  1995.             swap_parent_ids(fs_item->id, new_item->id);
  1996.             uint32 t = fs_item->id;
  1997.             fs_item->id = new_item->id;
  1998.             new_item->id = t;
  1999.         }
  2000.         return noErr;
  2001.     }
  2002. }
  2003.  
  2004. // Open working directory (WDParam)
  2005. static int16 fs_open_wd(uint32 pb)
  2006. {
  2007.     D(bug(" fs_open_wd(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioWDDirID)));
  2008.     M68kRegisters r;
  2009.  
  2010.     // Allocate WDCB
  2011.     D(bug("  allocating WDCB\n"));
  2012.     r.a[0] = pb;
  2013.     Execute68k(fs_data + fsAllocateWDCB, &r);
  2014.     D(bug("  UTAllocateWDCB returned %d, refNum is %d\n", r.d[0], ReadMacInt16(pb + ioVRefNum)));
  2015.     return (int16)r.d[0];
  2016. }
  2017.  
  2018. // Close working directory (WDParam)
  2019. static int16 fs_close_wd(uint32 pb)
  2020. {
  2021.     D(bug(" fs_close_wd(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum)));
  2022.     M68kRegisters r;
  2023.  
  2024.     // Release WDCB
  2025.     D(bug("  releasing WDCB\n"));
  2026.     r.d[0] = ReadMacInt16(pb + ioVRefNum);
  2027.     Execute68k(fs_data + fsReleaseWDCB, &r);
  2028.     D(bug("  UTReleaseWDCB returned %d\n", r.d[0]));
  2029.     return (int16)r.d[0];
  2030. }
  2031.  
  2032. // Query information about working directory (WDParam)
  2033. static int16 fs_get_wd_info(uint32 pb, uint32 vcb)
  2034. {
  2035.     D(bug(" fs_get_wd_info(%08lx), vRefNum %d, idx %d, procID %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioWDIndex), ReadMacInt32(pb + ioWDProcID)));
  2036.     M68kRegisters r;
  2037.  
  2038.     // Querying volume?
  2039.     if (ReadMacInt16(pb + ioWDIndex) == 0 && ReadMacInt16(pb + ioVRefNum) == ReadMacInt16(vcb + vcbVRefNum)) {
  2040.         WriteMacInt32(pb + ioWDProcID, 0);
  2041.         WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(vcb + vcbVRefNum));
  2042.         if (ReadMacInt32(pb + ioNamePtr))
  2043.             Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), vcb + vcbVN, 28);
  2044.         WriteMacInt32(pb + ioWDDirID, ROOT_ID);
  2045.         return noErr;
  2046.     }
  2047.  
  2048.     // Resolve WDCB
  2049.     D(bug("  resolving WDCB\n"));
  2050.     r.d[0] = ReadMacInt32(pb + ioWDProcID);
  2051.     r.d[1] = ReadMacInt16(pb + ioWDIndex);
  2052.     r.d[2] = ReadMacInt16(pb + ioVRefNum);
  2053.     r.a[0] = fs_data + fsReturn;
  2054.     Execute68k(fs_data + fsResolveWDCB, &r);
  2055.     uint32 wdcb = ReadMacInt32(fs_data + fsReturn);
  2056.     D(bug("  UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID)));
  2057.     if (r.d[0] & 0xffff)
  2058.         return (int16)r.d[0];
  2059.  
  2060.     // Return information
  2061.     WriteMacInt32(pb + ioWDProcID, ReadMacInt32(wdcb + wdProcID));
  2062.     WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(ReadMacInt32(wdcb + wdVCBPtr) + vcbVRefNum));
  2063.     if (ReadMacInt32(pb + ioNamePtr))
  2064.         Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), ReadMacInt32(wdcb + wdVCBPtr) + vcbVN, 28);
  2065.     WriteMacInt32(pb + ioWDDirID, ReadMacInt32(wdcb + wdDirID));
  2066.     return noErr;
  2067. }
  2068.  
  2069. // Main dispatch routine
  2070. int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 globalsPtr, int16 fsid)
  2071. {
  2072.     uint16 trapWord = selectCode & 0xf0ff;
  2073.     bool hfs = selectCode & kHFSMask;
  2074.     switch (trapWord) {
  2075.         case kFSMOpen:
  2076.             return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, false);
  2077.  
  2078.         case kFSMClose:
  2079.             return fs_close(paramBlock);
  2080.  
  2081.         case kFSMRead:
  2082.             return fs_read(paramBlock);
  2083.  
  2084.         case kFSMWrite:
  2085.             return fs_write(paramBlock);
  2086.  
  2087.         case kFSMGetVolInfo:
  2088.             return fs_get_vol_info(paramBlock, hfs);
  2089.  
  2090.         case kFSMCreate:
  2091.             return fs_create(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
  2092.  
  2093.         case kFSMDelete:
  2094.             return fs_delete(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
  2095.  
  2096.         case kFSMOpenRF:
  2097.             return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, true);
  2098.  
  2099.         case kFSMRename:
  2100.             return fs_rename(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
  2101.  
  2102.         case kFSMGetFileInfo:
  2103.             return fs_get_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
  2104.  
  2105.         case kFSMSetFileInfo:
  2106.             return fs_set_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
  2107.  
  2108.         case kFSMUnmountVol:
  2109.             return fs_unmount_vol(vcb);
  2110.  
  2111.         case kFSMMountVol:
  2112.             return fs_mount_vol(paramBlock);
  2113.  
  2114.         case kFSMAllocate:
  2115.             D(bug(" allocate\n"));
  2116.             WriteMacInt32(paramBlock + ioActCount, ReadMacInt32(paramBlock + ioReqCount));
  2117.             return noErr;
  2118.  
  2119.         case kFSMGetEOF:
  2120.             return fs_get_eof(paramBlock);
  2121.  
  2122.         case kFSMSetEOF:
  2123.             return fs_set_eof(paramBlock);
  2124.  
  2125.         case kFSMGetVol:
  2126.             return fs_get_vol(paramBlock);
  2127.  
  2128.         case kFSMSetVol:
  2129.             return fs_set_vol(paramBlock, hfs, vcb);
  2130.  
  2131.         case kFSMEject:
  2132.             D(bug(" eject\n"));
  2133.             return noErr;
  2134.  
  2135.         case kFSMGetFPos:
  2136.             return fs_get_fpos(paramBlock);
  2137.  
  2138.         case kFSMOffline:
  2139.             D(bug(" offline\n"));
  2140.             return noErr;
  2141.  
  2142.         case kFSMSetFilLock:
  2143.             return noErr;    //!!
  2144.  
  2145.         case kFSMRstFilLock:
  2146.             return noErr;    //!!
  2147.  
  2148.         case kFSMSetFPos:
  2149.             return fs_set_fpos(paramBlock);
  2150.  
  2151.         case kFSMOpenWD:
  2152.             return fs_open_wd(paramBlock);
  2153.  
  2154.         case kFSMCloseWD:
  2155.             return fs_close_wd(paramBlock);
  2156.  
  2157.         case kFSMCatMove:
  2158.             return fs_cat_move(paramBlock);
  2159.  
  2160.         case kFSMDirCreate:
  2161.             return fs_dir_create(paramBlock);
  2162.  
  2163.         case kFSMGetWDInfo:
  2164.             return fs_get_wd_info(paramBlock, vcb);
  2165.  
  2166.         case kFSMGetFCBInfo:
  2167.             return fs_get_fcb_info(paramBlock, vcb);
  2168.  
  2169.         case kFSMGetCatInfo:
  2170.             return fs_get_cat_info(paramBlock);
  2171.  
  2172.         case kFSMSetCatInfo:
  2173.             return fs_set_cat_info(paramBlock);
  2174.  
  2175.         case kFSMSetVolInfo:
  2176.             return fs_set_vol_info(paramBlock);
  2177.  
  2178.         case kFSMGetVolParms:
  2179.             return fs_get_vol_parms(paramBlock);
  2180.  
  2181.         case kFSMVolumeMount:
  2182.             return fs_volume_mount(paramBlock);
  2183.  
  2184.         case kFSMFlushVol:
  2185.         case kFSMFlushFile:
  2186.             D(bug(" flush_vol/flush_file\n"));
  2187.             return noErr;
  2188.  
  2189.         default:
  2190.             D(bug("ExtFSHFS(%08lx, %04x, %08lx, %08lx, %d)\n", vcb, selectCode, paramBlock, globalsPtr, fsid));
  2191.             return paramErr;
  2192.     }
  2193. }
  2194.