ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.14
Committed: 1999-11-15T15:01:34Z (24 years, 6 months ago) by cebix
Branch: MAIN
Changes since 1.13: +16 -13 lines
Log Message:
- fixed more ExtFS bugs

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 cebix 1.9 fsPB = 238, // IOParam (for mounting and renaming)
69 cebix 1.1 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 cebix 1.9 Host2Mac_memcpy(fs_data + fsFSD + fileSystemName, FS_NAME, 32);
608 cebix 1.1 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 cebix 1.9 Host2Mac_memcpy(ReadMacInt32(paramBlock + iconBufferPtr), ExtFSIcon, sizeof(ExtFSIcon));
662 cebix 1.1 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 cebix 1.9 Host2Mac_memcpy(vcb + vcbVN, VOLUME_NAME, 28);
973 cebix 1.1 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 cebix 1.9 Mac_memset(pb + ioVFndrInfo, 0, 32);
1047 cebix 1.1 }
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     uint32 actual = ReadMacInt32(pb + ioReqCount);
1067 cebix 1.14 if (actual > SIZEOF_GetVolParmsInfoBuffer)
1068     actual = SIZEOF_GetVolParmsInfoBuffer;
1069 cebix 1.1 WriteMacInt32(pb + ioActCount, actual);
1070 cebix 1.14 uint32 p = ReadMacInt32(pb + ioBuffer);
1071     if (actual > vMVersion) WriteMacInt16(p + vMVersion, 2);
1072     if (actual > vMAttrib) WriteMacInt32(p + vMAttrib, kNoMiniFndr | kNoVNEdit | kNoLclSync | kTrshOffLine | kNoSwitchTo | kNoBootBlks | kNoSysDir | kHasExtFSVol);
1073     if (actual > vMLocalHand) WriteMacInt32(p + vMLocalHand, 0);
1074     if (actual > vMServerAdr) WriteMacInt32(p + vMServerAdr, 0);
1075     if (actual > vMVolumeGrade) WriteMacInt32(p + vMVolumeGrade, 0);
1076     if (actual > vMForeignPrivID) WriteMacInt16(p + vMForeignPrivID, 0);
1077 cebix 1.1 return noErr;
1078     }
1079    
1080     // Get default volume (WDParam)
1081     static int16 fs_get_vol(uint32 pb)
1082     {
1083     D(bug(" fs_get_vol(%08lx)\n", pb));
1084     M68kRegisters r;
1085    
1086     // Getting default volume
1087     D(bug(" getting default volume\n"));
1088     r.a[0] = pb;
1089     Execute68k(fs_data + fsGetDefaultVol, &r);
1090     D(bug(" UTGetDefaultVol() returned %d\n", r.d[0]));
1091     return r.d[0];
1092     }
1093    
1094     // Set default volume (WDParam)
1095     static int16 fs_set_vol(uint32 pb, bool hfs, uint32 vcb)
1096     {
1097 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)));
1098 cebix 1.1 M68kRegisters r;
1099    
1100     // Determine parameters
1101     uint32 dirID;
1102     int16 refNum;
1103     if (hfs) {
1104    
1105     // Find FSItem for given dir
1106     FSItem *fs_item;
1107     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioWDDirID), fs_item);
1108     if (result != noErr)
1109     return result;
1110    
1111     // Is it a directory?
1112     struct stat st;
1113     if (stat(full_path, &st))
1114     return dirNFErr;
1115     if (!S_ISDIR(st.st_mode))
1116     return dirNFErr;
1117    
1118     // Get dirID and refNum
1119     dirID = fs_item->id;
1120     refNum = ReadMacInt16(vcb + vcbVRefNum);
1121    
1122     } else {
1123    
1124     // Is the given vRefNum a working directory number?
1125     D(bug(" checking for WDRefNum\n"));
1126     r.d[0] = ReadMacInt16(pb + ioVRefNum);
1127     Execute68k(fs_data + fsCheckWDRefNum, &r);
1128     D(bug(" UTCheckWDRefNum() returned %d\n", r.d[0]));
1129     if (r.d[0] & 0xffff) {
1130     // Volume refNum
1131     dirID = ROOT_ID;
1132     refNum = ReadMacInt16(vcb + vcbVRefNum);
1133     } else {
1134     // WD refNum
1135     dirID = 0;
1136     refNum = ReadMacInt16(pb + ioVRefNum);
1137     }
1138     }
1139    
1140     // Setting default volume
1141     D(bug(" setting default volume\n"));
1142     r.d[0] = 0;
1143     r.d[1] = dirID;
1144     r.d[2] = refNum;
1145     Execute68k(fs_data + fsSetDefaultVol, &r);
1146     D(bug(" UTSetDefaultVol() returned %d\n", r.d[0]));
1147     return r.d[0];
1148     }
1149    
1150     // Query file attributes (HFileParam)
1151     static int16 fs_get_file_info(uint32 pb, bool hfs, uint32 dirID)
1152     {
1153 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));
1154 cebix 1.1
1155     FSItem *fs_item;
1156 cebix 1.7 int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
1157 cebix 1.4 if (dir_index <= 0) { // Query item specified by ioDirID and ioNamePtr
1158 cebix 1.1
1159     // Find FSItem for given file
1160     int16 result = get_item_and_path(pb, dirID, fs_item);
1161     if (result != noErr)
1162     return result;
1163    
1164     } else { // Query item in directory specified by ioDirID by index
1165    
1166     // Find FSItem for parent directory
1167     int16 result;
1168     uint32 current_dir;
1169     if ((result = get_current_dir(pb, dirID, current_dir, true)) != noErr)
1170     return result;
1171     FSItem *p = find_fsitem_by_id(current_dir);
1172     if (p == NULL)
1173     return dirNFErr;
1174     get_path_for_fsitem(p);
1175    
1176     // Look for nth item in directory and add name to path
1177     DIR *d = opendir(full_path);
1178     if (d == NULL)
1179     return dirNFErr;
1180     struct dirent *de = NULL;
1181     for (int i=0; i<dir_index; i++) {
1182     read_next_de:
1183     de = readdir(d);
1184     if (de == NULL) {
1185     closedir(d);
1186     return fnfErr;
1187     }
1188     if (de->d_name[0] == '.')
1189 cebix 1.11 goto read_next_de; // Suppress names beginning with '.' (MacOS could interpret these as driver names)
1190 cebix 1.1 //!! suppress directories
1191     }
1192 cebix 1.5 add_path_comp(de->d_name);
1193 cebix 1.1
1194     // Get FSItem for queried item
1195     fs_item = find_fsitem(de->d_name, p);
1196     closedir(d);
1197     }
1198    
1199     // Get stats
1200     struct stat st;
1201     if (stat(full_path, &st))
1202     return fnfErr;
1203     if (S_ISDIR(st.st_mode))
1204     return fnfErr;
1205    
1206     // Fill in struct from fs_item and stats
1207     if (ReadMacInt32(pb + ioNamePtr))
1208     cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->name);
1209     WriteMacInt16(pb + ioFRefNum, 0);
1210     WriteMacInt8(pb + ioFlAttrib, access(full_path, W_OK) == 0 ? 0 : faLocked);
1211     WriteMacInt32(pb + ioDirID, fs_item->id);
1212    
1213     #ifdef __BEOS__
1214     WriteMacInt32(pb + ioFlCrDat, st.st_crtime + TIME_OFFSET);
1215     #else
1216     WriteMacInt32(pb + ioFlCrDat, 0);
1217     #endif
1218     WriteMacInt32(pb + ioFlMdDat, st.st_mtime + TIME_OFFSET);
1219    
1220 cebix 1.9 Mac_memset(pb + ioFlFndrInfo, 0, SIZEOF_FInfo);
1221 cebix 1.1 uint32 type, creator; // pb may point to kernel space, but stack is switched
1222     get_finder_type(full_path, type, creator);
1223     WriteMacInt32(pb + ioFlFndrInfo + fdType, type);
1224     WriteMacInt32(pb + ioFlFndrInfo + fdCreator, creator);
1225     uint16 fflags;
1226     get_finder_flags(full_path, fflags);
1227     WriteMacInt16(pb + ioFlFndrInfo + fdFlags, fflags);
1228    
1229     WriteMacInt16(pb + ioFlStBlk, 0);
1230     WriteMacInt32(pb + ioFlLgLen, st.st_size);
1231     WriteMacInt32(pb + ioFlPyLen, (st.st_size + 1023) & ~1023);
1232     WriteMacInt16(pb + ioFlRStBlk, 0);
1233     uint32 rf_size = get_rfork_size(full_path);
1234     WriteMacInt32(pb + ioFlRLgLen, rf_size);
1235     WriteMacInt32(pb + ioFlRPyLen, (rf_size + 1023) & ~1023);
1236    
1237     if (hfs) {
1238     WriteMacInt32(pb + ioFlBkDat, 0);
1239 cebix 1.9 Mac_memset(pb + ioFlXFndrInfo, 0, SIZEOF_FXInfo);
1240 cebix 1.1 WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
1241     WriteMacInt32(pb + ioFlClpSiz, 0);
1242     }
1243     return noErr;
1244     }
1245    
1246     // Set file attributes (HFileParam)
1247     static int16 fs_set_file_info(uint32 pb, bool hfs, uint32 dirID)
1248     {
1249 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));
1250 cebix 1.1
1251     // Find FSItem for given file/dir
1252     FSItem *fs_item;
1253     int16 result = get_item_and_path(pb, dirID, fs_item);
1254     if (result != noErr)
1255     return result;
1256    
1257     // Get stats
1258     struct stat st;
1259     if (stat(full_path, &st) < 0)
1260     return errno2oserr();
1261     if (S_ISDIR(st.st_mode))
1262     return fnfErr;
1263    
1264     // Set attributes
1265     set_finder_type(full_path, ReadMacInt32(pb + ioFlFndrInfo + fdType), ReadMacInt32(pb + ioFlFndrInfo + fdCreator));
1266     set_finder_flags(full_path, ReadMacInt16(pb + ioFlFndrInfo + fdFlags));
1267     //!! times
1268     return noErr;
1269     }
1270    
1271     // Query file/directory attributes
1272     static int16 fs_get_cat_info(uint32 pb)
1273     {
1274 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)));
1275 cebix 1.1
1276     FSItem *fs_item;
1277 cebix 1.7 int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
1278 cebix 1.4 if (dir_index < 0) { // Query directory specified by ioDirID
1279 cebix 1.1
1280     // Find FSItem for directory
1281     fs_item = find_fsitem_by_id(ReadMacInt32(pb + ioDrDirID));
1282     if (fs_item == NULL)
1283     return dirNFErr;
1284     get_path_for_fsitem(fs_item);
1285    
1286     } else if (dir_index == 0) { // Query item specified by ioDirID and ioNamePtr
1287    
1288     // Find FSItem for given file/dir
1289     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
1290     if (result != noErr)
1291     return result;
1292    
1293     } else { // Query item in directory specified by ioDirID by index
1294    
1295     // Find FSItem for parent directory
1296     int16 result;
1297     uint32 current_dir;
1298     if ((result = get_current_dir(pb, ReadMacInt32(pb + ioDirID), current_dir, true)) != noErr)
1299     return result;
1300     FSItem *p = find_fsitem_by_id(current_dir);
1301     if (p == NULL)
1302     return dirNFErr;
1303     get_path_for_fsitem(p);
1304    
1305     // Look for nth item in directory and add name to path
1306     DIR *d = opendir(full_path);
1307     if (d == NULL)
1308     return dirNFErr;
1309     struct dirent *de = NULL;
1310     for (int i=0; i<dir_index; i++) {
1311     read_next_de:
1312     de = readdir(d);
1313     if (de == NULL) {
1314     closedir(d);
1315     return fnfErr;
1316     }
1317     if (de->d_name[0] == '.')
1318 cebix 1.11 goto read_next_de; // Suppress names beginning with '.' (MacOS could interpret these as driver names)
1319 cebix 1.1 }
1320 cebix 1.5 add_path_comp(de->d_name);
1321 cebix 1.1
1322     // Get FSItem for queried item
1323     fs_item = find_fsitem(de->d_name, p);
1324     closedir(d);
1325     }
1326     D(bug(" path %s\n", full_path));
1327    
1328     // Get stats
1329     struct stat st;
1330     if (stat(full_path, &st) < 0)
1331     return errno2oserr();
1332     if (dir_index == -1 && !S_ISDIR(st.st_mode))
1333     return dirNFErr;
1334    
1335     // Fill in struct from fs_item and stats
1336     if (ReadMacInt32(pb + ioNamePtr))
1337     cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->name);
1338     WriteMacInt16(pb + ioFRefNum, 0);
1339     WriteMacInt8(pb + ioFlAttrib, (S_ISDIR(st.st_mode) ? faIsDir : 0) | (access(full_path, W_OK) == 0 ? 0 : faLocked));
1340     WriteMacInt8(pb + ioACUser, 0);
1341     WriteMacInt32(pb + ioDirID, fs_item->id);
1342     WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
1343     #ifdef __BEOS__
1344     WriteMacInt32(pb + ioFlCrDat, st.st_crtime + TIME_OFFSET);
1345     #else
1346     WriteMacInt32(pb + ioFlCrDat, 0);
1347     #endif
1348     time_t mtime = st.st_mtime;
1349     bool cached = true;
1350     if (mtime > fs_item->mtime) {
1351     fs_item->mtime = mtime;
1352     cached = false;
1353     }
1354 cebix 1.11 WriteMacInt32(pb + ioFlMdDat, mtime + TIME_OFFSET);
1355 cebix 1.1 WriteMacInt32(pb + ioFlBkDat, 0);
1356     if (S_ISDIR(st.st_mode)) {
1357 cebix 1.9 Mac_memset(pb + ioDrUsrWds, 0, SIZEOF_DInfo);
1358     Mac_memset(pb + ioDrFndrInfo, 0, SIZEOF_DXInfo);
1359 cebix 1.1 uint16 fflags; // pb may point to kernel space, but stack is switched
1360     get_finder_flags(full_path, fflags);
1361     WriteMacInt16(pb + ioDrUsrWds + frFlags, fflags);
1362    
1363     // Determine number of files in directory (cached)
1364     int count;
1365     if (cached)
1366     count = fs_item->cache_dircount;
1367     else {
1368     count = 0;
1369     DIR *d = opendir(full_path);
1370     if (d) {
1371     struct dirent *de;
1372     for (;;) {
1373     de = readdir(d);
1374     if (de == NULL)
1375     break;
1376 cebix 1.11 if (de->d_name[0] == '.')
1377     continue; // Suppress names beginning with '.'
1378 cebix 1.1 count++;
1379     }
1380     closedir(d);
1381     }
1382     fs_item->cache_dircount = count;
1383     }
1384     WriteMacInt16(pb + ioDrNmFls, count);
1385     } else {
1386 cebix 1.9 Mac_memset(pb + ioFlFndrInfo, 0, SIZEOF_FInfo);
1387     Mac_memset(pb + ioFlXFndrInfo, 0, SIZEOF_FXInfo);
1388 cebix 1.1 uint32 type, creator; // pb may point to kernel space, but stack is switched
1389     get_finder_type(full_path, type, creator);
1390     WriteMacInt32(pb + ioFlFndrInfo + fdType, type);
1391     WriteMacInt32(pb + ioFlFndrInfo + fdCreator, creator);
1392     uint16 fflags;
1393     get_finder_flags(full_path, fflags);
1394     WriteMacInt16(pb + ioFlFndrInfo + fdFlags, fflags);
1395     WriteMacInt16(pb + ioFlStBlk, 0);
1396     WriteMacInt32(pb + ioFlLgLen, st.st_size);
1397     WriteMacInt32(pb + ioFlPyLen, (st.st_size + 1023) & ~1023);
1398     WriteMacInt16(pb + ioFlRStBlk, 0);
1399     uint32 rf_size = get_rfork_size(full_path);
1400     WriteMacInt32(pb + ioFlRLgLen, rf_size);
1401     WriteMacInt32(pb + ioFlRPyLen, (rf_size + 1023) & ~1023);
1402     WriteMacInt32(pb + ioFlClpSiz, 0);
1403     }
1404     return noErr;
1405     }
1406    
1407     // Set file/directory attributes
1408     static int16 fs_set_cat_info(uint32 pb)
1409     {
1410 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)));
1411 cebix 1.1
1412     // Find FSItem for given file/dir
1413     FSItem *fs_item;
1414     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
1415     if (result != noErr)
1416     return result;
1417    
1418     // Get stats
1419     struct stat st;
1420     if (stat(full_path, &st) < 0)
1421     return errno2oserr();
1422    
1423     // Set attributes
1424     if (S_ISDIR(st.st_mode))
1425     set_finder_flags(full_path, ReadMacInt16(pb + ioDrUsrWds + frFlags));
1426     else {
1427     set_finder_type(full_path, ReadMacInt32(pb + ioFlFndrInfo + fdType), ReadMacInt32(pb + ioFlFndrInfo + fdCreator));
1428     set_finder_flags(full_path, ReadMacInt16(pb + ioFlFndrInfo + fdFlags));
1429     }
1430     //!! times
1431     return noErr;
1432     }
1433    
1434     // Open file
1435     static int16 fs_open(uint32 pb, uint32 dirID, uint32 vcb, bool resource_fork)
1436     {
1437 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)));
1438 cebix 1.1 M68kRegisters r;
1439    
1440     // Find FSItem for given file
1441     FSItem *fs_item;
1442     int16 result = get_item_and_path(pb, dirID, fs_item);
1443     if (result != noErr)
1444     return result;
1445    
1446     // Convert ioPermssn to open() flag
1447     int flag = 0;
1448     bool write_ok = (access(full_path, W_OK) == 0);
1449     switch (ReadMacInt8(pb + ioPermssn)) {
1450     case fsCurPerm: // Whatever is currently allowed
1451     if (write_ok)
1452     flag = O_RDWR;
1453     else
1454     flag = O_RDONLY;
1455     break;
1456     case fsRdPerm: // Exclusive read
1457     flag = O_RDONLY;
1458     break;
1459     case fsWrPerm: // Exclusive write
1460     flag = O_WRONLY;
1461     break;
1462     case fsRdWrPerm: // Exclusive read/write
1463     case fsRdWrShPerm: // Shared read/write
1464     default:
1465     flag = O_RDWR;
1466     break;
1467     }
1468    
1469     // Try to open and stat the file
1470     int fd = -1;
1471     struct stat st;
1472     if (resource_fork) {
1473     if (access(full_path, F_OK))
1474     return fnfErr;
1475     fd = open_rfork(full_path, flag);
1476     if (fd > 0) {
1477 cebix 1.14 if (fstat(fd, &st) < 0) {
1478     close(fd);
1479 cebix 1.1 return errno2oserr();
1480 cebix 1.14 }
1481 cebix 1.1 } else { // Resource fork not supported, silently ignore it ("pseudo" resource fork)
1482     st.st_size = 0;
1483     st.st_mode = 0;
1484     }
1485     } else {
1486     fd = open(full_path, flag);
1487     if (fd < 0)
1488     return errno2oserr();
1489 cebix 1.14 if (fstat(fd, &st) < 0) {
1490     close(fd);
1491 cebix 1.1 return errno2oserr();
1492 cebix 1.14 }
1493 cebix 1.1 }
1494    
1495     // File open, allocate FCB
1496     D(bug(" allocating FCB\n"));
1497     r.a[0] = pb + ioRefNum;
1498     r.a[1] = fs_data + fsReturn;
1499     Execute68k(fs_data + fsAllocateFCB, &r);
1500     uint32 fcb = ReadMacInt32(fs_data + fsReturn);
1501     D(bug(" UTAllocateFCB() returned %d, fRefNum %d, fcb %08lx\n", r.d[0], ReadMacInt16(pb + ioRefNum), fcb));
1502     if (r.d[0] & 0xffff) {
1503     close(fd);
1504     return r.d[0];
1505     }
1506    
1507     // Initialize FCB, fd is stored in fcbCatPos
1508     WriteMacInt32(fcb + fcbFlNm, fs_item->id);
1509     WriteMacInt8(fcb + fcbFlags, ((flag == O_WRONLY || flag == O_RDWR) ? fcbWriteMask : 0) | (resource_fork ? fcbResourceMask : 0) | (write_ok ? 0 : fcbFileLockedMask));
1510     WriteMacInt32(fcb + fcbEOF, st.st_size);
1511     WriteMacInt32(fcb + fcbPLen, (st.st_size + 1023) & ~1023);
1512     WriteMacInt32(fcb + fcbCrPs, 0);
1513     WriteMacInt32(fcb + fcbVPtr, vcb);
1514     WriteMacInt32(fcb + fcbClmpSize, 1024);
1515 cebix 1.14 uint32 type, creator; // BeOS: fcb may point to kernel space, but stack is switched
1516 cebix 1.1 get_finder_type(full_path, type, creator);
1517     WriteMacInt32(fcb + fcbFType, type);
1518     WriteMacInt32(fcb + fcbCatPos, fd);
1519     WriteMacInt32(fcb + fcbDirID, fs_item->parent_id);
1520     cstr2pstr((char *)Mac2HostAddr(fcb + fcbCName), fs_item->name);
1521     return noErr;
1522     }
1523    
1524     // Close file
1525     static int16 fs_close(uint32 pb)
1526     {
1527     D(bug(" fs_close(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
1528     M68kRegisters r;
1529    
1530     // Find FCB and fd for file
1531     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1532     if (fcb == 0)
1533     return rfNumErr;
1534     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1535     return fnOpnErr;
1536     int fd = ReadMacInt32(fcb + fcbCatPos);
1537    
1538     // Close file
1539     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {
1540     FSItem *item = find_fsitem_by_id(ReadMacInt32(fcb + fcbFlNm));
1541     if (item) {
1542     get_path_for_fsitem(item);
1543     close_rfork(full_path, fd);
1544     }
1545     } else
1546     close(fd);
1547     WriteMacInt32(fcb + fcbCatPos, (uint32)-1);
1548    
1549     // Release FCB
1550     D(bug(" releasing FCB\n"));
1551     r.d[0] = ReadMacInt16(pb + ioRefNum);
1552     Execute68k(fs_data + fsReleaseFCB, &r);
1553     D(bug(" UTReleaseFCB() returned %d\n", r.d[0]));
1554     return r.d[0];
1555     }
1556    
1557     // Query information about FCB (FCBPBRec)
1558     static int16 fs_get_fcb_info(uint32 pb, uint32 vcb)
1559     {
1560     D(bug(" fs_get_fcb_info(%08lx), vRefNum %d, refNum %d, idx %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioFCBIndx)));
1561     M68kRegisters r;
1562    
1563     uint32 fcb = 0;
1564     if (ReadMacInt16(pb + ioFCBIndx) == 0) { // Get information about single file
1565    
1566     // Find FCB for file
1567     fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1568    
1569     } else { // Get information about file specified by index
1570    
1571     // Find FCB by index
1572     WriteMacInt16(pb + ioRefNum, 0);
1573     for (int i=0; i<ReadMacInt16(pb + ioFCBIndx); i++) {
1574     D(bug(" indexing FCBs\n"));
1575     r.a[0] = vcb;
1576     r.a[1] = pb + ioRefNum;
1577     r.a[2] = fs_data + fsReturn;
1578     Execute68k(fs_data + fsIndexFCB, &r);
1579     fcb = ReadMacInt32(fs_data + fsReturn);
1580     D(bug(" UTIndexFCB() returned %d, fcb %p\n", r.d[0], fcb));
1581     if (r.d[0] & 0xffff)
1582     return r.d[0];
1583     }
1584     }
1585     if (fcb == 0)
1586     return rfNumErr;
1587    
1588     // Copy information from FCB
1589     if (ReadMacInt32(pb + ioNamePtr))
1590     pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), (char *)Mac2HostAddr(fcb + fcbCName));
1591     WriteMacInt32(pb + ioFCBFlNm, ReadMacInt32(fcb + fcbFlNm));
1592     WriteMacInt8(pb + ioFCBFlags, ReadMacInt8(fcb + fcbFlags));
1593     WriteMacInt16(pb + ioFCBStBlk, ReadMacInt16(fcb + fcbSBlk));
1594     WriteMacInt32(pb + ioFCBEOF, ReadMacInt32(fcb + fcbEOF));
1595     WriteMacInt32(pb + ioFCBPLen, ReadMacInt32(fcb + fcbPLen));
1596     WriteMacInt32(pb + ioFCBCrPs, ReadMacInt32(fcb + fcbCrPs));
1597     WriteMacInt16(pb + ioFCBVRefNum, ReadMacInt16(ReadMacInt32(fcb + fcbVPtr) + vcbVRefNum));
1598     WriteMacInt32(pb + ioFCBClpSiz, ReadMacInt32(fcb + fcbClmpSize));
1599     WriteMacInt32(pb + ioFCBParID, ReadMacInt32(fcb + fcbDirID));
1600     return noErr;
1601     }
1602    
1603     // Obtain logical size of an open file
1604     static int16 fs_get_eof(uint32 pb)
1605     {
1606     D(bug(" fs_get_eof(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
1607     M68kRegisters r;
1608    
1609     // Find FCB and fd for file
1610     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1611     if (fcb == 0)
1612     return rfNumErr;
1613     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1614     return fnOpnErr;
1615     int fd = ReadMacInt32(fcb + fcbCatPos);
1616     if (fd < 0)
1617     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
1618     WriteMacInt32(pb + ioMisc, 0);
1619     return noErr;
1620     } else
1621     return fnOpnErr;
1622    
1623     // Get file size
1624     struct stat st;
1625     if (fstat(fd, &st) < 0)
1626     return errno2oserr();
1627    
1628     // Adjust FCBs
1629     WriteMacInt32(fcb + fcbEOF, st.st_size);
1630     WriteMacInt32(fcb + fcbPLen, (st.st_size + 1023) & ~1023);
1631     WriteMacInt32(pb + ioMisc, st.st_size);
1632     D(bug(" adjusting FCBs\n"));
1633     r.d[0] = ReadMacInt16(pb + ioRefNum);
1634     Execute68k(fs_data + fsAdjustEOF, &r);
1635     D(bug(" UTAdjustEOF() returned %d\n", r.d[0]));
1636     return noErr;
1637     }
1638    
1639     // Truncate file
1640     static int16 fs_set_eof(uint32 pb)
1641     {
1642     D(bug(" fs_set_eof(%08lx), refNum %d, size %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioMisc)));
1643     M68kRegisters r;
1644    
1645     // Find FCB and fd for file
1646     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1647     if (fcb == 0)
1648     return rfNumErr;
1649     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1650     return fnOpnErr;
1651     int fd = ReadMacInt32(fcb + fcbCatPos);
1652     if (fd < 0)
1653     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) // "pseudo" resource fork
1654     return noErr;
1655     else
1656     return fnOpnErr;
1657    
1658     // Truncate file
1659     uint32 size = ReadMacInt32(pb + ioMisc);
1660     if (ftruncate(fd, size) < 0)
1661     return errno2oserr();
1662    
1663     // Adjust FCBs
1664     WriteMacInt32(fcb + fcbEOF, size);
1665     WriteMacInt32(fcb + fcbPLen, (size + 1023) & ~1023);
1666     D(bug(" adjusting FCBs\n"));
1667     r.d[0] = ReadMacInt16(pb + ioRefNum);
1668     Execute68k(fs_data + fsAdjustEOF, &r);
1669     D(bug(" UTAdjustEOF() returned %d\n", r.d[0]));
1670     return noErr;
1671     }
1672    
1673     // Query current file position
1674     static int16 fs_get_fpos(uint32 pb)
1675     {
1676     D(bug(" fs_get_fpos(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
1677    
1678     WriteMacInt32(pb + ioReqCount, 0);
1679     WriteMacInt32(pb + ioActCount, 0);
1680     WriteMacInt16(pb + ioPosMode, 0);
1681    
1682     // Find FCB and fd for file
1683     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1684     if (fcb == 0)
1685     return rfNumErr;
1686     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1687     return fnOpnErr;
1688     int fd = ReadMacInt32(fcb + fcbCatPos);
1689     if (fd < 0)
1690     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
1691     WriteMacInt32(pb + ioPosOffset, 0);
1692     return noErr;
1693     } else
1694     return fnOpnErr;
1695    
1696     // Get file position
1697     uint32 pos = lseek(fd, 0, SEEK_CUR);
1698     WriteMacInt32(fcb + fcbCrPs, pos);
1699     WriteMacInt32(pb + ioPosOffset, pos);
1700     return noErr;
1701     }
1702    
1703     // Set current file position
1704     static int16 fs_set_fpos(uint32 pb)
1705     {
1706     D(bug(" fs_set_fpos(%08lx), refNum %d, posMode %d, offset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
1707    
1708     // Find FCB and fd for file
1709     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1710     if (fcb == 0)
1711     return rfNumErr;
1712     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1713     return fnOpnErr;
1714     int fd = ReadMacInt32(fcb + fcbCatPos);
1715     if (fd < 0)
1716     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
1717     WriteMacInt32(pb + ioPosOffset, 0);
1718     return noErr;
1719     } else
1720     return fnOpnErr;
1721    
1722     // Set file position
1723     switch (ReadMacInt16(pb + ioPosMode)) {
1724     case fsFromStart:
1725     if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
1726     return posErr;
1727     break;
1728 cebix 1.4 case fsFromLEOF:
1729     if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
1730     return posErr;
1731     break;
1732 cebix 1.1 case fsFromMark:
1733 cebix 1.4 if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
1734 cebix 1.1 return posErr;
1735 cebix 1.4 break;
1736 cebix 1.1 default:
1737     break;
1738     }
1739     uint32 pos = lseek(fd, 0, SEEK_CUR);
1740     WriteMacInt32(fcb + fcbCrPs, pos);
1741     WriteMacInt32(pb + ioPosOffset, pos);
1742     return noErr;
1743     }
1744    
1745     // Read from file
1746     static int16 fs_read(uint32 pb)
1747     {
1748     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)));
1749    
1750     // Find FCB and fd for file
1751     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1752     if (fcb == 0)
1753     return rfNumErr;
1754     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1755     return fnOpnErr;
1756     int fd = ReadMacInt32(fcb + fcbCatPos);
1757     if (fd < 0)
1758     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
1759     WriteMacInt32(pb + ioActCount, 0);
1760     return eofErr;
1761     } else
1762     return fnOpnErr;
1763    
1764     // Seek
1765     switch (ReadMacInt16(pb + ioPosMode) & 3) {
1766     case fsFromStart:
1767     if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
1768     return posErr;
1769     break;
1770     case fsFromLEOF:
1771     if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
1772     return posErr;
1773     break;
1774     case fsFromMark:
1775     if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
1776     return posErr;
1777     break;
1778     }
1779    
1780     // Read
1781     size_t actual = extfs_read(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
1782 cebix 1.11 int16 read_err = errno2oserr();
1783 cebix 1.1 D(bug(" actual %d\n", actual));
1784     WriteMacInt32(pb + ioActCount, actual);
1785     uint32 pos = lseek(fd, 0, SEEK_CUR);
1786     WriteMacInt32(fcb + fcbCrPs, pos);
1787     WriteMacInt32(pb + ioPosOffset, pos);
1788     if (actual != ReadMacInt32(pb + ioReqCount))
1789 cebix 1.11 return read_err ? read_err : eofErr;
1790 cebix 1.1 else
1791     return noErr;
1792     }
1793    
1794     // Write to file
1795     static int16 fs_write(uint32 pb)
1796     {
1797     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)));
1798    
1799     // Find FCB and fd for file
1800     uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
1801     if (fcb == 0)
1802     return rfNumErr;
1803     if (ReadMacInt32(fcb + fcbFlNm) == 0)
1804     return fnOpnErr;
1805     int fd = ReadMacInt32(fcb + fcbCatPos);
1806     if (fd < 0)
1807     if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
1808     WriteMacInt32(pb + ioActCount, ReadMacInt32(pb + ioReqCount));
1809     return noErr;
1810     } else
1811     return fnOpnErr;
1812    
1813     // Seek
1814     switch (ReadMacInt16(pb + ioPosMode) & 3) {
1815     case fsFromStart:
1816     if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
1817     return posErr;
1818     break;
1819     case fsFromLEOF:
1820     if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
1821     return posErr;
1822     break;
1823     case fsFromMark:
1824     if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
1825     return posErr;
1826     break;
1827     }
1828    
1829     // Write
1830     size_t actual = extfs_write(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
1831 cebix 1.11 int16 write_err = errno2oserr();
1832 cebix 1.1 D(bug(" actual %d\n", actual));
1833     WriteMacInt32(pb + ioActCount, actual);
1834     uint32 pos = lseek(fd, 0, SEEK_CUR);
1835     WriteMacInt32(fcb + fcbCrPs, pos);
1836     WriteMacInt32(pb + ioPosOffset, pos);
1837     if (actual != ReadMacInt32(pb + ioReqCount))
1838 cebix 1.11 return write_err;
1839 cebix 1.1 else
1840     return noErr;
1841     }
1842    
1843     // Create file
1844     static int16 fs_create(uint32 pb, uint32 dirID)
1845     {
1846 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));
1847 cebix 1.1
1848     // Find FSItem for given file
1849     FSItem *fs_item;
1850     int16 result = get_item_and_path(pb, dirID, fs_item);
1851     if (result != noErr)
1852     return result;
1853    
1854     // Does the file already exist?
1855     if (access(full_path, F_OK) == 0)
1856     return dupFNErr;
1857    
1858     // Create file
1859 cebix 1.8 int fd = creat(full_path, 0666);
1860 cebix 1.1 if (fd < 0)
1861     return errno2oserr();
1862     else {
1863     close(fd);
1864     return noErr;
1865     }
1866     }
1867    
1868     // Create directory
1869     static int16 fs_dir_create(uint32 pb)
1870     {
1871 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)));
1872 cebix 1.1
1873     // Find FSItem for given directory
1874     FSItem *fs_item;
1875     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
1876     if (result != noErr)
1877     return result;
1878    
1879     // Does the directory already exist?
1880     if (access(full_path, F_OK) == 0)
1881     return dupFNErr;
1882    
1883     // Create directory
1884 cebix 1.8 if (mkdir(full_path, 0777) < 0)
1885 cebix 1.1 return errno2oserr();
1886     else {
1887     WriteMacInt32(pb + ioDirID, fs_item->id);
1888     return noErr;
1889     }
1890     }
1891    
1892     // Delete file/directory
1893     static int16 fs_delete(uint32 pb, uint32 dirID)
1894     {
1895 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));
1896 cebix 1.1
1897     // Find FSItem for given file/dir
1898     FSItem *fs_item;
1899     int16 result = get_item_and_path(pb, dirID, fs_item);
1900     if (result != noErr)
1901     return result;
1902    
1903     // Delete file
1904 cebix 1.12 if (!extfs_remove(full_path))
1905     return errno2oserr();
1906     else
1907 cebix 1.1 return noErr;
1908     }
1909    
1910     // Rename file/directory
1911     static int16 fs_rename(uint32 pb, uint32 dirID)
1912     {
1913 cebix 1.4 D(bug(" fs_rename(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, Mac2HostAddr(ReadMacInt32(pb + ioMisc) + 1)));
1914 cebix 1.1
1915     // Find path of given file/dir
1916     FSItem *fs_item;
1917     int16 result = get_item_and_path(pb, dirID, fs_item);
1918     if (result != noErr)
1919     return result;
1920    
1921     // Save path of existing item
1922     char old_path[MAX_PATH_LENGTH];
1923     strcpy(old_path, full_path);
1924    
1925     // Find path for new name
1926 cebix 1.9 Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
1927     WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioMisc));
1928 cebix 1.1 FSItem *new_item;
1929 cebix 1.9 result = get_item_and_path(fs_data + fsPB, dirID, new_item);
1930 cebix 1.1 if (result != noErr)
1931     return result;
1932    
1933     // Does the new name already exist?
1934     if (access(full_path, F_OK) == 0)
1935     return dupFNErr;
1936    
1937     // Rename item
1938     D(bug(" renaming %s -> %s\n", old_path, full_path));
1939 cebix 1.13 if (!extfs_rename(old_path, full_path))
1940 cebix 1.1 return errno2oserr();
1941     else {
1942     // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems
1943     uint32 t = fs_item->id;
1944     fs_item->id = new_item->id;
1945     new_item->id = t;
1946     return noErr;
1947     }
1948     }
1949    
1950     // Move file/directory (CMovePBRec)
1951     static int16 fs_cat_move(uint32 pb)
1952     {
1953 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)));
1954 cebix 1.1
1955     // Find path of given file/dir
1956     FSItem *fs_item;
1957     int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
1958     if (result != noErr)
1959     return result;
1960    
1961     // Save path of existing item
1962     char old_path[MAX_PATH_LENGTH];
1963     strcpy(old_path, full_path);
1964    
1965     // Find path for new directory
1966 cebix 1.10 Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
1967 cebix 1.9 WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioNewName));
1968 cebix 1.1 FSItem *new_dir_item;
1969 cebix 1.9 result = get_item_and_path(fs_data + fsPB, ReadMacInt32(pb + ioNewDirID), new_dir_item);
1970 cebix 1.1 if (result != noErr)
1971     return result;
1972    
1973     // Append old file/dir name
1974 cebix 1.5 add_path_comp(fs_item->name);
1975 cebix 1.1
1976     // Does the new name already exist?
1977     if (access(full_path, F_OK) == 0)
1978     return dupFNErr;
1979    
1980     // Move item
1981     D(bug(" moving %s -> %s\n", old_path, full_path));
1982 cebix 1.13 if (!extfs_rename(old_path, full_path))
1983 cebix 1.1 return errno2oserr();
1984     else {
1985     // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems
1986     FSItem *new_item = find_fsitem(fs_item->name, new_dir_item);
1987     if (new_item) {
1988     uint32 t = fs_item->id;
1989     fs_item->id = new_item->id;
1990     new_item->id = t;
1991     }
1992     return noErr;
1993     }
1994     }
1995    
1996     // Open working directory (WDParam)
1997     static int16 fs_open_wd(uint32 pb)
1998     {
1999 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)));
2000 cebix 1.1 M68kRegisters r;
2001    
2002     // Allocate WDCB
2003     D(bug(" allocating WDCB\n"));
2004     r.a[0] = pb;
2005     Execute68k(fs_data + fsAllocateWDCB, &r);
2006 cebix 1.7 D(bug(" UTAllocateWDCB returned %d, refNum is %d\n", r.d[0], ReadMacInt16(pb + ioVRefNum)));
2007 cebix 1.1 return r.d[0];
2008     }
2009    
2010     // Close working directory (WDParam)
2011     static int16 fs_close_wd(uint32 pb)
2012     {
2013     D(bug(" fs_close_wd(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum)));
2014     M68kRegisters r;
2015    
2016     // Release WDCB
2017     D(bug(" releasing WDCB\n"));
2018     r.d[0] = ReadMacInt16(pb + ioVRefNum);
2019     Execute68k(fs_data + fsReleaseWDCB, &r);
2020     D(bug(" UTReleaseWDCB returned %d\n", r.d[0]));
2021     return r.d[0];
2022     }
2023    
2024     // Query information about working directory (WDParam)
2025     static int16 fs_get_wd_info(uint32 pb, uint32 vcb)
2026     {
2027     D(bug(" fs_get_wd_info(%08lx), vRefNum %d, idx %d, procID %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioWDIndex), ReadMacInt32(pb + ioWDProcID)));
2028     M68kRegisters r;
2029    
2030     // Querying volume?
2031     if (ReadMacInt16(pb + ioWDIndex) == 0 && ReadMacInt16(pb + ioVRefNum) == ReadMacInt16(vcb + vcbVRefNum)) {
2032     WriteMacInt32(pb + ioWDProcID, 0);
2033     WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(vcb + vcbVRefNum));
2034     if (ReadMacInt32(pb + ioNamePtr))
2035 cebix 1.9 Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), vcb + vcbVN, 28);
2036 cebix 1.1 WriteMacInt32(pb + ioWDDirID, ROOT_ID);
2037     return noErr;
2038     }
2039    
2040     // Resolve WDCB
2041     D(bug(" resolving WDCB\n"));
2042     r.d[0] = ReadMacInt32(pb + ioWDProcID);
2043     r.d[1] = ReadMacInt16(pb + ioWDIndex);
2044     r.d[2] = ReadMacInt16(pb + ioVRefNum);
2045     r.a[0] = fs_data + fsReturn;
2046     Execute68k(fs_data + fsResolveWDCB, &r);
2047     uint32 wdcb = ReadMacInt32(fs_data + fsReturn);
2048     D(bug(" UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID)));
2049     if (r.d[0] & 0xffff)
2050     return r.d[0];
2051    
2052     // Return information
2053 cebix 1.11 WriteMacInt32(pb + ioWDProcID, ReadMacInt32(wdcb + wdProcID));
2054 cebix 1.1 WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(ReadMacInt32(wdcb + wdVCBPtr) + vcbVRefNum));
2055     if (ReadMacInt32(pb + ioNamePtr))
2056 cebix 1.9 Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), ReadMacInt32(wdcb + wdVCBPtr) + vcbVN, 28);
2057 cebix 1.1 WriteMacInt32(pb + ioWDDirID, ReadMacInt32(wdcb + wdDirID));
2058     return noErr;
2059     }
2060    
2061     // Main dispatch routine
2062     int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 globalsPtr, int16 fsid)
2063     {
2064     uint16 trapWord = selectCode & 0xf0ff;
2065     bool hfs = selectCode & kHFSMask;
2066     switch (trapWord) {
2067     case kFSMOpen:
2068     return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, false);
2069    
2070     case kFSMClose:
2071     return fs_close(paramBlock);
2072    
2073     case kFSMRead:
2074     return fs_read(paramBlock);
2075    
2076     case kFSMWrite:
2077     return fs_write(paramBlock);
2078    
2079     case kFSMGetVolInfo:
2080     return fs_get_vol_info(paramBlock, hfs);
2081    
2082     case kFSMCreate:
2083     return fs_create(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
2084    
2085     case kFSMDelete:
2086     return fs_delete(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
2087    
2088     case kFSMOpenRF:
2089     return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, true);
2090    
2091     case kFSMRename:
2092     return fs_rename(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
2093    
2094     case kFSMGetFileInfo:
2095     return fs_get_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
2096    
2097     case kFSMSetFileInfo:
2098     return fs_set_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
2099    
2100     case kFSMUnmountVol:
2101     return fs_unmount_vol(vcb);
2102    
2103     case kFSMMountVol:
2104     return fs_mount_vol(paramBlock);
2105    
2106     case kFSMAllocate:
2107     D(bug(" allocate\n"));
2108     WriteMacInt32(paramBlock + ioActCount, ReadMacInt32(paramBlock + ioReqCount));
2109     return noErr;
2110    
2111     case kFSMGetEOF:
2112     return fs_get_eof(paramBlock);
2113    
2114     case kFSMSetEOF:
2115     return fs_set_eof(paramBlock);
2116    
2117     case kFSMGetVol:
2118     return fs_get_vol(paramBlock);
2119    
2120     case kFSMSetVol:
2121     return fs_set_vol(paramBlock, hfs, vcb);
2122    
2123     case kFSMEject:
2124     D(bug(" eject\n"));
2125     return noErr;
2126    
2127     case kFSMGetFPos:
2128     return fs_get_fpos(paramBlock);
2129    
2130     case kFSMOffline:
2131     D(bug(" offline\n"));
2132     return noErr;
2133    
2134     case kFSMSetFilLock:
2135     return noErr; //!!
2136    
2137     case kFSMRstFilLock:
2138     return noErr; //!!
2139    
2140     case kFSMSetFPos:
2141     return fs_set_fpos(paramBlock);
2142    
2143     case kFSMOpenWD:
2144     return fs_open_wd(paramBlock);
2145    
2146     case kFSMCloseWD:
2147     return fs_close_wd(paramBlock);
2148    
2149     case kFSMCatMove:
2150     return fs_cat_move(paramBlock);
2151    
2152     case kFSMDirCreate:
2153     return fs_dir_create(paramBlock);
2154    
2155     case kFSMGetWDInfo:
2156     return fs_get_wd_info(paramBlock, vcb);
2157    
2158     case kFSMGetFCBInfo:
2159     return fs_get_fcb_info(paramBlock, vcb);
2160    
2161     case kFSMGetCatInfo:
2162     return fs_get_cat_info(paramBlock);
2163    
2164     case kFSMSetCatInfo:
2165     return fs_set_cat_info(paramBlock);
2166    
2167     case kFSMSetVolInfo:
2168     return fs_set_vol_info(paramBlock);
2169    
2170     case kFSMGetVolParms:
2171     return fs_get_vol_parms(paramBlock);
2172    
2173     case kFSMVolumeMount:
2174     return fs_volume_mount(paramBlock);
2175    
2176     case kFSMFlushVol:
2177     case kFSMFlushFile:
2178     D(bug(" flush_vol/flush_file\n"));
2179     return noErr;
2180    
2181     default:
2182     D(bug("ExtFSHFS(%08lx, %04x, %08lx, %08lx, %d)\n", vcb, selectCode, paramBlock, globalsPtr, fsid));
2183     return paramErr;
2184     }
2185     }