ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.1
Committed: 1999-10-19T17:41:14Z (25 years, 1 month ago) by cebix
Branch: MAIN
Log Message:
- added external file system
- moved most init/deinit code to InitAll()/ExitAll() in main.cpp

File Contents

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