ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.3
Committed: 1999-10-20T15:13:53Z (24 years, 7 months ago) by cebix
Branch: MAIN
Changes since 1.2: +19 -12 lines
Log Message:
- renamed main_volume to speaker_volume and dac_volume to main_volume
  (same for mute)
- added defines for headphone volume/mute

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