ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.31
Committed: 2006-04-30T15:46:55Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19
Changes since 1.30: +50 -0 lines
Log Message:
handle creation time on MacOS X

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