ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/extfs.cpp
Revision: 1.28
Committed: 2002-01-15T14:58:32Z (22 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-12, nigel-build-13, snapshot-15012002
Changes since 1.27: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

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