~ubuntu-branches/ubuntu/trusty/basilisk2/trusty

« back to all changes in this revision

Viewing changes to src/extfs.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2003-07-24 00:48:57 UTC
  • Revision ID: james.westby@ubuntu.com-20030724004857-vnv33v6vf7a7u0z6
Tags: upstream-0.9.20030722
ImportĀ upstreamĀ versionĀ 0.9.20030722

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  extfs.cpp - MacOS file system for native file system access
 
3
 *
 
4
 *  Basilisk II (C) 1997-2002 Christian Bauer
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
 
 
21
/*
 
22
 *  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
 
 
36
#include "sysdeps.h"
 
37
 
 
38
#include <sys/types.h>
 
39
#include <sys/stat.h>
 
40
#include <string.h>
 
41
#include <stdio.h>
 
42
#include <stdlib.h>
 
43
#include <fcntl.h>
 
44
#include <errno.h>
 
45
 
 
46
#ifndef WIN32
 
47
#include <unistd.h>
 
48
#include <dirent.h>
 
49
#endif
 
50
 
 
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
#ifdef WIN32
 
61
# include "posix_emu.h"
 
62
#endif
 
63
 
 
64
#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
        fsPB = 238,                                             // IOParam (for mounting and renaming), also used for temporary storage
 
75
        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
        fsResolveWDCB = 614,                    // UTResolveWDCB(uint32 procID{d0}, int16 index{d1}, int16 vRefNum{d0}, uint32 *wdcb{a0})
 
82
        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
const int16 MY_FSID = EMULATOR_ID_2;
 
111
const uint32 MY_MEDIA_TYPE = EMULATOR_ID_4;
 
112
 
 
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
// 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
const int AL_BLK_SIZE = 0x4000;
 
123
const int CLUMP_SIZE = 0x4000;
 
124
 
 
125
// 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
static void add_path_comp(const char *s)
 
218
{
 
219
        add_path_component(full_path, s);
 
220
}
 
221
 
 
222
static void get_path_for_fsitem(FSItem *p)
 
223
{
 
224
        if (p->id == ROOT_PARENT_ID) {
 
225
                full_path[0] = 0;
 
226
        } else if (p->id == ROOT_ID) {
 
227
                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
                add_path_comp(p->name);
 
232
        }
 
233
}
 
234
 
 
235
 
 
236
/*
 
237
 *  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
 *  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
                // 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
                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
                // 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
                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
        // Create root's parent FSItem
 
344
        FSItem *p = new FSItem;
 
345
        first_fs_item = last_fs_item = p;
 
346
        p->next = NULL;
 
347
        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
        p->id = ROOT_ID;
 
358
        p->parent_id = ROOT_PARENT_ID;
 
359
        p->parent = first_fs_item;
 
360
        strncpy(p->name, GetString(STR_EXTFS_VOLUME_NAME), 32);
 
361
        p->name[31] = 0;
 
362
 
 
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
        D(bug("FSAttr %d, %08x\n", r.d[0], r.a[0]));
 
411
        if ((r.d[0] & 0xffff) || !(r.a[0] & (1 << gestaltHasFileSystemManager))) {
 
412
                printf("WARNING: No FSM present, disabling ExtFS\n");
 
413
                return;
 
414
        }
 
415
 
 
416
        // Yes, version >=1.2?
 
417
        r.d[0] = gestaltFSMVersion;
 
418
        Execute68kTrap(0xa1ad, &r);     // Gestalt()
 
419
        D(bug("FSMVersion %d, %08x\n", r.d[0], r.a[0]));
 
420
        if ((r.d[0] & 0xffff) || (r.a[0] < 0x0120)) {
 
421
                printf("WARNING: FSM <1.2 found, disabling ExtFS\n");
 
422
                return;
 
423
        }
 
424
 
 
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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
460
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
470
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
482
        if (p - fs_data != fsResolveWDCB)
 
483
                goto fsdat_error;
 
484
        WriteMacInt16(p, 0x4267); p+= 2;        // clr.w -(sp)
 
485
        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
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
493
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
501
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
509
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
518
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
526
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
534
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
544
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
553
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
561
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
571
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
580
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
588
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
596
        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
        WriteMacInt16(p, M68K_RTS); p+= 2;
 
604
        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
        Host2Mac_memcpy(fs_data + fsFSD + fileSystemName, FS_NAME, 32);
 
628
        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
                                Host2Mac_memcpy(ReadMacInt32(paramBlock + iconBufferPtr), ExtFSIcon, sizeof(ExtFSIcon));
 
682
                                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
                        if ((int16)ReadMacInt16(paramBlock + ioVRefNum) == drive_number)
 
690
                                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
        D(bug("  determining volume, dirID %d\n", dirID));
 
719
        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
        D(bug("  UTDetermineVol() returned %d, status %d\n", r.d[0], status));
 
734
        result = (int16)(r.d[0] & 0xffff);
 
735
 
 
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
                                        r.d[0] = 0;
 
753
                                        r.d[1] = 0;
 
754
                                        r.d[2] = ReadMacInt16(pb + ioVRefNum);
 
755
                                        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
                                        result = (int16)(r.d[0] & 0xffff);
 
760
                                        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
                                        result = (int16)(r.d[0] & 0xffff);
 
776
                                        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
        return (int16)(r.d[0] & 0xffff);
 
802
}
 
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
        D(bug("  current dir %08x\n", current_dir));
 
819
        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
        D(bug("  parsing pathname\n"));
 
833
        r.a[0] = parseRec + ppStartOffset;
 
834
        r.a[1] = ReadMacInt32(parseRec + ppNamePtr);
 
835
        Execute68k(fs_data + fsParsePathname, &r);
 
836
        D(bug("  UTParsePathname() returned %d, startOffset %d\n", r.d[0], ReadMacInt16(parseRec + ppStartOffset)));
 
837
        result = (int16)(r.d[0] & 0xffff);
 
838
        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
        if ((int16)ReadMacInt16(pb + ioVRefNum) == drive_number)
 
951
                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
#if DEBUG
 
968
        uint16 sysVCBLength = ReadMacInt16(fs_data + fsReturn);
 
969
#endif
 
970
        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
                return (int16)r.d[0];
 
974
 
 
975
        // Init VCB
 
976
        WriteMacInt16(vcb + vcbSigWord, 0x4244);
 
977
#if defined(__BEOS__) || defined(WIN32)
 
978
        WriteMacInt32(vcb + vcbCrDate, TimeToMacTime(root_stat.st_crtime));
 
979
#else
 
980
        WriteMacInt32(vcb + vcbCrDate, 0);
 
981
#endif
 
982
        WriteMacInt32(vcb + vcbLsMod, TimeToMacTime(root_stat.st_mtime));
 
983
        WriteMacInt32(vcb + vcbVolBkUp, 0);
 
984
        WriteMacInt16(vcb + vcbNmFls, 1);                       //!!
 
985
        WriteMacInt16(vcb + vcbNmRtDirs, 1);            //!!
 
986
        WriteMacInt16(vcb + vcbNmAlBlks, 0xffff);       //!!
 
987
        WriteMacInt32(vcb + vcbAlBlkSiz, AL_BLK_SIZE);
 
988
        WriteMacInt32(vcb + vcbClpSiz, CLUMP_SIZE);
 
989
        WriteMacInt32(vcb + vcbNxtCNID, next_cnid);
 
990
        WriteMacInt16(vcb + vcbFreeBks, 0xffff);        //!!
 
991
        Host2Mac_memcpy(vcb + vcbVN, VOLUME_NAME, 28);
 
992
        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
        int16 vRefNum = (int16)ReadMacInt32(fs_data + fsReturn);
 
1003
        D(bug("  UTAddNewVCB() returned %d, vRefNum %d\n", r.d[0], vRefNum));
 
1004
        if (r.d[0] & 0xffff)
 
1005
                return (int16)r.d[0];
 
1006
 
 
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
        return (int16)r.d[0];
 
1030
}
 
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
#if defined(__BEOS__) || defined(WIN32)
 
1041
        WriteMacInt32(pb + ioVCrDate, TimeToMacTime(root_stat.st_crtime));
 
1042
#else
 
1043
        WriteMacInt32(pb + ioVCrDate, 0);
 
1044
#endif
 
1045
        WriteMacInt32(pb + ioVLsMod, TimeToMacTime(root_stat.st_mtime));
 
1046
        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
        WriteMacInt32(pb + ioVAlBlkSiz, AL_BLK_SIZE);
 
1052
        WriteMacInt32(pb + ioVClpSiz, CLUMP_SIZE);
 
1053
        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
                Mac_memset(pb + ioVFndrInfo, 0, 32);
 
1066
        }
 
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
        if (actual > SIZEOF_GetVolParmsInfoBuffer)
 
1087
                actual = SIZEOF_GetVolParmsInfoBuffer;
 
1088
        WriteMacInt32(pb + ioActCount, actual);
 
1089
        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
        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
        return (int16)r.d[0];
 
1111
}
 
1112
 
 
1113
// Set default volume (WDParam)
 
1114
static int16 fs_set_vol(uint32 pb, bool hfs, uint32 vcb)
 
1115
{
 
1116
        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
        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
        return (int16)r.d[0];
 
1167
}
 
1168
 
 
1169
// Query file attributes (HFileParam)
 
1170
static int16 fs_get_file_info(uint32 pb, bool hfs, uint32 dirID)
 
1171
{
 
1172
        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
 
 
1174
        FSItem *fs_item;
 
1175
        int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
 
1176
        if (dir_index <= 0) {           // Query item specified by ioDirID and ioNamePtr
 
1177
 
 
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
                                goto read_next_de;      // Suppress names beginning with '.' (MacOS could interpret these as driver names)
 
1209
                        //!! suppress directories
 
1210
                }
 
1211
                add_path_comp(de->d_name);
 
1212
 
 
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
#if defined(__BEOS__) || defined(WIN32)
 
1233
        WriteMacInt32(pb + ioFlCrDat, TimeToMacTime(st.st_crtime));
 
1234
#else
 
1235
        WriteMacInt32(pb + ioFlCrDat, 0);
 
1236
#endif
 
1237
        WriteMacInt32(pb + ioFlMdDat, TimeToMacTime(st.st_mtime));
 
1238
 
 
1239
        get_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false);
 
1240
 
 
1241
        WriteMacInt16(pb + ioFlStBlk, 0);
 
1242
        WriteMacInt32(pb + ioFlLgLen, st.st_size);
 
1243
        WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
 
1244
        WriteMacInt16(pb + ioFlRStBlk, 0);
 
1245
        uint32 rf_size = get_rfork_size(full_path);
 
1246
        WriteMacInt32(pb + ioFlRLgLen, rf_size);
 
1247
        WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1);
 
1248
 
 
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
        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
 
 
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
        // Set Finder info
 
1276
        set_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false);
 
1277
 
 
1278
        //!! times
 
1279
        return noErr;
 
1280
}
 
1281
 
 
1282
// Query file/directory attributes
 
1283
static int16 fs_get_cat_info(uint32 pb)
 
1284
{
 
1285
        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
 
 
1287
        FSItem *fs_item;
 
1288
        int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
 
1289
        if (dir_index < 0) {                    // Query directory specified by ioDirID
 
1290
 
 
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
                                goto read_next_de;      // Suppress names beginning with '.' (MacOS could interpret these as driver names)
 
1330
                }
 
1331
                add_path_comp(de->d_name);
 
1332
 
 
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
#if defined(__BEOS__) || defined(WIN32)
 
1355
        WriteMacInt32(pb + ioFlCrDat, TimeToMacTime(st.st_crtime));
 
1356
#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
        WriteMacInt32(pb + ioFlMdDat, TimeToMacTime(mtime));
 
1366
        WriteMacInt32(pb + ioFlBkDat, 0);
 
1367
 
 
1368
        get_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode));
 
1369
 
 
1370
        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
                                        if (de->d_name[0] == '.')
 
1386
                                                continue;       // Suppress names beginning with '.'
 
1387
                                        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
                WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
 
1398
                WriteMacInt16(pb + ioFlRStBlk, 0);
 
1399
                uint32 rf_size = get_rfork_size(full_path);
 
1400
                WriteMacInt32(pb + ioFlRLgLen, rf_size);
 
1401
                WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1);
 
1402
                WriteMacInt32(pb + ioFlClpSiz, 0);
 
1403
        }
 
1404
        return noErr;
 
1405
}
 
1406
 
 
1407
// Set file/directory attributes
 
1408
static int16 fs_set_cat_info(uint32 pb)
 
1409
{
 
1410
        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
 
 
1412
        // Find FSItem for given file/dir
 
1413
        FSItem *fs_item;
 
1414
        int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
 
1415
        if (result != noErr)
 
1416
                return result;
 
1417
 
 
1418
        // Get stats
 
1419
        struct stat st;
 
1420
        if (stat(full_path, &st) < 0)
 
1421
                return errno2oserr();
 
1422
 
 
1423
        // Set Finder info
 
1424
        set_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode));
 
1425
 
 
1426
        //!! 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
        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
        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
                if (fd >= 0) {
 
1473
                        if (fstat(fd, &st) < 0) {
 
1474
                                close(fd);
 
1475
                                return errno2oserr();
 
1476
                        }
 
1477
                } 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
                if (fstat(fd, &st) < 0) {
 
1486
                        close(fd);
 
1487
                        return errno2oserr();
 
1488
                }
 
1489
        }
 
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
                return (int16)r.d[0];
 
1501
        }
 
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
        WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
 
1508
        WriteMacInt32(fcb + fcbCrPs, 0);
 
1509
        WriteMacInt32(fcb + fcbVPtr, vcb);
 
1510
        WriteMacInt32(fcb + fcbClmpSize, CLUMP_SIZE);
 
1511
 
 
1512
        get_finfo(full_path, fs_data + fsPB, 0, false);
 
1513
        WriteMacInt32(fcb + fcbFType, ReadMacInt32(fs_data + fsPB + fdType));
 
1514
 
 
1515
        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
        return (int16)r.d[0];
 
1552
}
 
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
                for (int i=0; i<(int)ReadMacInt16(pb + ioFCBIndx); i++) {
 
1571
                        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
                                return (int16)r.d[0];
 
1580
                }
 
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
        WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
 
1628
        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
        WriteMacInt32(fcb + fcbPLen, (size | (AL_BLK_SIZE - 1)) + 1);
 
1663
        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
                case fsFromLEOF:
 
1726
                        if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
 
1727
                                return posErr;
 
1728
                        break;
 
1729
                case fsFromMark:
 
1730
                        if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
 
1731
                                return posErr;
 
1732
                        break;
 
1733
                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
        // Check parameters
 
1748
        if ((int32)ReadMacInt32(pb + ioReqCount) < 0)
 
1749
                return paramErr;
 
1750
 
 
1751
        // 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
        ssize_t actual = extfs_read(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
 
1783
        int16 read_err = errno2oserr();
 
1784
        D(bug("  actual %d\n", actual));
 
1785
        WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0);
 
1786
        uint32 pos = lseek(fd, 0, SEEK_CUR);
 
1787
        WriteMacInt32(fcb + fcbCrPs, pos);
 
1788
        WriteMacInt32(pb + ioPosOffset, pos);
 
1789
        if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount))
 
1790
                return actual < 0 ? read_err : eofErr;
 
1791
        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
        // Check parameters
 
1801
        if ((int32)ReadMacInt32(pb + ioReqCount) < 0)
 
1802
                return paramErr;
 
1803
 
 
1804
        // 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
        ssize_t actual = extfs_write(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
 
1836
        int16 write_err = errno2oserr();
 
1837
        D(bug("  actual %d\n", actual));
 
1838
        WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0);
 
1839
        uint32 pos = lseek(fd, 0, SEEK_CUR);
 
1840
        WriteMacInt32(fcb + fcbCrPs, pos);
 
1841
        WriteMacInt32(pb + ioPosOffset, pos);
 
1842
        if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount))
 
1843
                return write_err;
 
1844
        else
 
1845
                return noErr;
 
1846
}
 
1847
 
 
1848
// Create file
 
1849
static int16 fs_create(uint32 pb, uint32 dirID)
 
1850
{
 
1851
        D(bug(" fs_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID));
 
1852
 
 
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
        int fd = creat(full_path, 0666);
 
1865
        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
        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
 
 
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
        if (mkdir(full_path, 0777) < 0)
 
1890
                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
        D(bug(" fs_delete(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID));
 
1901
 
 
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
        if (!extfs_remove(full_path))
 
1910
                return errno2oserr();
 
1911
        else
 
1912
                return noErr;
 
1913
}
 
1914
 
 
1915
// Rename file/directory
 
1916
static int16 fs_rename(uint32 pb, uint32 dirID)
 
1917
{
 
1918
        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
 
 
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
        Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
 
1932
        WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioMisc));
 
1933
        FSItem *new_item;
 
1934
        result = get_item_and_path(fs_data + fsPB, dirID, new_item);
 
1935
        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
        if (!extfs_rename(old_path, full_path))
 
1945
                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
                swap_parent_ids(fs_item->id, new_item->id);
 
1949
                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
        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
 
 
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
        Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
 
1973
        WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioNewName));
 
1974
        FSItem *new_dir_item;
 
1975
        result = get_item_and_path(fs_data + fsPB, ReadMacInt32(pb + ioNewDirID), new_dir_item);
 
1976
        if (result != noErr)
 
1977
                return result;
 
1978
 
 
1979
        // Append old file/dir name
 
1980
        add_path_comp(fs_item->name);
 
1981
 
 
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
        if (!extfs_rename(old_path, full_path))
 
1989
                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
                        swap_parent_ids(fs_item->id, new_item->id);
 
1995
                        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
        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
        M68kRegisters r;
 
2008
 
 
2009
        // Allocate WDCB
 
2010
        D(bug("  allocating WDCB\n"));
 
2011
        r.a[0] = pb;
 
2012
        Execute68k(fs_data + fsAllocateWDCB, &r);
 
2013
        D(bug("  UTAllocateWDCB returned %d, refNum is %d\n", r.d[0], ReadMacInt16(pb + ioVRefNum)));
 
2014
        return (int16)r.d[0];
 
2015
}
 
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
        return (int16)r.d[0];
 
2029
}
 
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
                        Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), vcb + vcbVN, 28);
 
2043
                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
                return (int16)r.d[0];
 
2058
 
 
2059
        // Return information
 
2060
        WriteMacInt32(pb + ioWDProcID, ReadMacInt32(wdcb + wdProcID));
 
2061
        WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(ReadMacInt32(wdcb + wdVCBPtr) + vcbVRefNum));
 
2062
        if (ReadMacInt32(pb + ioNamePtr))
 
2063
                Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), ReadMacInt32(wdcb + wdVCBPtr) + vcbVN, 28);
 
2064
        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
}