ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.2
Committed: 1999-10-19T21:33:56Z (25 years ago) by cebix
Branch: MAIN
Changes since 1.1: +4 -1 lines
Log Message:
- fixed compilation problems on BeOS

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