ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.4
Committed: 1999-10-20T17:23:53Z (24 years, 6 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.3: +39 -23 lines
Log Message:
- fixed bugs in extfs.cpp:
   - root's parent now has an FSItem, so finding the volume by name with
     parent dirID 1 now works
   - fs_get_file_info() and fs_get_cat_info() handle all negative values of
     dir_index correctly
   - fs_set_fpos() handles fsFromLEOF positioning mode
   - replaced "%#s" format codes in debug output
- fixed some file extensions in extfs_unix.cpp
- "speaker" means "main volume", as before

File Contents

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