ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.5
Committed: 1999-10-21T22:39:51Z (25 years ago) by cebix
Branch: MAIN
Changes since 1.4: +23 -28 lines
Log Message:
- ExtFS works under AmigaOS
- fixed erroneous __regargs attributes in prefs_editor_amiga.cpp
  and audio_amiga.cpp for GCC

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