ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.33
Committed: 2007-01-24T02:37:06Z (17 years, 3 months ago) by asvitkine
Branch: MAIN
Changes since 1.32: +1 -1 lines
Log Message:
macroman_to_host_encoding - so it works the other way around too

File Contents

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