/
macclassic.c
930 lines (756 loc) · 27.9 KB
1
2
3
4
5
6
7
8
/*
* MacOS Classic support routines for PhysicsFS.
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
9
10
11
12
#if HAVE_CONFIG_H
# include <config.h>
#endif
13
#include <stdio.h>
14
15
#include <stdlib.h>
#include <string.h>
16
#include <ctype.h>
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
* Most of the API calls in here are, according to ADC, available since
* MacOS 8.1. I don't think I used any MacOS 9 or CarbonLib-specific
* functions. There might be one or two 8.5 calls, and perhaps when the
* ADC docs say "Available in MacOS 8.1" they really mean "this works
* with System 6, but we don't want to hear about it at this point."
*
* IsAliasFile() showed up in MacOS 8.5. You can duplicate this code with
* PBGetCatInfoSync(), which is an older API, if you hope the bits in the
* catalog info never change (which they won't for, say, MacOS 8.1).
* See Apple Technote FL-30:
* http://developer.apple.com/technotes/fl/fl_30.html
*
* If you want to use weak pointers and Gestalt, and choose the correct
* code to use during __PHYSFS_platformInit(), I'll accept a patch, but
* chances are, it wasn't worth the time it took to write this, let alone
* implement that.
*/
37
38
39
40
/*
* Please note that I haven't tried this code with CarbonLib or under
* MacOS X at all. The code in unix.c is known to work with Darwin,
41
42
* and you may or may not be better off using that, especially since
* mutexes are no-ops in this file. Patches welcome.
43
*/
44
#ifdef __PHYSFS_CARBONIZED__ /* this is currently not defined anywhere. */
45
46
47
48
49
#include <Carbon.h>
#else
#include <OSUtils.h>
#include <Processes.h>
#include <Files.h>
50
51
52
#include <TextUtils.h>
#include <Resources.h>
#include <MacMemory.h>
53
#include <Events.h>
54
#include <DriverGestalt.h>
55
#include <Aliases.h>
56
57
58
59
60
61
62
63
#endif
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
const char *__PHYSFS_platformDirSeparator = ":";
64
65
static const char *get_macos_error_string(OSErr err)
66
67
68
69
70
71
{
if (err == noErr)
return(NULL);
switch (err)
{
72
73
74
75
76
case fnfErr: return(ERR_NO_SUCH_FILE);
case notOpenErr: return(ERR_NO_SUCH_VOLUME);
case dirFulErr: return(ERR_DIRECTORY_FULL);
case dskFulErr: return(ERR_DISK_FULL);
case nsvErr: return(ERR_NO_SUCH_VOLUME);
77
78
79
80
81
case ioErr: return(ERR_IO_ERROR);
case bdNamErr: return(ERR_BAD_FILENAME);
case fnOpnErr: return(ERR_NOT_A_HANDLE);
case eofErr: return(ERR_PAST_EOF);
case posErr: return(ERR_SEEK_OUT_OF_RANGE);
82
83
84
85
86
case tmfoErr: return(ERR_TOO_MANY_HANDLES);
case wPrErr: return(ERR_VOL_LOCKED_HW);
case fLckdErr: return(ERR_FILE_LOCKED);
case vLckdErr: return(ERR_VOL_LOCKED_SW);
case fBsyErr: return(ERR_FILE_OR_DIR_BUSY);
87
case dupFNErr: return(ERR_FILE_EXISTS);
88
89
90
91
92
93
94
95
96
97
98
99
case opWrErr: return(ERR_FILE_ALREADY_OPEN_W);
case rfNumErr: return(ERR_INVALID_REFNUM);
case gfpErr: return(ERR_GETTING_FILE_POS);
case volOffLinErr: return(ERR_VOLUME_OFFLINE);
case permErr: return(ERR_PERMISSION_DENIED);
case volOnLinErr: return(ERR_VOL_ALREADY_ONLINE);
case nsDrvErr: return(ERR_NO_SUCH_DRIVE);
case noMacDskErr: return(ERR_NOT_MAC_DISK);
case extFSErr: return(ERR_VOL_EXTERNAL_FS);
case fsRnErr: return(ERR_PROBLEM_RENAME);
case badMDBErr: return(ERR_BAD_MASTER_BLOCK);
case wrPermErr: return(ERR_PERMISSION_DENIED);
100
case memFullErr: return(ERR_OUT_OF_MEMORY);
101
102
103
104
105
case dirNFErr: return(ERR_NO_SUCH_PATH);
case tmwdoErr: return(ERR_TOO_MANY_HANDLES);
case badMovErr: return(ERR_CANT_MOVE_FORBIDDEN);
case wrgVolTypErr: return(ERR_WRONG_VOL_TYPE);
case volGoneErr: return(ERR_SERVER_VOL_LOST);
106
case errFSNameTooLong: return(ERR_BAD_FILENAME);
107
case errFSNotAFolder: return(ERR_NOT_A_DIR);
108
/*case errFSNotAFile: return(ERR_NOT_A_FILE);*/
109
110
111
112
113
114
case fidNotFound: return(ERR_FILE_ID_NOT_FOUND);
case fidExists: return(ERR_FILE_ID_EXISTS);
case afpAccessDenied: return(ERR_ACCESS_DENIED);
case afpNoServer: return(ERR_SERVER_NO_RESPOND);
case afpUserNotAuth: return(ERR_USER_AUTH_FAILED);
case afpPwdExpiredErr: return(ERR_PWORD_EXPIRED);
115
116
117
118
119
120
121
case paramErr:
case errFSBadFSRef:
case errFSBadBuffer:
case errFSMissingName:
case errFSBadPosMode:
case errFSBadAllocFlags:
122
123
124
case errFSBadItemCount:
case errFSBadSearchParams:
case afpDenyConflict:
125
return(ERR_PHYSFS_BAD_OS_CALL);
126
127
default: return(ERR_MACOS_GENERIC);
128
129
130
} /* switch */
return(NULL);
131
} /* get_macos_error_string */
132
133
134
static OSErr oserr(OSErr retval)
135
{
136
char buf[sizeof (ERR_MACOS_GENERIC) + 32];
137
const char *errstr = get_macos_error_string(retval);
138
if (strcmp(errstr, ERR_MACOS_GENERIC) == 0)
139
{
140
sprintf(buf, ERR_MACOS_GENERIC, (int) retval);
141
142
143
144
errstr = buf;
} /* if */
if (errstr != NULL)
145
__PHYSFS_setError(errstr);
146
147
return(retval);
148
149
150
} /* oserr */
151
152
static struct ProcessInfoRec procInfo;
static FSSpec procfsspec;
153
154
155
int __PHYSFS_platformInit(void)
{
156
157
OSErr err;
ProcessSerialNumber psn;
158
BAIL_IF_MACRO(oserr(GetCurrentProcess(&psn)) != noErr, NULL, 0);
159
160
161
162
163
memset(&procInfo, '\0', sizeof (ProcessInfoRec));
memset(&procfsspec, '\0', sizeof (FSSpec));
procInfo.processInfoLength = sizeof (ProcessInfoRec);
procInfo.processAppSpec = &procfsspec;
err = GetProcessInformation(&psn, &procInfo);
164
BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0);
165
return(1); /* we're golden. */
166
167
168
169
170
171
172
173
174
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
175
176
177
178
/*
* CD detection code is borrowed from Apple Technical Q&A DV18.
* http://developer.apple.com/qa/dv/dv18.html
*/
179
180
char **__PHYSFS_platformDetectAvailableCDs(void)
{
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
DriverGestaltParam pb;
DrvQEl *dqp;
OSErr status;
char **retval = (char **) malloc(sizeof (char *));
int cd_count = 1;
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
*retval = NULL;
pb.csCode = kDriverGestaltCode;
pb.driverGestaltSelector = kdgDeviceType;
dqp = (DrvQEl *) GetDrvQHdr()->qHead;
while (dqp != NULL)
{
pb.ioCRefNum = dqp->dQRefNum;
pb.ioVRefNum = dqp->dQDrive;
status = PBStatusSync((ParmBlkPtr) &pb);
if ((status == noErr) && (pb.driverGestaltResponse == kdgCDType))
{
Str63 volName;
HParamBlockRec hpbr;
memset(&hpbr, '\0', sizeof (HParamBlockRec));
hpbr.volumeParam.ioNamePtr = volName;
hpbr.volumeParam.ioVRefNum = dqp->dQDrive;
hpbr.volumeParam.ioVolIndex = 0;
if (PBHGetVInfoSync(&hpbr) == noErr)
{
210
char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
if (tmp)
{
char *str = (char *) malloc(volName[0] + 1);
retval = tmp;
if (str != NULL)
{
memcpy(str, &volName[1], volName[0]);
str[volName[0]] = '\0';
retval[cd_count-1] = str;
cd_count++;
} /* if */
} /* if */
} /* if */
} /* if */
dqp = (DrvQEl *) dqp->qLink;
} /* while */
retval[cd_count - 1] = NULL;
return(retval);
231
232
233
} /* __PHYSFS_platformDetectAvailableCDs */
234
static char *convFSSpecToPath(FSSpec *spec, int includeFile)
235
236
237
238
239
240
{
char *ptr;
char *retval = NULL;
UInt32 retLength = 0;
CInfoPBRec infoPB;
Str255 str255;
241
242
243
244
str255[0] = spec->name[0];
memcpy(&str255[1], &spec->name[1], str255[0]);
245
memset(&infoPB, '\0', sizeof (CInfoPBRec));
246
infoPB.dirInfo.ioNamePtr = str255; /* put name in here. */
247
248
249
infoPB.dirInfo.ioVRefNum = spec->vRefNum; /* ID of bin's volume. */
infoPB.dirInfo.ioDrParID = spec->parID; /* ID of bin's dir. */
infoPB.dirInfo.ioFDirIndex = (includeFile) ? 0 : -1;
250
251
252
253
254
255
/* walk the tree back to the root dir (volume), building path string... */
do
{
/* check parent dir of what we last looked at... */
infoPB.dirInfo.ioDrDirID = infoPB.dirInfo.ioDrParID;
256
if (oserr(PBGetCatInfoSync(&infoPB)) != noErr)
257
258
259
{
if (retval != NULL)
free(retval);
260
return(NULL);
261
} /* if */
262
263
264
infoPB.dirInfo.ioFDirIndex = -1; /* look at parent dir next time. */
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* allocate more space for the retval... */
retLength += str255[0] + 1; /* + 1 for a ':' or null char... */
ptr = (char *) malloc(retLength);
if (ptr == NULL)
{
if (retval != NULL)
free(retval);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
/* prepend new dir to retval and cleanup... */
memcpy(ptr, &str255[1], str255[0]);
ptr[str255[0]] = '\0'; /* null terminate it. */
if (retval != NULL)
{
strcat(ptr, ":");
strcat(ptr, retval);
free(retval);
} /* if */
retval = ptr;
} while (infoPB.dirInfo.ioDrDirID != fsRtDirID);
return(retval);
288
289
290
291
292
293
294
295
296
297
} /* convFSSpecToPath */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
FSSpec spec;
/* Get the name of the binary's parent directory. */
FSMakeFSSpec(procfsspec.vRefNum, procfsspec.parID, procfsspec.name, &spec);
return(convFSSpecToPath(&spec, 0));
298
299
300
301
302
303
} /* __PHYSFS_platformCalcBaseDir */
char *__PHYSFS_platformGetUserName(void)
{
char *retval = NULL;
304
305
306
307
308
309
StringHandle strHandle;
short origResourceFile = CurResFile();
/* use the System resource file. */
UseResFile(0);
/* apparently, -16096 specifies the username. */
310
strHandle = GetString(-16096);
311
UseResFile(origResourceFile);
312
BAIL_IF_MACRO(strHandle == NULL, NULL, NULL);
313
314
315
316
317
318
319
320
321
322
323
324
HLock((Handle) strHandle);
retval = (char *) malloc((*strHandle)[0] + 1);
if (retval == NULL)
{
HUnlock((Handle) strHandle);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
memcpy(retval, &(*strHandle)[1], (*strHandle)[0]);
retval[(*strHandle)[0]] = '\0'; /* null-terminate it. */
HUnlock((Handle) strHandle);
325
326
327
328
329
330
return(retval);
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
331
#if 0
332
return(NULL); /* bah...use default behaviour, I guess. */
333
334
335
336
#else
/* (Hmm. Default behaviour is broken in the base library. :) ) */
return(__PHYSFS_platformCalcBaseDir(NULL));
#endif
337
338
339
340
341
342
343
344
345
346
347
} /* __PHYSFS_platformGetUserDir */
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
return(1); /* single threaded. */
} /* __PHYSFS_platformGetThreadID */
int __PHYSFS_platformStricmp(const char *x, const char *y)
{
348
349
350
351
352
353
354
355
356
357
358
359
360
int ux, uy;
do
{
ux = toupper((int) *x);
uy = toupper((int) *y);
if (ux != uy)
return((ux > uy) ? 1 : -1);
x++;
y++;
} while ((ux) && (uy));
return(0);
361
362
363
} /* __PHYSFS_platformStricmp */
364
int __PHYSFS_platformStrnicmp(const char *x, const char *y, PHYSFS_uint32 len)
365
{
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
int ux, uy;
if (!len)
return(0);
do
{
ux = toupper((int) *x);
uy = toupper((int) *y);
if (ux != uy)
return((ux > uy) ? 1 : -1);
x++;
y++;
len--;
} while ((ux) && (uy) && (len));
return(0);
} /* __PHYSFS_platformStrnicmp */
384
385
386
static OSErr fnameToFSSpecNoAlias(const char *fname, FSSpec *spec)
387
{
388
OSErr err;
389
Str255 str255;
390
int needColon = (strchr(fname, ':') == NULL);
391
int len = strlen(fname) + ((needColon) ? 1 : 0);
392
393
394
395
396
if (len > 255)
return(bdNamErr);
/* !!! FIXME: What happens with relative pathnames? */
397
398
399
400
401
402
403
str255[0] = len;
memcpy(&str255[1], fname, len);
/* probably just a volume name, which seems to need a ':' at the end. */
if (needColon)
str255[len] = ':';
404
err = oserr(FSMakeFSSpec(0, 0, str255, spec));
405
return(err);
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
} /* fnameToFSSpecNoAlias */
static OSErr fnameToFSSpec(const char *fname, FSSpec *spec)
{
Boolean alias = 0;
Boolean folder = 0;
OSErr err = fnameToFSSpecNoAlias(fname, spec);
if (err == dirNFErr) /* might be an alias in the middle of the path. */
{
/*
* Has to be at least two ':' chars, or we wouldn't get a
* dir-not-found condition. (no ':' means it was just a volume,
* just one ':' means we would have gotten a fnfErr, if anything.
*/
char *ptr;
char *start;
char *path = alloca(strlen(fname) + 1);
strcpy(path, fname);
ptr = strchr(path, ':');
427
BAIL_IF_MACRO(!ptr, ERR_NO_SUCH_FILE, err); /* just in case */
428
ptr = strchr(ptr + 1, ':');
429
BAIL_IF_MACRO(!ptr, ERR_NO_SUCH_FILE, err); /* just in case */
430
431
*ptr = '\0';
err = fnameToFSSpecNoAlias(path, spec); /* get first dir. */
432
BAIL_IF_MACRO(oserr(err) != noErr, NULL, err);
433
434
435
start = ptr;
ptr = strchr(start + 1, ':');
436
/* Now check each element of the path for aliases... */
437
438
439
440
441
442
443
444
445
do
{
CInfoPBRec infoPB;
memset(&infoPB, '\0', sizeof (CInfoPBRec));
infoPB.dirInfo.ioNamePtr = spec->name;
infoPB.dirInfo.ioVRefNum = spec->vRefNum;
infoPB.dirInfo.ioDrDirID = spec->parID;
infoPB.dirInfo.ioFDirIndex = 0;
err = PBGetCatInfoSync(&infoPB);
446
if (err != noErr) /* not an alias, really just a bogus path. */
447
448
449
450
451
return(fnameToFSSpecNoAlias(fname, spec)); /* reset */
if ((infoPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0)
spec->parID = infoPB.dirInfo.ioDrDirID;
452
if (ptr != NULL) /* terminate string after next element. */
453
*ptr = '\0';
454
455
456
457
458
459
460
461
462
463
*start = strlen(start + 1); /* make it a pstring. */
err = FSMakeFSSpec(spec->vRefNum, spec->parID,
(const unsigned char *) start, spec);
if (err != noErr) /* not an alias, really a bogus path. */
return(fnameToFSSpecNoAlias(fname, spec)); /* reset */
err = ResolveAliasFileWithMountFlags(spec, 1, &folder, &alias, 0);
if (err != noErr) /* not an alias, really a bogus path. */
return(fnameToFSSpecNoAlias(fname, spec)); /* reset */
464
465
start = ptr; /* move to the next element. */
466
467
468
469
470
471
472
if (ptr != NULL)
ptr = strchr(start + 1, ':');
} while (start != NULL);
} /* if */
else /* there's something there; make sure final file is not an alias. */
{
473
BAIL_IF_MACRO(oserr(err) != noErr, NULL, err);
474
err = ResolveAliasFileWithMountFlags(spec, 1, &folder, &alias, 0);
475
BAIL_IF_MACRO(oserr(err) != noErr, NULL, err);
476
477
478
} /* else */
return(noErr); /* w00t. */
479
480
481
} /* fnameToFSSpec */
482
483
int __PHYSFS_platformExists(const char *fname)
{
484
485
FSSpec spec;
return(fnameToFSSpec(fname, &spec) == noErr);
486
487
488
489
490
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
OSErr err;
FSSpec spec;
Boolean a = 0;
Boolean f = 0;
CInfoPBRec infoPB;
char *ptr;
char *dir = alloca(strlen(fname) + 1);
BAIL_IF_MACRO(dir == NULL, ERR_OUT_OF_MEMORY, 0);
strcpy(dir, fname);
ptr = strrchr(dir, ':');
if (ptr == NULL) /* just a volume name? Can't be a symlink. */
return(0);
/* resolve aliases up to the actual file... */
*ptr = '\0';
506
BAIL_IF_MACRO(fnameToFSSpec(dir, &spec) != noErr, NULL, 0);
507
508
509
510
511
512
513
*ptr = strlen(ptr + 1); /* ptr is now a pascal string. Yikes! */
memset(&infoPB, '\0', sizeof (CInfoPBRec));
infoPB.dirInfo.ioNamePtr = spec.name;
infoPB.dirInfo.ioVRefNum = spec.vRefNum;
infoPB.dirInfo.ioDrDirID = spec.parID;
infoPB.dirInfo.ioFDirIndex = 0;
514
BAIL_IF_MACRO(oserr(PBGetCatInfoSync(&infoPB)) != noErr, NULL, 0);
515
516
517
err = FSMakeFSSpec(spec.vRefNum, infoPB.dirInfo.ioDrDirID,
(const unsigned char *) ptr, &spec);
518
519
BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0);
BAIL_IF_MACRO(oserr(IsAliasFile(&spec, &a, &f)) != noErr, NULL, 0);
520
return(a);
521
522
523
524
525
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
526
527
FSSpec spec;
CInfoPBRec infoPB;
528
OSErr err;
529
530
BAIL_IF_MACRO(fnameToFSSpec(fname, &spec) != noErr, NULL, 0);
531
532
533
memset(&infoPB, '\0', sizeof (CInfoPBRec));
infoPB.dirInfo.ioNamePtr = spec.name; /* put name in here. */
infoPB.dirInfo.ioVRefNum = spec.vRefNum; /* ID of file's volume. */
534
infoPB.dirInfo.ioDrDirID = spec.parID; /* ID of bin's dir. */
535
infoPB.dirInfo.ioFDirIndex = 0; /* file (not parent) info. */
536
err = PBGetCatInfoSync(&infoPB);
537
BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0);
538
return((infoPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0);
539
540
541
542
543
544
545
} /* __PHYSFS_platformIsDirectory */
char *__PHYSFS_platformCvtToDependent(const char *prepend,
const char *dirName,
const char *append)
{
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
int len = ((prepend) ? strlen(prepend) : 0) +
((append) ? strlen(append) : 0) +
strlen(dirName) + 1;
const char *src;
char *dst;
char *retval = malloc(len);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
if (prepend != NULL)
{
strcpy(retval, prepend);
dst = retval + strlen(retval);
} /* if */
else
{
*retval = '\0';
dst = retval;
} /* else */
for (src = dirName; *src; src++, dst++)
*dst = ((*src == '/') ? ':' : *src);
*dst = '\0';
return(retval);
570
571
572
573
574
} /* __PHYSFS_platformCvtToDependent */
void __PHYSFS_platformTimeslice(void)
{
575
SystemTask();
576
577
578
579
580
581
} /* __PHYSFS_platformTimeslice */
LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks)
{
582
LinkedStringList *ret = NULL, *p = NULL;
583
584
UInt16 i;
UInt16 max;
585
586
587
FSSpec spec;
CInfoPBRec infoPB;
Str255 str255;
588
long dirID;
589
590
BAIL_IF_MACRO(fnameToFSSpec(dirname, &spec) != noErr, NULL, 0);
591
592
593
594
595
596
597
/* get the dir ID of what we want to enumerate... */
memset(&infoPB, '\0', sizeof (CInfoPBRec));
infoPB.dirInfo.ioNamePtr = spec.name; /* name of dir to enum. */
infoPB.dirInfo.ioVRefNum = spec.vRefNum; /* ID of file's volume. */
infoPB.dirInfo.ioDrDirID = spec.parID; /* ID of dir. */
infoPB.dirInfo.ioFDirIndex = 0; /* file (not parent) info. */
598
BAIL_IF_MACRO(oserr(PBGetCatInfoSync(&infoPB)) != noErr, NULL, NULL);
599
600
601
602
603
604
605
606
if ((infoPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) == 0)
BAIL_MACRO(ERR_NOT_A_DIR, NULL);
dirID = infoPB.dirInfo.ioDrDirID;
max = infoPB.dirInfo.ioDrNmFls;
for (i = 1; i <= max; i++)
607
{
608
609
610
611
FSSpec aliasspec;
Boolean alias = 0;
Boolean folder = 0;
612
613
memset(&infoPB, '\0', sizeof (CInfoPBRec));
str255[0] = 0;
614
615
616
617
infoPB.dirInfo.ioNamePtr = str255; /* store name in here. */
infoPB.dirInfo.ioVRefNum = spec.vRefNum; /* ID of dir's volume. */
infoPB.dirInfo.ioDrDirID = dirID; /* ID of dir. */
infoPB.dirInfo.ioFDirIndex = i; /* next file's info. */
618
if (PBGetCatInfoSync(&infoPB) != noErr)
619
continue; /* skip this file. Oh well. */
620
621
622
623
624
625
626
627
628
629
630
if (FSMakeFSSpec(spec.vRefNum, dirID, str255, &aliasspec) != noErr)
continue; /* skip it. */
if (IsAliasFile(&aliasspec, &alias, &folder) != noErr)
continue; /* skip it. */
if ((alias) && (omitSymLinks))
continue;
/* still here? Add it to the list. */
631
ret = __PHYSFS_addToLinkedStringList(ret, &p, (const char *) &str255[1], str255[0]);
632
} /* for */
633
634
return(ret);
635
636
637
638
639
} /* __PHYSFS_platformEnumerateFiles */
char *__PHYSFS_platformCurrentDir(void)
{
640
641
642
643
644
645
646
/*
* I don't think MacOS has a concept of "current directory", beyond
* what is grafted on by a given standard C library implementation,
* so just return the base dir.
* We don't use this for anything crucial at the moment anyhow.
*/
return(__PHYSFS_platformCalcBaseDir(NULL));
647
648
649
650
651
} /* __PHYSFS_platformCurrentDir */
char *__PHYSFS_platformRealPath(const char *path)
{
652
653
654
655
656
657
658
659
/*
* fnameToFSSpec() will resolve any symlinks to get to the real
* file's FSSpec, which, when converted, will contain the real
* direct path to a given file. convFSSpecToPath() mallocs a
* return value buffer.
*/
FSSpec spec;
660
BAIL_IF_MACRO(fnameToFSSpec(path, &spec) != noErr, NULL, NULL);
661
return(convFSSpecToPath(&spec, 1));
662
663
664
665
666
} /* __PHYSFS_platformRealPath */
int __PHYSFS_platformMkDir(const char *path)
{
667
668
669
670
671
SInt32 val = 0;
FSSpec spec;
OSErr err = fnameToFSSpec(path, &spec);
BAIL_IF_MACRO(err == noErr, ERR_FILE_EXISTS, 0);
672
BAIL_IF_MACRO(err != fnfErr, NULL, 0);
673
674
err = DirCreate(spec.vRefNum, spec.parID, spec.name, &val);
675
BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0);
676
return(1);
677
678
679
} /* __PHYSFS_platformMkDir */
680
681
682
683
684
685
static SInt16 *macDoOpen(const char *fname, SInt8 perm, int createIfMissing)
{
int created = 0;
SInt16 *retval = NULL;
FSSpec spec;
OSErr err = fnameToFSSpec(fname, &spec);
686
BAIL_IF_MACRO((err != noErr) && (err != fnfErr), NULL, NULL);
687
688
if (err == fnfErr)
{
689
BAIL_IF_MACRO(!createIfMissing, ERR_NO_SUCH_FILE, NULL);
690
691
err = HCreate(spec.vRefNum, spec.parID, spec.name,
procInfo.processSignature, 'BINA');
692
BAIL_IF_MACRO(oserr(err) != noErr, NULL, NULL);
693
694
695
696
697
698
699
700
701
702
703
created = 1;
} /* if */
retval = (SInt16 *) malloc(sizeof (SInt16));
if (retval == NULL)
{
if (created)
HDelete(spec.vRefNum, spec.parID, spec.name);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
704
err = HOpenDF(spec.vRefNum, spec.parID, spec.name, perm, retval);
705
if (oserr(err) != noErr)
706
707
708
709
{
free(retval);
if (created)
HDelete(spec.vRefNum, spec.parID, spec.name);
710
return(NULL);
711
712
713
714
715
716
} /* if */
return(retval);
} /* macDoOpen */
717
718
void *__PHYSFS_platformOpenRead(const char *filename)
{
719
720
721
SInt16 *retval = macDoOpen(filename, fsRdPerm, 0);
if (retval != NULL) /* got a file; seek to start. */
{
722
if (oserr(SetFPos(*retval, fsFromStart, 0)) != noErr)
723
724
{
FSClose(*retval);
725
return(NULL);
726
727
728
729
} /* if */
} /* if */
return((void *) retval);
730
731
732
733
734
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
735
736
737
SInt16 *retval = macDoOpen(filename, fsRdWrPerm, 1);
if (retval != NULL) /* got a file; truncate it. */
{
738
739
if ((oserr(SetEOF(*retval, 0)) != noErr) ||
(oserr(SetFPos(*retval, fsFromStart, 0)) != noErr))
740
741
{
FSClose(*retval);
742
return(NULL);
743
744
745
746
} /* if */
} /* if */
return((void *) retval);
747
748
749
750
751
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
752
753
754
SInt16 *retval = macDoOpen(filename, fsRdWrPerm, 1);
if (retval != NULL) /* got a file; seek to end. */
{
755
if (oserr(SetFPos(*retval, fsFromLEOF, 0)) != noErr)
756
757
{
FSClose(*retval);
758
return(NULL);
759
760
761
762
} /* if */
} /* if */
return(retval);
763
764
765
766
767
768
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
769
SInt16 ref = *((SInt16 *) opaque);
770
SInt32 br = size*count;
771
772
773
BAIL_IF_MACRO(oserr(FSRead(ref, &br, buffer)) != noErr, NULL, br/size);
BAIL_IF_MACRO(br != size*count, NULL, br/size); /* !!! FIXME: seek back if only read part of an object! */
774
775
return(count);
776
777
778
779
780
781
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
782
SInt16 ref = *((SInt16 *) opaque);
783
SInt32 bw = size*count;
784
785
786
BAIL_IF_MACRO(oserr(FSWrite(ref, &bw, buffer)) != noErr, NULL, bw/size);
BAIL_IF_MACRO(bw != size*count, NULL, bw/size); /* !!! FIXME: seek back if only wrote part of an object! */
787
788
return(count);
789
790
791
792
793
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
794
795
SInt16 ref = *((SInt16 *) opaque);
OSErr err = SetFPos(ref, fsFromStart, (SInt32) pos);
796
BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0);
797
return(1);
798
799
800
801
802
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
803
804
SInt16 ref = *((SInt16 *) opaque);
SInt32 curPos;
805
BAIL_IF_MACRO(oserr(GetFPos(ref, &curPos)) != noErr, NULL, -1);
806
return((PHYSFS_sint64) curPos);
807
808
809
810
811
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
812
813
SInt16 ref = *((SInt16 *) opaque);
SInt32 eofPos;
814
BAIL_IF_MACRO(oserr(GetEOF(ref, &eofPos)) != noErr, NULL, -1);
815
return((PHYSFS_sint64) eofPos);
816
817
818
819
820
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
821
822
SInt16 ref = *((SInt16 *) opaque);
SInt32 eofPos, curPos;
823
824
BAIL_IF_MACRO(oserr(GetEOF(ref, &eofPos)) != noErr, NULL, 1);
BAIL_IF_MACRO(oserr(GetFPos(ref, &curPos)) != noErr, NULL, 1);
825
return(curPos >= eofPos);
826
827
828
829
830
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
831
832
833
834
SInt16 ref = *((SInt16 *) opaque);
ParamBlockRec pb;
memset(&pb, '\0', sizeof (ParamBlockRec));
pb.ioParam.ioRefNum = ref;
835
BAIL_IF_MACRO(oserr(PBFlushFileSync(&pb)) != noErr, NULL, 0);
836
return(1);
837
838
839
840
841
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
842
843
844
SInt16 ref = *((SInt16 *) opaque);
SInt16 vRefNum;
Str63 volName;
845
int flushVol = 0;
846
847
848
849
850
851
852
853
854
855
856
if (GetVRefNum(ref, &vRefNum) == noErr)
{
HParamBlockRec hpbr;
memset(&hpbr, '\0', sizeof (HParamBlockRec));
hpbr.volumeParam.ioNamePtr = volName;
hpbr.volumeParam.ioVRefNum = vRefNum;
hpbr.volumeParam.ioVolIndex = 0;
if (PBHGetVInfoSync(&hpbr) == noErr)
flushVol = 1;
} /* if */
857
858
BAIL_IF_MACRO(oserr(FSClose(ref)) != noErr, NULL, 0);
859
860
free(opaque);
861
862
863
if (flushVol)
FlushVol(volName, vRefNum); /* update catalog info, etc. */
864
return(1);
865
866
867
868
869
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
870
871
FSSpec spec;
OSErr err;
872
BAIL_IF_MACRO(fnameToFSSpec(path, &spec) != noErr, NULL, 0);
873
err = HDelete(spec.vRefNum, spec.parID, spec.name);
874
BAIL_IF_MACRO(oserr(err) != noErr, NULL, 0);
875
return(1);
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
} /* __PHYSFS_platformDelete */
void *__PHYSFS_platformCreateMutex(void)
{
return((void *) 0x0001); /* no mutexes on MacOS Classic. */
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
/* no mutexes on MacOS Classic. */
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
return(1); /* no mutexes on MacOS Classic. */
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
/* no mutexes on MacOS Classic. */
} /* __PHYSFS_platformReleaseMutex */
902
903
904
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
{
905
906
907
908
FSSpec spec;
CInfoPBRec infoPB;
UInt32 modDate;
909
910
if (fnameToFSSpec(fname, &spec) != noErr)
return(-1); /* fnameToFSSpec() sets physfs error message. */
911
912
913
914
915
916
memset(&infoPB, '\0', sizeof (CInfoPBRec));
infoPB.dirInfo.ioNamePtr = spec.name;
infoPB.dirInfo.ioVRefNum = spec.vRefNum;
infoPB.dirInfo.ioDrDirID = spec.parID;
infoPB.dirInfo.ioFDirIndex = 0;
917
BAIL_IF_MACRO(oserr(PBGetCatInfoSync(&infoPB)) != noErr, NULL, -1);
918
919
920
921
922
923
924
925
926
modDate = ((infoPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0) ?
infoPB.dirInfo.ioDrMdDat : infoPB.hFileInfo.ioFlMdDat;
/* epoch is different on MacOS. They use Jan 1, 1904, apparently. */
/* subtract seconds between those epochs, counting leap years. */
modDate -= 2082844800;
return((PHYSFS_sint64) modDate);
927
928
} /* __PHYSFS_platformGetLastModTime */
929
/* end of macclassic.c ... */