ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.35
Committed: 2008-01-01T09:40:31Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.34: +1 -1 lines
Log Message:
Happy New Year!

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