ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.7
Committed: 1999-10-27T16:59:35Z (24 years, 6 months ago) by cebix
Branch: MAIN
Changes since 1.6: +11 -10 lines
Log Message:
- imported fixed UAE FPU from Lauri
- extfs.cpp: fixed bug with fsResolveWDCB in fs_get_wd_info()
- ExtFS: MAX_PATH_LENGTH is global, removed third parameter to
  add_path_component()
- rom_patches.cpp: added print_rom_info()
- Unix: added "-rominfo" command line argument
- extfs_unix.cpp: supports finder info and resource forks
- prefs_editor_gtk.cpp: tab widget is no longer scrollable

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