7768
+ − 1
/**
+ − 2
* PhysicsFS; a portable, flexible file i/o abstraction.
+ − 3
*
+ − 4
* Documentation is in physfs.h. It's verbose, honest. :)
+ − 5
*
+ − 6
* Please see the file LICENSE.txt in the source's root directory.
+ − 7
*
+ − 8
* This file written by Ryan C. Gordon.
+ − 9
*/
+ − 10
+ − 11
/* !!! FIXME: ERR_PAST_EOF shouldn't trigger for reads. Just return zero. */
+ − 12
/* !!! FIXME: use snprintf(), not sprintf(). */
+ − 13
+ − 14
#define __PHYSICSFS_INTERNAL__
+ − 15
#include "physfs_internal.h"
+ − 16
+ − 17
+ − 18
typedef struct __PHYSFS_DIRHANDLE__
+ − 19
{
+ − 20
void *opaque; /* Instance data unique to the archiver. */
+ − 21
char *dirName; /* Path to archive in platform-dependent notation. */
+ − 22
char *mountPoint; /* Mountpoint in virtual file tree. */
+ − 23
const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
+ − 24
struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
+ − 25
} DirHandle;
+ − 26
+ − 27
+ − 28
typedef struct __PHYSFS_FILEHANDLE__
+ − 29
{
+ − 30
PHYSFS_Io *io; /* Instance data unique to the archiver for this file. */
+ − 31
PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
+ − 32
const DirHandle *dirHandle; /* Archiver instance that created this */
+ − 33
PHYSFS_uint8 *buffer; /* Buffer, if set (NULL otherwise). Don't touch! */
+ − 34
PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */
+ − 35
PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */
+ − 36
PHYSFS_uint32 bufpos; /* Buffer position. Don't touch! */
+ − 37
struct __PHYSFS_FILEHANDLE__ *next; /* linked list stuff. */
+ − 38
} FileHandle;
+ − 39
+ − 40
+ − 41
typedef struct __PHYSFS_ERRSTATETYPE__
+ − 42
{
+ − 43
void *tid;
+ − 44
PHYSFS_ErrorCode code;
+ − 45
struct __PHYSFS_ERRSTATETYPE__ *next;
+ − 46
} ErrState;
+ − 47
+ − 48
+ − 49
/* The various i/o drivers...some of these may not be compiled in. */
+ − 50
extern const PHYSFS_Archiver __PHYSFS_Archiver_ZIP;
+ − 51
extern const PHYSFS_Archiver __PHYSFS_Archiver_LZMA;
+ − 52
extern const PHYSFS_Archiver __PHYSFS_Archiver_GRP;
+ − 53
extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK;
+ − 54
extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG;
+ − 55
extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL;
+ − 56
extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD;
+ − 57
extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR;
+ − 58
extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660;
+ − 59
+ − 60
static const PHYSFS_Archiver *staticArchivers[] =
+ − 61
{
+ − 62
#if PHYSFS_SUPPORTS_ZIP
+ − 63
&__PHYSFS_Archiver_ZIP,
+ − 64
#endif
+ − 65
#if PHYSFS_SUPPORTS_7Z
+ − 66
&__PHYSFS_Archiver_LZMA,
+ − 67
#endif
+ − 68
#if PHYSFS_SUPPORTS_GRP
+ − 69
&__PHYSFS_Archiver_GRP,
+ − 70
#endif
+ − 71
#if PHYSFS_SUPPORTS_QPAK
+ − 72
&__PHYSFS_Archiver_QPAK,
+ − 73
#endif
+ − 74
#if PHYSFS_SUPPORTS_HOG
+ − 75
&__PHYSFS_Archiver_HOG,
+ − 76
#endif
+ − 77
#if PHYSFS_SUPPORTS_MVL
+ − 78
&__PHYSFS_Archiver_MVL,
+ − 79
#endif
+ − 80
#if PHYSFS_SUPPORTS_WAD
+ − 81
&__PHYSFS_Archiver_WAD,
+ − 82
#endif
+ − 83
#if PHYSFS_SUPPORTS_ISO9660
+ − 84
&__PHYSFS_Archiver_ISO9660,
+ − 85
#endif
+ − 86
NULL
+ − 87
};
+ − 88
+ − 89
+ − 90
+ − 91
/* General PhysicsFS state ... */
+ − 92
static int initialized = 0;
+ − 93
static ErrState *errorStates = NULL;
+ − 94
static DirHandle *searchPath = NULL;
+ − 95
static DirHandle *writeDir = NULL;
+ − 96
static FileHandle *openWriteList = NULL;
+ − 97
static FileHandle *openReadList = NULL;
+ − 98
static char *baseDir = NULL;
+ − 99
static char *userDir = NULL;
+ − 100
static char *prefDir = NULL;
+ − 101
static int allowSymLinks = 0;
+ − 102
static const PHYSFS_Archiver **archivers = NULL;
+ − 103
static const PHYSFS_ArchiveInfo **archiveInfo = NULL;
+ − 104
+ − 105
/* mutexes ... */
+ − 106
static void *errorLock = NULL; /* protects error message list. */
+ − 107
static void *stateLock = NULL; /* protects other PhysFS static state. */
+ − 108
+ − 109
/* allocator ... */
+ − 110
static int externalAllocator = 0;
+ − 111
PHYSFS_Allocator allocator;
+ − 112
+ − 113
+ − 114
/* PHYSFS_Io implementation for i/o to physical filesystem... */
+ − 115
+ − 116
/* !!! FIXME: maybe refcount the paths in a string pool? */
+ − 117
typedef struct __PHYSFS_NativeIoInfo
+ − 118
{
+ − 119
void *handle;
+ − 120
const char *path;
+ − 121
int mode; /* 'r', 'w', or 'a' */
+ − 122
} NativeIoInfo;
+ − 123
+ − 124
static PHYSFS_sint64 nativeIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+ − 125
{
+ − 126
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 127
return __PHYSFS_platformRead(info->handle, buf, len);
+ − 128
} /* nativeIo_read */
+ − 129
+ − 130
static PHYSFS_sint64 nativeIo_write(PHYSFS_Io *io, const void *buffer,
+ − 131
PHYSFS_uint64 len)
+ − 132
{
+ − 133
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 134
return __PHYSFS_platformWrite(info->handle, buffer, len);
+ − 135
} /* nativeIo_write */
+ − 136
+ − 137
static int nativeIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+ − 138
{
+ − 139
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 140
return __PHYSFS_platformSeek(info->handle, offset);
+ − 141
} /* nativeIo_seek */
+ − 142
+ − 143
static PHYSFS_sint64 nativeIo_tell(PHYSFS_Io *io)
+ − 144
{
+ − 145
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 146
return __PHYSFS_platformTell(info->handle);
+ − 147
} /* nativeIo_tell */
+ − 148
+ − 149
static PHYSFS_sint64 nativeIo_length(PHYSFS_Io *io)
+ − 150
{
+ − 151
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 152
return __PHYSFS_platformFileLength(info->handle);
+ − 153
} /* nativeIo_length */
+ − 154
+ − 155
static PHYSFS_Io *nativeIo_duplicate(PHYSFS_Io *io)
+ − 156
{
+ − 157
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 158
return __PHYSFS_createNativeIo(info->path, info->mode);
+ − 159
} /* nativeIo_duplicate */
+ − 160
+ − 161
static int nativeIo_flush(PHYSFS_Io *io)
+ − 162
{
+ − 163
return __PHYSFS_platformFlush(io->opaque);
+ − 164
} /* nativeIo_flush */
+ − 165
+ − 166
static void nativeIo_destroy(PHYSFS_Io *io)
+ − 167
{
+ − 168
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ − 169
__PHYSFS_platformClose(info->handle);
+ − 170
allocator.Free((void *) info->path);
+ − 171
allocator.Free(info);
+ − 172
allocator.Free(io);
+ − 173
} /* nativeIo_destroy */
+ − 174
+ − 175
static const PHYSFS_Io __PHYSFS_nativeIoInterface =
+ − 176
{
+ − 177
CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ − 178
nativeIo_read,
+ − 179
nativeIo_write,
+ − 180
nativeIo_seek,
+ − 181
nativeIo_tell,
+ − 182
nativeIo_length,
+ − 183
nativeIo_duplicate,
+ − 184
nativeIo_flush,
+ − 185
nativeIo_destroy
+ − 186
};
+ − 187
+ − 188
PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode)
+ − 189
{
+ − 190
PHYSFS_Io *io = NULL;
+ − 191
NativeIoInfo *info = NULL;
+ − 192
void *handle = NULL;
+ − 193
char *pathdup = NULL;
+ − 194
+ − 195
assert((mode == 'r') || (mode == 'w') || (mode == 'a'));
+ − 196
+ − 197
io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ − 198
GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+ − 199
info = (NativeIoInfo *) allocator.Malloc(sizeof (NativeIoInfo));
+ − 200
GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+ − 201
pathdup = (char *) allocator.Malloc(strlen(path) + 1);
+ − 202
GOTO_IF_MACRO(!pathdup, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+ − 203
+ − 204
if (mode == 'r')
+ − 205
handle = __PHYSFS_platformOpenRead(path);
+ − 206
else if (mode == 'w')
+ − 207
handle = __PHYSFS_platformOpenWrite(path);
+ − 208
else if (mode == 'a')
+ − 209
handle = __PHYSFS_platformOpenAppend(path);
+ − 210
+ − 211
GOTO_IF_MACRO(!handle, ERRPASS, createNativeIo_failed);
+ − 212
+ − 213
strcpy(pathdup, path);
+ − 214
info->handle = handle;
+ − 215
info->path = pathdup;
+ − 216
info->mode = mode;
+ − 217
memcpy(io, &__PHYSFS_nativeIoInterface, sizeof (*io));
+ − 218
io->opaque = info;
+ − 219
return io;
+ − 220
+ − 221
createNativeIo_failed:
+ − 222
if (handle != NULL) __PHYSFS_platformClose(handle);
+ − 223
if (pathdup != NULL) allocator.Free(pathdup);
+ − 224
if (info != NULL) allocator.Free(info);
+ − 225
if (io != NULL) allocator.Free(io);
+ − 226
return NULL;
+ − 227
} /* __PHYSFS_createNativeIo */
+ − 228
+ − 229
+ − 230
/* PHYSFS_Io implementation for i/o to a memory buffer... */
+ − 231
+ − 232
typedef struct __PHYSFS_MemoryIoInfo
+ − 233
{
+ − 234
const PHYSFS_uint8 *buf;
+ − 235
PHYSFS_uint64 len;
+ − 236
PHYSFS_uint64 pos;
+ − 237
PHYSFS_Io *parent;
+ − 238
volatile PHYSFS_uint32 refcount;
+ − 239
void (*destruct)(void *);
+ − 240
} MemoryIoInfo;
+ − 241
+ − 242
static PHYSFS_sint64 memoryIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+ − 243
{
+ − 244
MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 245
const PHYSFS_uint64 avail = info->len - info->pos;
+ − 246
assert(avail <= info->len);
+ − 247
+ − 248
if (avail == 0)
+ − 249
return 0; /* we're at EOF; nothing to do. */
+ − 250
+ − 251
if (len > avail)
+ − 252
len = avail;
+ − 253
+ − 254
memcpy(buf, info->buf + info->pos, (size_t) len);
+ − 255
info->pos += len;
+ − 256
return len;
+ − 257
} /* memoryIo_read */
+ − 258
+ − 259
static PHYSFS_sint64 memoryIo_write(PHYSFS_Io *io, const void *buffer,
+ − 260
PHYSFS_uint64 len)
+ − 261
{
+ − 262
BAIL_MACRO(PHYSFS_ERR_OPEN_FOR_READING, -1);
+ − 263
} /* memoryIo_write */
+ − 264
+ − 265
static int memoryIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+ − 266
{
+ − 267
MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 268
BAIL_IF_MACRO(offset > info->len, PHYSFS_ERR_PAST_EOF, 0);
+ − 269
info->pos = offset;
+ − 270
return 1;
+ − 271
} /* memoryIo_seek */
+ − 272
+ − 273
static PHYSFS_sint64 memoryIo_tell(PHYSFS_Io *io)
+ − 274
{
+ − 275
const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 276
return (PHYSFS_sint64) info->pos;
+ − 277
} /* memoryIo_tell */
+ − 278
+ − 279
static PHYSFS_sint64 memoryIo_length(PHYSFS_Io *io)
+ − 280
{
+ − 281
const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 282
return (PHYSFS_sint64) info->len;
+ − 283
} /* memoryIo_length */
+ − 284
+ − 285
static PHYSFS_Io *memoryIo_duplicate(PHYSFS_Io *io)
+ − 286
{
+ − 287
MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 288
MemoryIoInfo *newinfo = NULL;
+ − 289
PHYSFS_Io *parent = info->parent;
+ − 290
PHYSFS_Io *retval = NULL;
+ − 291
+ − 292
/* avoid deep copies. */
+ − 293
assert((!parent) || (!((MemoryIoInfo *) parent->opaque)->parent) );
+ − 294
+ − 295
/* share the buffer between duplicates. */
+ − 296
if (parent != NULL) /* dup the parent, increment its refcount. */
+ − 297
return parent->duplicate(parent);
+ − 298
+ − 299
/* we're the parent. */
+ − 300
+ − 301
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ − 302
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 303
newinfo = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
+ − 304
if (!newinfo)
+ − 305
{
+ − 306
allocator.Free(retval);
+ − 307
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 308
} /* if */
+ − 309
+ − 310
/* !!! FIXME: want lockless atomic increment. */
+ − 311
__PHYSFS_platformGrabMutex(stateLock);
+ − 312
info->refcount++;
+ − 313
__PHYSFS_platformReleaseMutex(stateLock);
+ − 314
+ − 315
memset(newinfo, '\0', sizeof (*info));
+ − 316
newinfo->buf = info->buf;
+ − 317
newinfo->len = info->len;
+ − 318
newinfo->pos = 0;
+ − 319
newinfo->parent = io;
+ − 320
newinfo->refcount = 0;
+ − 321
newinfo->destruct = NULL;
+ − 322
+ − 323
memcpy(retval, io, sizeof (*retval));
+ − 324
retval->opaque = newinfo;
+ − 325
return retval;
+ − 326
} /* memoryIo_duplicate */
+ − 327
+ − 328
static int memoryIo_flush(PHYSFS_Io *io) { return 1; /* it's read-only. */ }
+ − 329
+ − 330
static void memoryIo_destroy(PHYSFS_Io *io)
+ − 331
{
+ − 332
MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 333
PHYSFS_Io *parent = info->parent;
+ − 334
int should_die = 0;
+ − 335
+ − 336
if (parent != NULL)
+ − 337
{
+ − 338
assert(info->buf == ((MemoryIoInfo *) info->parent->opaque)->buf);
+ − 339
assert(info->len == ((MemoryIoInfo *) info->parent->opaque)->len);
+ − 340
assert(info->refcount == 0);
+ − 341
assert(info->destruct == NULL);
+ − 342
allocator.Free(info);
+ − 343
allocator.Free(io);
+ − 344
parent->destroy(parent); /* decrements refcount. */
+ − 345
return;
+ − 346
} /* if */
+ − 347
+ − 348
/* we _are_ the parent. */
+ − 349
assert(info->refcount > 0); /* even in a race, we hold a reference. */
+ − 350
+ − 351
/* !!! FIXME: want lockless atomic decrement. */
+ − 352
__PHYSFS_platformGrabMutex(stateLock);
+ − 353
info->refcount--;
+ − 354
should_die = (info->refcount == 0);
+ − 355
__PHYSFS_platformReleaseMutex(stateLock);
+ − 356
+ − 357
if (should_die)
+ − 358
{
+ − 359
void (*destruct)(void *) = info->destruct;
+ − 360
void *buf = (void *) info->buf;
+ − 361
io->opaque = NULL; /* kill this here in case of race. */
+ − 362
allocator.Free(info);
+ − 363
allocator.Free(io);
+ − 364
if (destruct != NULL)
+ − 365
destruct(buf);
+ − 366
} /* if */
+ − 367
} /* memoryIo_destroy */
+ − 368
+ − 369
+ − 370
static const PHYSFS_Io __PHYSFS_memoryIoInterface =
+ − 371
{
+ − 372
CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ − 373
memoryIo_read,
+ − 374
memoryIo_write,
+ − 375
memoryIo_seek,
+ − 376
memoryIo_tell,
+ − 377
memoryIo_length,
+ − 378
memoryIo_duplicate,
+ − 379
memoryIo_flush,
+ − 380
memoryIo_destroy
+ − 381
};
+ − 382
+ − 383
PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
+ − 384
void (*destruct)(void *))
+ − 385
{
+ − 386
PHYSFS_Io *io = NULL;
+ − 387
MemoryIoInfo *info = NULL;
+ − 388
+ − 389
io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ − 390
GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
+ − 391
info = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
+ − 392
GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
+ − 393
+ − 394
memset(info, '\0', sizeof (*info));
+ − 395
info->buf = (const PHYSFS_uint8 *) buf;
+ − 396
info->len = len;
+ − 397
info->pos = 0;
+ − 398
info->parent = NULL;
+ − 399
info->refcount = 1;
+ − 400
info->destruct = destruct;
+ − 401
+ − 402
memcpy(io, &__PHYSFS_memoryIoInterface, sizeof (*io));
+ − 403
io->opaque = info;
+ − 404
return io;
+ − 405
+ − 406
createMemoryIo_failed:
+ − 407
if (info != NULL) allocator.Free(info);
+ − 408
if (io != NULL) allocator.Free(io);
+ − 409
return NULL;
+ − 410
} /* __PHYSFS_createMemoryIo */
+ − 411
+ − 412
+ − 413
/* PHYSFS_Io implementation for i/o to a PHYSFS_File... */
+ − 414
+ − 415
static PHYSFS_sint64 handleIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+ − 416
{
+ − 417
return PHYSFS_readBytes((PHYSFS_File *) io->opaque, buf, len);
+ − 418
} /* handleIo_read */
+ − 419
+ − 420
static PHYSFS_sint64 handleIo_write(PHYSFS_Io *io, const void *buffer,
+ − 421
PHYSFS_uint64 len)
+ − 422
{
+ − 423
return PHYSFS_writeBytes((PHYSFS_File *) io->opaque, buffer, len);
+ − 424
} /* handleIo_write */
+ − 425
+ − 426
static int handleIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+ − 427
{
+ − 428
return PHYSFS_seek((PHYSFS_File *) io->opaque, offset);
+ − 429
} /* handleIo_seek */
+ − 430
+ − 431
static PHYSFS_sint64 handleIo_tell(PHYSFS_Io *io)
+ − 432
{
+ − 433
return PHYSFS_tell((PHYSFS_File *) io->opaque);
+ − 434
} /* handleIo_tell */
+ − 435
+ − 436
static PHYSFS_sint64 handleIo_length(PHYSFS_Io *io)
+ − 437
{
+ − 438
return PHYSFS_fileLength((PHYSFS_File *) io->opaque);
+ − 439
} /* handleIo_length */
+ − 440
+ − 441
static PHYSFS_Io *handleIo_duplicate(PHYSFS_Io *io)
+ − 442
{
+ − 443
/*
+ − 444
* There's no duplicate at the PHYSFS_File level, so we break the
+ − 445
* abstraction. We're allowed to: we're physfs.c!
+ − 446
*/
+ − 447
FileHandle *origfh = (FileHandle *) io->opaque;
+ − 448
FileHandle *newfh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+ − 449
PHYSFS_Io *retval = NULL;
+ − 450
+ − 451
GOTO_IF_MACRO(!newfh, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+ − 452
memset(newfh, '\0', sizeof (*newfh));
+ − 453
+ − 454
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ − 455
GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+ − 456
+ − 457
#if 0 /* we don't buffer the duplicate, at least not at the moment. */
+ − 458
if (origfh->buffer != NULL)
+ − 459
{
+ − 460
newfh->buffer = (PHYSFS_uint8 *) allocator.Malloc(origfh->bufsize);
+ − 461
if (!newfh->buffer)
+ − 462
GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+ − 463
newfh->bufsize = origfh->bufsize;
+ − 464
} /* if */
+ − 465
#endif
+ − 466
+ − 467
newfh->io = origfh->io->duplicate(origfh->io);
+ − 468
GOTO_IF_MACRO(!newfh->io, ERRPASS, handleIo_dupe_failed);
+ − 469
+ − 470
newfh->forReading = origfh->forReading;
+ − 471
newfh->dirHandle = origfh->dirHandle;
+ − 472
+ − 473
__PHYSFS_platformGrabMutex(stateLock);
+ − 474
if (newfh->forReading)
+ − 475
{
+ − 476
newfh->next = openReadList;
+ − 477
openReadList = newfh;
+ − 478
} /* if */
+ − 479
else
+ − 480
{
+ − 481
newfh->next = openWriteList;
+ − 482
openWriteList = newfh;
+ − 483
} /* else */
+ − 484
__PHYSFS_platformReleaseMutex(stateLock);
+ − 485
+ − 486
memcpy(retval, io, sizeof (PHYSFS_Io));
+ − 487
retval->opaque = newfh;
+ − 488
return retval;
10017
+ − 489
7768
+ − 490
handleIo_dupe_failed:
+ − 491
if (newfh)
+ − 492
{
+ − 493
if (newfh->io != NULL) newfh->io->destroy(newfh->io);
+ − 494
if (newfh->buffer != NULL) allocator.Free(newfh->buffer);
+ − 495
allocator.Free(newfh);
+ − 496
} /* if */
+ − 497
+ − 498
return NULL;
+ − 499
} /* handleIo_duplicate */
+ − 500
+ − 501
static int handleIo_flush(PHYSFS_Io *io)
+ − 502
{
+ − 503
return PHYSFS_flush((PHYSFS_File *) io->opaque);
+ − 504
} /* handleIo_flush */
+ − 505
+ − 506
static void handleIo_destroy(PHYSFS_Io *io)
+ − 507
{
+ − 508
if (io->opaque != NULL)
+ − 509
PHYSFS_close((PHYSFS_File *) io->opaque);
+ − 510
allocator.Free(io);
+ − 511
} /* handleIo_destroy */
+ − 512
+ − 513
static const PHYSFS_Io __PHYSFS_handleIoInterface =
+ − 514
{
+ − 515
CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ − 516
handleIo_read,
+ − 517
handleIo_write,
+ − 518
handleIo_seek,
+ − 519
handleIo_tell,
+ − 520
handleIo_length,
+ − 521
handleIo_duplicate,
+ − 522
handleIo_flush,
+ − 523
handleIo_destroy
+ − 524
};
+ − 525
+ − 526
static PHYSFS_Io *__PHYSFS_createHandleIo(PHYSFS_File *f)
+ − 527
{
+ − 528
PHYSFS_Io *io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ − 529
BAIL_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 530
memcpy(io, &__PHYSFS_handleIoInterface, sizeof (*io));
+ − 531
io->opaque = f;
+ − 532
return io;
+ − 533
} /* __PHYSFS_createHandleIo */
+ − 534
+ − 535
+ − 536
/* functions ... */
+ − 537
+ − 538
typedef struct
+ − 539
{
+ − 540
char **list;
+ − 541
PHYSFS_uint32 size;
+ − 542
PHYSFS_ErrorCode errcode;
+ − 543
} EnumStringListCallbackData;
+ − 544
+ − 545
static void enumStringListCallback(void *data, const char *str)
+ − 546
{
+ − 547
void *ptr;
+ − 548
char *newstr;
+ − 549
EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+ − 550
+ − 551
if (pecd->errcode)
+ − 552
return;
+ − 553
+ − 554
ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+ − 555
newstr = (char *) allocator.Malloc(strlen(str) + 1);
+ − 556
if (ptr != NULL)
+ − 557
pecd->list = (char **) ptr;
+ − 558
+ − 559
if ((ptr == NULL) || (newstr == NULL))
+ − 560
{
+ − 561
pecd->errcode = PHYSFS_ERR_OUT_OF_MEMORY;
+ − 562
pecd->list[pecd->size] = NULL;
+ − 563
PHYSFS_freeList(pecd->list);
+ − 564
return;
+ − 565
} /* if */
+ − 566
+ − 567
strcpy(newstr, str);
+ − 568
pecd->list[pecd->size] = newstr;
+ − 569
pecd->size++;
+ − 570
} /* enumStringListCallback */
+ − 571
+ − 572
+ − 573
static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
+ − 574
{
+ − 575
EnumStringListCallbackData ecd;
+ − 576
memset(&ecd, '\0', sizeof (ecd));
+ − 577
ecd.list = (char **) allocator.Malloc(sizeof (char *));
+ − 578
BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 579
func(enumStringListCallback, &ecd);
+ − 580
+ − 581
if (ecd.errcode)
+ − 582
{
+ − 583
__PHYSFS_setError(ecd.errcode);
+ − 584
return NULL;
+ − 585
} /* if */
+ − 586
+ − 587
ecd.list[ecd.size] = NULL;
+ − 588
return ecd.list;
+ − 589
} /* doEnumStringList */
+ − 590
+ − 591
+ − 592
static void __PHYSFS_bubble_sort(void *a, size_t lo, size_t hi,
+ − 593
int (*cmpfn)(void *, size_t, size_t),
+ − 594
void (*swapfn)(void *, size_t, size_t))
+ − 595
{
+ − 596
size_t i;
+ − 597
int sorted;
+ − 598
+ − 599
do
+ − 600
{
+ − 601
sorted = 1;
+ − 602
for (i = lo; i < hi; i++)
+ − 603
{
+ − 604
if (cmpfn(a, i, i + 1) > 0)
+ − 605
{
+ − 606
swapfn(a, i, i + 1);
+ − 607
sorted = 0;
+ − 608
} /* if */
+ − 609
} /* for */
+ − 610
} while (!sorted);
+ − 611
} /* __PHYSFS_bubble_sort */
+ − 612
+ − 613
+ − 614
static void __PHYSFS_quick_sort(void *a, size_t lo, size_t hi,
+ − 615
int (*cmpfn)(void *, size_t, size_t),
+ − 616
void (*swapfn)(void *, size_t, size_t))
+ − 617
{
+ − 618
size_t i;
+ − 619
size_t j;
+ − 620
size_t v;
+ − 621
+ − 622
if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD)
+ − 623
__PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn);
+ − 624
else
+ − 625
{
+ − 626
i = (hi + lo) / 2;
+ − 627
+ − 628
if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i);
+ − 629
if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi);
+ − 630
if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi);
+ − 631
+ − 632
j = hi - 1;
+ − 633
swapfn(a, i, j);
+ − 634
i = lo;
+ − 635
v = j;
+ − 636
while (1)
+ − 637
{
+ − 638
while(cmpfn(a, ++i, v) < 0) { /* do nothing */ }
+ − 639
while(cmpfn(a, --j, v) > 0) { /* do nothing */ }
+ − 640
if (j < i)
+ − 641
break;
+ − 642
swapfn(a, i, j);
+ − 643
} /* while */
+ − 644
if (i != (hi-1))
+ − 645
swapfn(a, i, hi-1);
+ − 646
__PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn);
+ − 647
__PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn);
+ − 648
} /* else */
+ − 649
} /* __PHYSFS_quick_sort */
+ − 650
+ − 651
+ − 652
void __PHYSFS_sort(void *entries, size_t max,
+ − 653
int (*cmpfn)(void *, size_t, size_t),
+ − 654
void (*swapfn)(void *, size_t, size_t))
+ − 655
{
+ − 656
/*
+ − 657
* Quicksort w/ Bubblesort fallback algorithm inspired by code from here:
+ − 658
* http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html
+ − 659
*/
+ − 660
if (max > 0)
+ − 661
__PHYSFS_quick_sort(entries, 0, max - 1, cmpfn, swapfn);
+ − 662
} /* __PHYSFS_sort */
+ − 663
+ − 664
+ − 665
static ErrState *findErrorForCurrentThread(void)
+ − 666
{
+ − 667
ErrState *i;
+ − 668
void *tid;
+ − 669
+ − 670
if (errorLock != NULL)
+ − 671
__PHYSFS_platformGrabMutex(errorLock);
+ − 672
+ − 673
if (errorStates != NULL)
+ − 674
{
+ − 675
tid = __PHYSFS_platformGetThreadID();
+ − 676
+ − 677
for (i = errorStates; i != NULL; i = i->next)
+ − 678
{
+ − 679
if (i->tid == tid)
+ − 680
{
+ − 681
if (errorLock != NULL)
+ − 682
__PHYSFS_platformReleaseMutex(errorLock);
+ − 683
return i;
+ − 684
} /* if */
+ − 685
} /* for */
+ − 686
} /* if */
+ − 687
+ − 688
if (errorLock != NULL)
+ − 689
__PHYSFS_platformReleaseMutex(errorLock);
+ − 690
+ − 691
return NULL; /* no error available. */
+ − 692
} /* findErrorForCurrentThread */
+ − 693
+ − 694
+ − 695
void __PHYSFS_setError(const PHYSFS_ErrorCode errcode)
+ − 696
{
+ − 697
ErrState *err;
+ − 698
+ − 699
if (!errcode)
+ − 700
return;
+ − 701
+ − 702
err = findErrorForCurrentThread();
+ − 703
if (err == NULL)
+ − 704
{
+ − 705
err = (ErrState *) allocator.Malloc(sizeof (ErrState));
+ − 706
if (err == NULL)
+ − 707
return; /* uhh...? */
+ − 708
+ − 709
memset(err, '\0', sizeof (ErrState));
+ − 710
err->tid = __PHYSFS_platformGetThreadID();
+ − 711
+ − 712
if (errorLock != NULL)
+ − 713
__PHYSFS_platformGrabMutex(errorLock);
+ − 714
+ − 715
err->next = errorStates;
+ − 716
errorStates = err;
+ − 717
+ − 718
if (errorLock != NULL)
+ − 719
__PHYSFS_platformReleaseMutex(errorLock);
+ − 720
} /* if */
+ − 721
+ − 722
err->code = errcode;
+ − 723
} /* __PHYSFS_setError */
+ − 724
+ − 725
+ − 726
PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
+ − 727
{
+ − 728
ErrState *err = findErrorForCurrentThread();
+ − 729
const PHYSFS_ErrorCode retval = (err) ? err->code : PHYSFS_ERR_OK;
+ − 730
if (err)
+ − 731
err->code = PHYSFS_ERR_OK;
+ − 732
return retval;
+ − 733
} /* PHYSFS_getLastErrorCode */
+ − 734
+ − 735
+ − 736
PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
+ − 737
{
+ − 738
switch (code)
+ − 739
{
+ − 740
case PHYSFS_ERR_OK: return "no error";
+ − 741
case PHYSFS_ERR_OTHER_ERROR: return "unknown error";
+ − 742
case PHYSFS_ERR_OUT_OF_MEMORY: return "out of memory";
+ − 743
case PHYSFS_ERR_NOT_INITIALIZED: return "not initialized";
+ − 744
case PHYSFS_ERR_IS_INITIALIZED: return "already initialized";
+ − 745
case PHYSFS_ERR_ARGV0_IS_NULL: return "argv[0] is NULL";
+ − 746
case PHYSFS_ERR_UNSUPPORTED: return "unsupported";
+ − 747
case PHYSFS_ERR_PAST_EOF: return "past end of file";
+ − 748
case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open";
+ − 749
case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument";
+ − 750
case PHYSFS_ERR_NOT_MOUNTED: return "not mounted";
+ − 751
case PHYSFS_ERR_NO_SUCH_PATH: return "no such path";
+ − 752
case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden";
+ − 753
case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set";
+ − 754
case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading";
+ − 755
case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing";
+ − 756
case PHYSFS_ERR_NOT_A_FILE: return "not a file";
+ − 757
case PHYSFS_ERR_READ_ONLY: return "read-only filesystem";
+ − 758
case PHYSFS_ERR_CORRUPT: return "corrupted";
+ − 759
case PHYSFS_ERR_SYMLINK_LOOP: return "infinite symbolic link loop";
+ − 760
case PHYSFS_ERR_IO: return "i/o error";
+ − 761
case PHYSFS_ERR_PERMISSION: return "permission denied";
+ − 762
case PHYSFS_ERR_NO_SPACE: return "no space available for writing";
+ − 763
case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure";
+ − 764
case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs";
+ − 765
case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty";
+ − 766
case PHYSFS_ERR_OS_ERROR: return "OS reported an error";
+ − 767
} /* switch */
+ − 768
+ − 769
return NULL; /* don't know this error code. */
+ − 770
} /* PHYSFS_getErrorByCode */
+ − 771
+ − 772
+ − 773
void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
+ − 774
{
+ − 775
__PHYSFS_setError(code);
+ − 776
} /* PHYSFS_setErrorCode */
+ − 777
+ − 778
+ − 779
const char *PHYSFS_getLastError(void)
+ − 780
{
+ − 781
const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
+ − 782
return (err) ? PHYSFS_getErrorByCode(err) : NULL;
+ − 783
} /* PHYSFS_getLastError */
+ − 784
+ − 785
+ − 786
/* MAKE SURE that errorLock is held before calling this! */
+ − 787
static void freeErrorStates(void)
+ − 788
{
+ − 789
ErrState *i;
+ − 790
ErrState *next;
+ − 791
+ − 792
for (i = errorStates; i != NULL; i = next)
+ − 793
{
+ − 794
next = i->next;
+ − 795
allocator.Free(i);
+ − 796
} /* for */
+ − 797
+ − 798
errorStates = NULL;
+ − 799
} /* freeErrorStates */
+ − 800
+ − 801
+ − 802
void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+ − 803
{
+ − 804
if (ver != NULL)
+ − 805
{
+ − 806
ver->major = PHYSFS_VER_MAJOR;
+ − 807
ver->minor = PHYSFS_VER_MINOR;
+ − 808
ver->patch = PHYSFS_VER_PATCH;
+ − 809
} /* if */
+ − 810
} /* PHYSFS_getLinkedVersion */
+ − 811
+ − 812
+ − 813
static const char *find_filename_extension(const char *fname)
+ − 814
{
+ − 815
const char *retval = NULL;
+ − 816
if (fname != NULL)
+ − 817
{
+ − 818
const char *p = strchr(fname, '.');
+ − 819
retval = p;
+ − 820
+ − 821
while (p != NULL)
+ − 822
{
+ − 823
p = strchr(p + 1, '.');
+ − 824
if (p != NULL)
+ − 825
retval = p;
+ − 826
} /* while */
+ − 827
+ − 828
if (retval != NULL)
+ − 829
retval++; /* skip '.' */
+ − 830
} /* if */
+ − 831
+ − 832
return retval;
+ − 833
} /* find_filename_extension */
+ − 834
+ − 835
+ − 836
static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
+ − 837
const char *d, int forWriting)
+ − 838
{
+ − 839
DirHandle *retval = NULL;
+ − 840
void *opaque = NULL;
+ − 841
+ − 842
if (io != NULL)
+ − 843
BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
+ − 844
+ − 845
opaque = funcs->openArchive(io, d, forWriting);
+ − 846
if (opaque != NULL)
+ − 847
{
+ − 848
retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
+ − 849
if (retval == NULL)
+ − 850
funcs->closeArchive(opaque);
+ − 851
else
+ − 852
{
+ − 853
memset(retval, '\0', sizeof (DirHandle));
+ − 854
retval->mountPoint = NULL;
+ − 855
retval->funcs = funcs;
+ − 856
retval->opaque = opaque;
+ − 857
} /* else */
+ − 858
} /* if */
+ − 859
+ − 860
return retval;
+ − 861
} /* tryOpenDir */
+ − 862
+ − 863
+ − 864
static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
+ − 865
{
+ − 866
DirHandle *retval = NULL;
+ − 867
const PHYSFS_Archiver **i;
+ − 868
const char *ext;
+ − 869
+ − 870
assert((io != NULL) || (d != NULL));
+ − 871
+ − 872
if (io == NULL)
+ − 873
{
+ − 874
/* DIR gets first shot (unlike the rest, it doesn't deal with files). */
+ − 875
retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
+ − 876
if (retval != NULL)
+ − 877
return retval;
+ − 878
+ − 879
io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
+ − 880
BAIL_IF_MACRO(!io, ERRPASS, 0);
+ − 881
} /* if */
+ − 882
+ − 883
ext = find_filename_extension(d);
+ − 884
if (ext != NULL)
+ − 885
{
+ − 886
/* Look for archivers with matching file extensions first... */
+ − 887
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+ − 888
{
+ − 889
if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0)
+ − 890
retval = tryOpenDir(io, *i, d, forWriting);
+ − 891
} /* for */
+ − 892
+ − 893
/* failing an exact file extension match, try all the others... */
+ − 894
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+ − 895
{
+ − 896
if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) != 0)
+ − 897
retval = tryOpenDir(io, *i, d, forWriting);
+ − 898
} /* for */
+ − 899
} /* if */
+ − 900
+ − 901
else /* no extension? Try them all. */
+ − 902
{
+ − 903
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+ − 904
retval = tryOpenDir(io, *i, d, forWriting);
+ − 905
} /* else */
+ − 906
+ − 907
BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL);
+ − 908
return retval;
+ − 909
} /* openDirectory */
+ − 910
+ − 911
+ − 912
/*
+ − 913
* Make a platform-independent path string sane. Doesn't actually check the
+ − 914
* file hierarchy, it just cleans up the string.
+ − 915
* (dst) must be a buffer at least as big as (src), as this is where the
+ − 916
* cleaned up string is deposited.
+ − 917
* If there are illegal bits in the path (".." entries, etc) then we
+ − 918
* return zero and (dst) is undefined. Non-zero if the path was sanitized.
+ − 919
*/
+ − 920
static int sanitizePlatformIndependentPath(const char *src, char *dst)
+ − 921
{
+ − 922
char *prev;
+ − 923
char ch;
+ − 924
+ − 925
while (*src == '/') /* skip initial '/' chars... */
+ − 926
src++;
+ − 927
+ − 928
prev = dst;
+ − 929
do
+ − 930
{
+ − 931
ch = *(src++);
+ − 932
+ − 933
if ((ch == ':') || (ch == '\\')) /* illegal chars in a physfs path. */
+ − 934
BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
+ − 935
+ − 936
if (ch == '/') /* path separator. */
+ − 937
{
+ − 938
*dst = '\0'; /* "." and ".." are illegal pathnames. */
+ − 939
if ((strcmp(prev, ".") == 0) || (strcmp(prev, "..") == 0))
+ − 940
BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
+ − 941
+ − 942
while (*src == '/') /* chop out doubles... */
+ − 943
src++;
+ − 944
+ − 945
if (*src == '\0') /* ends with a pathsep? */
+ − 946
break; /* we're done, don't add final pathsep to dst. */
+ − 947
+ − 948
prev = dst + 1;
+ − 949
} /* if */
+ − 950
+ − 951
*(dst++) = ch;
+ − 952
} while (ch != '\0');
+ − 953
+ − 954
return 1;
+ − 955
} /* sanitizePlatformIndependentPath */
+ − 956
+ − 957
+ − 958
/*
+ − 959
* Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
+ − 960
* output from sanitizePlatformIndependentPath(), so that it is in a known
+ − 961
* state.
+ − 962
*
+ − 963
* This only finds legitimate segments of a mountpoint. If the mountpoint is
+ − 964
* "/a/b/c" and (fname) is "/a/b/c", "/", or "/a/b/c/d", then the results are
+ − 965
* all zero. "/a/b" will succeed, though.
+ − 966
*/
+ − 967
static int partOfMountPoint(DirHandle *h, char *fname)
+ − 968
{
+ − 969
/* !!! FIXME: This code feels gross. */
+ − 970
int rc;
+ − 971
size_t len, mntpntlen;
+ − 972
+ − 973
if (h->mountPoint == NULL)
+ − 974
return 0;
+ − 975
else if (*fname == '\0')
+ − 976
return 1;
+ − 977
+ − 978
len = strlen(fname);
+ − 979
mntpntlen = strlen(h->mountPoint);
+ − 980
if (len > mntpntlen) /* can't be a subset of mountpoint. */
+ − 981
return 0;
+ − 982
+ − 983
/* if true, must be not a match or a complete match, but not a subset. */
+ − 984
if ((len + 1) == mntpntlen)
+ − 985
return 0;
+ − 986
+ − 987
rc = strncmp(fname, h->mountPoint, len); /* !!! FIXME: case insensitive? */
+ − 988
if (rc != 0)
+ − 989
return 0; /* not a match. */
+ − 990
+ − 991
/* make sure /a/b matches /a/b/ and not /a/bc ... */
+ − 992
return h->mountPoint[len] == '/';
+ − 993
} /* partOfMountPoint */
+ − 994
+ − 995
+ − 996
static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
+ − 997
const char *mountPoint, int forWriting)
+ − 998
{
+ − 999
DirHandle *dirHandle = NULL;
+ − 1000
char *tmpmntpnt = NULL;
+ − 1001
+ − 1002
if (mountPoint != NULL)
+ − 1003
{
+ − 1004
const size_t len = strlen(mountPoint) + 1;
+ − 1005
tmpmntpnt = (char *) __PHYSFS_smallAlloc(len);
+ − 1006
GOTO_IF_MACRO(!tmpmntpnt, PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+ − 1007
if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt))
+ − 1008
goto badDirHandle;
+ − 1009
mountPoint = tmpmntpnt; /* sanitized version. */
+ − 1010
} /* if */
+ − 1011
+ − 1012
dirHandle = openDirectory(io, newDir, forWriting);
+ − 1013
GOTO_IF_MACRO(!dirHandle, ERRPASS, badDirHandle);
+ − 1014
+ − 1015
if (newDir == NULL)
+ − 1016
dirHandle->dirName = NULL;
+ − 1017
else
+ − 1018
{
+ − 1019
dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
+ − 1020
if (!dirHandle->dirName)
+ − 1021
GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+ − 1022
strcpy(dirHandle->dirName, newDir);
+ − 1023
} /* else */
+ − 1024
+ − 1025
if ((mountPoint != NULL) && (*mountPoint != '\0'))
+ − 1026
{
+ − 1027
dirHandle->mountPoint = (char *)allocator.Malloc(strlen(mountPoint)+2);
+ − 1028
if (!dirHandle->mountPoint)
+ − 1029
GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+ − 1030
strcpy(dirHandle->mountPoint, mountPoint);
+ − 1031
strcat(dirHandle->mountPoint, "/");
+ − 1032
} /* if */
+ − 1033
+ − 1034
__PHYSFS_smallFree(tmpmntpnt);
+ − 1035
return dirHandle;
+ − 1036
+ − 1037
badDirHandle:
+ − 1038
if (dirHandle != NULL)
+ − 1039
{
+ − 1040
dirHandle->funcs->closeArchive(dirHandle->opaque);
+ − 1041
allocator.Free(dirHandle->dirName);
+ − 1042
allocator.Free(dirHandle->mountPoint);
+ − 1043
allocator.Free(dirHandle);
+ − 1044
} /* if */
+ − 1045
+ − 1046
__PHYSFS_smallFree(tmpmntpnt);
+ − 1047
return NULL;
+ − 1048
} /* createDirHandle */
+ − 1049
+ − 1050
+ − 1051
/* MAKE SURE you've got the stateLock held before calling this! */
+ − 1052
static int freeDirHandle(DirHandle *dh, FileHandle *openList)
+ − 1053
{
+ − 1054
FileHandle *i;
+ − 1055
+ − 1056
if (dh == NULL)
+ − 1057
return 1;
+ − 1058
+ − 1059
for (i = openList; i != NULL; i = i->next)
+ − 1060
BAIL_IF_MACRO(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0);
+ − 1061
+ − 1062
dh->funcs->closeArchive(dh->opaque);
+ − 1063
allocator.Free(dh->dirName);
+ − 1064
allocator.Free(dh->mountPoint);
+ − 1065
allocator.Free(dh);
+ − 1066
return 1;
+ − 1067
} /* freeDirHandle */
+ − 1068
+ − 1069
+ − 1070
static char *calculateBaseDir(const char *argv0)
+ − 1071
{
+ − 1072
const char dirsep = __PHYSFS_platformDirSeparator;
+ − 1073
char *retval = NULL;
+ − 1074
char *ptr = NULL;
+ − 1075
+ − 1076
/* Give the platform layer first shot at this. */
+ − 1077
retval = __PHYSFS_platformCalcBaseDir(argv0);
+ − 1078
if (retval != NULL)
+ − 1079
return retval;
+ − 1080
+ − 1081
/* We need argv0 to go on. */
+ − 1082
BAIL_IF_MACRO(argv0 == NULL, PHYSFS_ERR_ARGV0_IS_NULL, NULL);
+ − 1083
+ − 1084
ptr = strrchr(argv0, dirsep);
+ − 1085
if (ptr != NULL)
+ − 1086
{
+ − 1087
const size_t size = ((size_t) (ptr - argv0)) + 1;
+ − 1088
retval = (char *) allocator.Malloc(size + 1);
+ − 1089
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 1090
memcpy(retval, argv0, size);
+ − 1091
retval[size] = '\0';
+ − 1092
return retval;
+ − 1093
} /* if */
+ − 1094
+ − 1095
/* argv0 wasn't helpful. */
+ − 1096
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ − 1097
} /* calculateBaseDir */
+ − 1098
+ − 1099
+ − 1100
static int initializeMutexes(void)
+ − 1101
{
+ − 1102
errorLock = __PHYSFS_platformCreateMutex();
+ − 1103
if (errorLock == NULL)
+ − 1104
goto initializeMutexes_failed;
+ − 1105
+ − 1106
stateLock = __PHYSFS_platformCreateMutex();
+ − 1107
if (stateLock == NULL)
+ − 1108
goto initializeMutexes_failed;
+ − 1109
+ − 1110
return 1; /* success. */
+ − 1111
+ − 1112
initializeMutexes_failed:
+ − 1113
if (errorLock != NULL)
+ − 1114
__PHYSFS_platformDestroyMutex(errorLock);
+ − 1115
+ − 1116
if (stateLock != NULL)
+ − 1117
__PHYSFS_platformDestroyMutex(stateLock);
+ − 1118
+ − 1119
errorLock = stateLock = NULL;
+ − 1120
return 0; /* failed. */
+ − 1121
} /* initializeMutexes */
+ − 1122
+ − 1123
+ − 1124
static void setDefaultAllocator(void);
+ − 1125
+ − 1126
static int initStaticArchivers(void)
+ − 1127
{
+ − 1128
const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers);
+ − 1129
const size_t len = numStaticArchivers * sizeof (void *);
+ − 1130
size_t i;
+ − 1131
+ − 1132
assert(numStaticArchivers > 0); /* seriously, none at all?! */
+ − 1133
assert(staticArchivers[numStaticArchivers - 1] == NULL);
+ − 1134
+ − 1135
archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len);
+ − 1136
BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 1137
archivers = (const PHYSFS_Archiver **) allocator.Malloc(len);
+ − 1138
BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 1139
+ − 1140
for (i = 0; i < numStaticArchivers - 1; i++)
+ − 1141
archiveInfo[i] = &staticArchivers[i]->info;
+ − 1142
archiveInfo[numStaticArchivers - 1] = NULL;
+ − 1143
+ − 1144
memcpy(archivers, staticArchivers, len);
+ − 1145
+ − 1146
return 1;
+ − 1147
} /* initStaticArchivers */
+ − 1148
+ − 1149
+ − 1150
static int doDeinit(void);
+ − 1151
+ − 1152
int PHYSFS_init(const char *argv0)
+ − 1153
{
+ − 1154
BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
+ − 1155
+ − 1156
if (!externalAllocator)
+ − 1157
setDefaultAllocator();
+ − 1158
+ − 1159
if ((allocator.Init != NULL) && (!allocator.Init())) return 0;
+ − 1160
+ − 1161
if (!__PHYSFS_platformInit())
+ − 1162
{
+ − 1163
if (allocator.Deinit != NULL) allocator.Deinit();
+ − 1164
return 0;
+ − 1165
} /* if */
+ − 1166
+ − 1167
/* everything below here can be cleaned up safely by doDeinit(). */
+ − 1168
+ − 1169
if (!initializeMutexes()) goto initFailed;
+ − 1170
+ − 1171
baseDir = calculateBaseDir(argv0);
+ − 1172
if (!baseDir) goto initFailed;
+ − 1173
+ − 1174
userDir = __PHYSFS_platformCalcUserDir();
+ − 1175
if (!userDir) goto initFailed;
+ − 1176
+ − 1177
/* Platform layer is required to append a dirsep. */
+ − 1178
assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator);
+ − 1179
assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator);
+ − 1180
+ − 1181
if (!initStaticArchivers()) goto initFailed;
+ − 1182
+ − 1183
initialized = 1;
+ − 1184
+ − 1185
/* This makes sure that the error subsystem is initialized. */
+ − 1186
__PHYSFS_setError(PHYSFS_getLastErrorCode());
+ − 1187
+ − 1188
return 1;
+ − 1189
+ − 1190
initFailed:
+ − 1191
doDeinit();
+ − 1192
return 0;
+ − 1193
} /* PHYSFS_init */
+ − 1194
+ − 1195
+ − 1196
/* MAKE SURE you hold stateLock before calling this! */
+ − 1197
static int closeFileHandleList(FileHandle **list)
+ − 1198
{
+ − 1199
FileHandle *i;
+ − 1200
FileHandle *next = NULL;
+ − 1201
+ − 1202
for (i = *list; i != NULL; i = next)
+ − 1203
{
+ − 1204
PHYSFS_Io *io = i->io;
+ − 1205
next = i->next;
+ − 1206
+ − 1207
if (!io->flush(io))
+ − 1208
{
+ − 1209
*list = i;
+ − 1210
return 0;
+ − 1211
} /* if */
+ − 1212
+ − 1213
io->destroy(io);
+ − 1214
allocator.Free(i);
+ − 1215
} /* for */
+ − 1216
+ − 1217
*list = NULL;
+ − 1218
return 1;
+ − 1219
} /* closeFileHandleList */
+ − 1220
+ − 1221
+ − 1222
/* MAKE SURE you hold the stateLock before calling this! */
+ − 1223
static void freeSearchPath(void)
+ − 1224
{
+ − 1225
DirHandle *i;
+ − 1226
DirHandle *next = NULL;
+ − 1227
+ − 1228
closeFileHandleList(&openReadList);
+ − 1229
+ − 1230
if (searchPath != NULL)
+ − 1231
{
+ − 1232
for (i = searchPath; i != NULL; i = next)
+ − 1233
{
+ − 1234
next = i->next;
+ − 1235
freeDirHandle(i, openReadList);
+ − 1236
} /* for */
+ − 1237
searchPath = NULL;
+ − 1238
} /* if */
+ − 1239
} /* freeSearchPath */
+ − 1240
+ − 1241
+ − 1242
static int doDeinit(void)
+ − 1243
{
+ − 1244
BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0);
+ − 1245
+ − 1246
closeFileHandleList(&openWriteList);
+ − 1247
BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0);
+ − 1248
+ − 1249
freeSearchPath();
+ − 1250
freeErrorStates();
+ − 1251
+ − 1252
if (baseDir != NULL)
+ − 1253
{
+ − 1254
allocator.Free(baseDir);
+ − 1255
baseDir = NULL;
+ − 1256
} /* if */
+ − 1257
+ − 1258
if (userDir != NULL)
+ − 1259
{
+ − 1260
allocator.Free(userDir);
+ − 1261
userDir = NULL;
+ − 1262
} /* if */
+ − 1263
+ − 1264
if (prefDir != NULL)
+ − 1265
{
+ − 1266
allocator.Free(prefDir);
+ − 1267
prefDir = NULL;
+ − 1268
} /* if */
+ − 1269
+ − 1270
if (archiveInfo != NULL)
+ − 1271
{
+ − 1272
allocator.Free(archiveInfo);
+ − 1273
archiveInfo = NULL;
+ − 1274
} /* if */
+ − 1275
+ − 1276
if (archivers != NULL)
+ − 1277
{
+ − 1278
allocator.Free(archivers);
+ − 1279
archivers = NULL;
+ − 1280
} /* if */
+ − 1281
+ − 1282
allowSymLinks = 0;
+ − 1283
initialized = 0;
+ − 1284
+ − 1285
if (errorLock) __PHYSFS_platformDestroyMutex(errorLock);
+ − 1286
if (stateLock) __PHYSFS_platformDestroyMutex(stateLock);
+ − 1287
+ − 1288
if (allocator.Deinit != NULL)
+ − 1289
allocator.Deinit();
+ − 1290
+ − 1291
errorLock = stateLock = NULL;
+ − 1292
return 1;
+ − 1293
} /* doDeinit */
+ − 1294
+ − 1295
+ − 1296
int PHYSFS_deinit(void)
+ − 1297
{
+ − 1298
BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+ − 1299
return doDeinit();
+ − 1300
} /* PHYSFS_deinit */
+ − 1301
+ − 1302
+ − 1303
int PHYSFS_isInit(void)
+ − 1304
{
+ − 1305
return initialized;
+ − 1306
} /* PHYSFS_isInit */
+ − 1307
+ − 1308
+ − 1309
const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+ − 1310
{
+ − 1311
BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
+ − 1312
return archiveInfo;
+ − 1313
} /* PHYSFS_supportedArchiveTypes */
+ − 1314
+ − 1315
+ − 1316
void PHYSFS_freeList(void *list)
+ − 1317
{
+ − 1318
void **i;
+ − 1319
if (list != NULL)
+ − 1320
{
+ − 1321
for (i = (void **) list; *i != NULL; i++)
+ − 1322
allocator.Free(*i);
+ − 1323
+ − 1324
allocator.Free(list);
+ − 1325
} /* if */
+ − 1326
} /* PHYSFS_freeList */
+ − 1327
+ − 1328
+ − 1329
const char *PHYSFS_getDirSeparator(void)
+ − 1330
{
+ − 1331
static char retval[2] = { __PHYSFS_platformDirSeparator, '\0' };
+ − 1332
return retval;
+ − 1333
} /* PHYSFS_getDirSeparator */
+ − 1334
+ − 1335
+ − 1336
char **PHYSFS_getCdRomDirs(void)
+ − 1337
{
+ − 1338
return doEnumStringList(__PHYSFS_platformDetectAvailableCDs);
+ − 1339
} /* PHYSFS_getCdRomDirs */
+ − 1340
+ − 1341
+ − 1342
void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
+ − 1343
{
+ − 1344
__PHYSFS_platformDetectAvailableCDs(callback, data);
+ − 1345
} /* PHYSFS_getCdRomDirsCallback */
+ − 1346
+ − 1347
+ − 1348
const char *PHYSFS_getPrefDir(const char *org, const char *app)
+ − 1349
{
+ − 1350
const char dirsep = __PHYSFS_platformDirSeparator;
+ − 1351
PHYSFS_Stat statbuf;
+ − 1352
char *ptr = NULL;
+ − 1353
char *endstr = NULL;
+ − 1354
int exists = 0;
+ − 1355
+ − 1356
BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+ − 1357
BAIL_IF_MACRO(!org, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ − 1358
BAIL_IF_MACRO(*org == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ − 1359
BAIL_IF_MACRO(!app, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ − 1360
BAIL_IF_MACRO(*app == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ − 1361
+ − 1362
allocator.Free(prefDir);
+ − 1363
prefDir = __PHYSFS_platformCalcPrefDir(org, app);
+ − 1364
BAIL_IF_MACRO(!prefDir, ERRPASS, NULL);
+ − 1365
+ − 1366
assert(strlen(prefDir) > 0);
+ − 1367
endstr = prefDir + (strlen(prefDir) - 1);
+ − 1368
assert(*endstr == dirsep);
+ − 1369
*endstr = '\0'; /* mask out the final dirsep for now. */
+ − 1370
+ − 1371
if (!__PHYSFS_platformStat(prefDir, &exists, &statbuf))
+ − 1372
{
+ − 1373
for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep))
+ − 1374
{
+ − 1375
*ptr = '\0';
+ − 1376
__PHYSFS_platformMkDir(prefDir);
+ − 1377
*ptr = dirsep;
+ − 1378
} /* for */
+ − 1379
+ − 1380
if (!__PHYSFS_platformMkDir(prefDir))
+ − 1381
{
+ − 1382
allocator.Free(prefDir);
+ − 1383
prefDir = NULL;
+ − 1384
} /* if */
+ − 1385
} /* if */
+ − 1386
+ − 1387
*endstr = dirsep; /* readd the final dirsep. */
+ − 1388
+ − 1389
return prefDir;
+ − 1390
} /* PHYSFS_getPrefDir */
+ − 1391
+ − 1392
+ − 1393
const char *PHYSFS_getBaseDir(void)
+ − 1394
{
+ − 1395
return baseDir; /* this is calculated in PHYSFS_init()... */
+ − 1396
} /* PHYSFS_getBaseDir */
+ − 1397
+ − 1398
+ − 1399
const char *__PHYSFS_getUserDir(void) /* not deprecated internal version. */
+ − 1400
{
+ − 1401
return userDir; /* this is calculated in PHYSFS_init()... */
+ − 1402
} /* __PHYSFS_getUserDir */
+ − 1403
+ − 1404
+ − 1405
const char *PHYSFS_getUserDir(void)
+ − 1406
{
+ − 1407
return __PHYSFS_getUserDir();
+ − 1408
} /* PHYSFS_getUserDir */
+ − 1409
+ − 1410
+ − 1411
const char *PHYSFS_getWriteDir(void)
+ − 1412
{
+ − 1413
const char *retval = NULL;
+ − 1414
+ − 1415
__PHYSFS_platformGrabMutex(stateLock);
+ − 1416
if (writeDir != NULL)
+ − 1417
retval = writeDir->dirName;
+ − 1418
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1419
+ − 1420
return retval;
+ − 1421
} /* PHYSFS_getWriteDir */
+ − 1422
+ − 1423
+ − 1424
int PHYSFS_setWriteDir(const char *newDir)
+ − 1425
{
+ − 1426
int retval = 1;
+ − 1427
+ − 1428
__PHYSFS_platformGrabMutex(stateLock);
+ − 1429
+ − 1430
if (writeDir != NULL)
+ − 1431
{
+ − 1432
BAIL_IF_MACRO_MUTEX(!freeDirHandle(writeDir, openWriteList), ERRPASS,
+ − 1433
stateLock, 0);
+ − 1434
writeDir = NULL;
+ − 1435
} /* if */
+ − 1436
+ − 1437
if (newDir != NULL)
+ − 1438
{
+ − 1439
/* !!! FIXME: PHYSFS_Io shouldn't be NULL */
+ − 1440
writeDir = createDirHandle(NULL, newDir, NULL, 1);
+ − 1441
retval = (writeDir != NULL);
+ − 1442
} /* if */
+ − 1443
+ − 1444
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1445
+ − 1446
return retval;
+ − 1447
} /* PHYSFS_setWriteDir */
+ − 1448
+ − 1449
+ − 1450
static int doMount(PHYSFS_Io *io, const char *fname,
+ − 1451
const char *mountPoint, int appendToPath)
+ − 1452
{
+ − 1453
DirHandle *dh;
+ − 1454
DirHandle *prev = NULL;
+ − 1455
DirHandle *i;
+ − 1456
+ − 1457
if (mountPoint == NULL)
+ − 1458
mountPoint = "/";
+ − 1459
+ − 1460
__PHYSFS_platformGrabMutex(stateLock);
+ − 1461
+ − 1462
if (fname != NULL)
+ − 1463
{
+ − 1464
for (i = searchPath; i != NULL; i = i->next)
+ − 1465
{
+ − 1466
/* already in search path? */
+ − 1467
if ((i->dirName != NULL) && (strcmp(fname, i->dirName) == 0))
+ − 1468
BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
+ − 1469
prev = i;
+ − 1470
} /* for */
+ − 1471
} /* if */
+ − 1472
+ − 1473
dh = createDirHandle(io, fname, mountPoint, 0);
+ − 1474
BAIL_IF_MACRO_MUTEX(!dh, ERRPASS, stateLock, 0);
+ − 1475
+ − 1476
if (appendToPath)
+ − 1477
{
+ − 1478
if (prev == NULL)
+ − 1479
searchPath = dh;
+ − 1480
else
+ − 1481
prev->next = dh;
+ − 1482
} /* if */
+ − 1483
else
+ − 1484
{
+ − 1485
dh->next = searchPath;
+ − 1486
searchPath = dh;
+ − 1487
} /* else */
+ − 1488
+ − 1489
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1490
return 1;
+ − 1491
} /* doMount */
+ − 1492
+ − 1493
+ − 1494
int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
+ − 1495
const char *mountPoint, int appendToPath)
+ − 1496
{
+ − 1497
BAIL_IF_MACRO(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1498
BAIL_IF_MACRO(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0);
+ − 1499
return doMount(io, fname, mountPoint, appendToPath);
+ − 1500
} /* PHYSFS_mountIo */
+ − 1501
+ − 1502
+ − 1503
int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *),
+ − 1504
const char *fname, const char *mountPoint,
+ − 1505
int appendToPath)
+ − 1506
{
+ − 1507
int retval = 0;
+ − 1508
PHYSFS_Io *io = NULL;
+ − 1509
+ − 1510
BAIL_IF_MACRO(!buf, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1511
+ − 1512
io = __PHYSFS_createMemoryIo(buf, len, del);
+ − 1513
BAIL_IF_MACRO(!io, ERRPASS, 0);
+ − 1514
retval = doMount(io, fname, mountPoint, appendToPath);
+ − 1515
if (!retval)
+ − 1516
{
+ − 1517
/* docs say not to call (del) in case of failure, so cheat. */
+ − 1518
MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ − 1519
info->destruct = NULL;
+ − 1520
io->destroy(io);
+ − 1521
} /* if */
+ − 1522
+ − 1523
return retval;
+ − 1524
} /* PHYSFS_mountMemory */
+ − 1525
+ − 1526
+ − 1527
int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
+ − 1528
const char *mountPoint, int appendToPath)
+ − 1529
{
+ − 1530
int retval = 0;
+ − 1531
PHYSFS_Io *io = NULL;
+ − 1532
+ − 1533
BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1534
+ − 1535
io = __PHYSFS_createHandleIo(file);
+ − 1536
BAIL_IF_MACRO(!io, ERRPASS, 0);
+ − 1537
retval = doMount(io, fname, mountPoint, appendToPath);
+ − 1538
if (!retval)
+ − 1539
{
+ − 1540
/* docs say not to destruct in case of failure, so cheat. */
+ − 1541
io->opaque = NULL;
+ − 1542
io->destroy(io);
+ − 1543
} /* if */
+ − 1544
+ − 1545
return retval;
+ − 1546
} /* PHYSFS_mountHandle */
+ − 1547
+ − 1548
+ − 1549
int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+ − 1550
{
+ − 1551
BAIL_IF_MACRO(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1552
return doMount(NULL, newDir, mountPoint, appendToPath);
+ − 1553
} /* PHYSFS_mount */
+ − 1554
+ − 1555
+ − 1556
int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+ − 1557
{
+ − 1558
return doMount(NULL, newDir, NULL, appendToPath);
+ − 1559
} /* PHYSFS_addToSearchPath */
+ − 1560
+ − 1561
+ − 1562
int PHYSFS_removeFromSearchPath(const char *oldDir)
+ − 1563
{
+ − 1564
return PHYSFS_unmount(oldDir);
+ − 1565
} /* PHYSFS_removeFromSearchPath */
+ − 1566
+ − 1567
+ − 1568
int PHYSFS_unmount(const char *oldDir)
+ − 1569
{
+ − 1570
DirHandle *i;
+ − 1571
DirHandle *prev = NULL;
+ − 1572
DirHandle *next = NULL;
+ − 1573
+ − 1574
BAIL_IF_MACRO(oldDir == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1575
+ − 1576
__PHYSFS_platformGrabMutex(stateLock);
+ − 1577
for (i = searchPath; i != NULL; i = i->next)
+ − 1578
{
+ − 1579
if (strcmp(i->dirName, oldDir) == 0)
+ − 1580
{
+ − 1581
next = i->next;
+ − 1582
BAIL_IF_MACRO_MUTEX(!freeDirHandle(i, openReadList), ERRPASS,
+ − 1583
stateLock, 0);
+ − 1584
+ − 1585
if (prev == NULL)
+ − 1586
searchPath = next;
+ − 1587
else
+ − 1588
prev->next = next;
+ − 1589
+ − 1590
BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
+ − 1591
} /* if */
+ − 1592
prev = i;
+ − 1593
} /* for */
+ − 1594
+ − 1595
BAIL_MACRO_MUTEX(PHYSFS_ERR_NOT_MOUNTED, stateLock, 0);
+ − 1596
} /* PHYSFS_unmount */
+ − 1597
+ − 1598
+ − 1599
char **PHYSFS_getSearchPath(void)
+ − 1600
{
+ − 1601
return doEnumStringList(PHYSFS_getSearchPathCallback);
+ − 1602
} /* PHYSFS_getSearchPath */
+ − 1603
+ − 1604
+ − 1605
const char *PHYSFS_getMountPoint(const char *dir)
+ − 1606
{
+ − 1607
DirHandle *i;
+ − 1608
__PHYSFS_platformGrabMutex(stateLock);
+ − 1609
for (i = searchPath; i != NULL; i = i->next)
+ − 1610
{
+ − 1611
if (strcmp(i->dirName, dir) == 0)
+ − 1612
{
+ − 1613
const char *retval = ((i->mountPoint) ? i->mountPoint : "/");
+ − 1614
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1615
return retval;
+ − 1616
} /* if */
+ − 1617
} /* for */
+ − 1618
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1619
+ − 1620
BAIL_MACRO(PHYSFS_ERR_NOT_MOUNTED, NULL);
+ − 1621
} /* PHYSFS_getMountPoint */
+ − 1622
+ − 1623
+ − 1624
void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data)
+ − 1625
{
+ − 1626
DirHandle *i;
+ − 1627
+ − 1628
__PHYSFS_platformGrabMutex(stateLock);
+ − 1629
+ − 1630
for (i = searchPath; i != NULL; i = i->next)
+ − 1631
callback(data, i->dirName);
+ − 1632
+ − 1633
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1634
} /* PHYSFS_getSearchPathCallback */
+ − 1635
+ − 1636
+ − 1637
/* Split out to avoid stack allocation in a loop. */
+ − 1638
static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep,
+ − 1639
int archivesFirst)
+ − 1640
{
+ − 1641
const char *d = PHYSFS_getRealDir(i);
+ − 1642
const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
+ − 1643
char *str = (char *) __PHYSFS_smallAlloc(allocsize);
+ − 1644
if (str != NULL)
+ − 1645
{
+ − 1646
sprintf(str, "%s%s%s", d, dirsep, i);
+ − 1647
PHYSFS_mount(str, NULL, archivesFirst == 0);
+ − 1648
__PHYSFS_smallFree(str);
+ − 1649
} /* if */
+ − 1650
} /* setSaneCfgAddPath */
+ − 1651
+ − 1652
+ − 1653
int PHYSFS_setSaneConfig(const char *organization, const char *appName,
+ − 1654
const char *archiveExt, int includeCdRoms,
+ − 1655
int archivesFirst)
+ − 1656
{
+ − 1657
const char *dirsep = PHYSFS_getDirSeparator();
+ − 1658
const char *basedir;
+ − 1659
const char *prefdir;
+ − 1660
+ − 1661
BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+ − 1662
+ − 1663
prefdir = PHYSFS_getPrefDir(organization, appName);
+ − 1664
BAIL_IF_MACRO(!prefdir, ERRPASS, 0);
+ − 1665
+ − 1666
basedir = PHYSFS_getBaseDir();
+ − 1667
BAIL_IF_MACRO(!basedir, ERRPASS, 0);
+ − 1668
+ − 1669
BAIL_IF_MACRO(!PHYSFS_setWriteDir(prefdir), PHYSFS_ERR_NO_WRITE_DIR, 0);
+ − 1670
+ − 1671
/* Put write dir first in search path... */
+ − 1672
PHYSFS_mount(prefdir, NULL, 0);
+ − 1673
+ − 1674
/* Put base path on search path... */
+ − 1675
PHYSFS_mount(basedir, NULL, 1);
+ − 1676
+ − 1677
/* handle CD-ROMs... */
+ − 1678
if (includeCdRoms)
+ − 1679
{
+ − 1680
char **cds = PHYSFS_getCdRomDirs();
+ − 1681
char **i;
+ − 1682
for (i = cds; *i != NULL; i++)
+ − 1683
PHYSFS_mount(*i, NULL, 1);
+ − 1684
PHYSFS_freeList(cds);
+ − 1685
} /* if */
+ − 1686
+ − 1687
/* Root out archives, and add them to search path... */
+ − 1688
if (archiveExt != NULL)
+ − 1689
{
+ − 1690
char **rc = PHYSFS_enumerateFiles("/");
+ − 1691
char **i;
+ − 1692
size_t extlen = strlen(archiveExt);
+ − 1693
char *ext;
+ − 1694
+ − 1695
for (i = rc; *i != NULL; i++)
+ − 1696
{
+ − 1697
size_t l = strlen(*i);
+ − 1698
if ((l > extlen) && ((*i)[l - extlen - 1] == '.'))
+ − 1699
{
+ − 1700
ext = (*i) + (l - extlen);
+ − 1701
if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0)
+ − 1702
setSaneCfgAddPath(*i, l, dirsep, archivesFirst);
+ − 1703
} /* if */
+ − 1704
} /* for */
+ − 1705
+ − 1706
PHYSFS_freeList(rc);
+ − 1707
} /* if */
+ − 1708
+ − 1709
return 1;
+ − 1710
} /* PHYSFS_setSaneConfig */
+ − 1711
+ − 1712
+ − 1713
void PHYSFS_permitSymbolicLinks(int allow)
+ − 1714
{
+ − 1715
allowSymLinks = allow;
+ − 1716
} /* PHYSFS_permitSymbolicLinks */
+ − 1717
+ − 1718
+ − 1719
int PHYSFS_symbolicLinksPermitted(void)
+ − 1720
{
+ − 1721
return allowSymLinks;
+ − 1722
} /* PHYSFS_symbolicLinksPermitted */
+ − 1723
+ − 1724
+ − 1725
/*
+ − 1726
* Verify that (fname) (in platform-independent notation), in relation
+ − 1727
* to (h) is secure. That means that each element of fname is checked
+ − 1728
* for symlinks (if they aren't permitted). This also allows for quick
+ − 1729
* rejection of files that exist outside an archive's mountpoint.
+ − 1730
*
+ − 1731
* With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs
+ − 1732
* at a time), you should always pass zero for "allowMissing" for efficiency.
+ − 1733
*
+ − 1734
* (fname) must point to an output from sanitizePlatformIndependentPath(),
+ − 1735
* since it will make sure that path names are in the right format for
+ − 1736
* passing certain checks. It will also do checks for "insecure" pathnames
+ − 1737
* like ".." which should be done once instead of once per archive. This also
+ − 1738
* gives us license to treat (fname) as scratch space in this function.
+ − 1739
*
+ − 1740
* Returns non-zero if string is safe, zero if there's a security issue.
+ − 1741
* PHYSFS_getLastError() will specify what was wrong. (*fname) will be
+ − 1742
* updated to point past any mount point elements so it is prepared to
+ − 1743
* be used with the archiver directly.
+ − 1744
*/
+ − 1745
static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
+ − 1746
{
+ − 1747
char *fname = *_fname;
+ − 1748
int retval = 1;
+ − 1749
char *start;
+ − 1750
char *end;
+ − 1751
+ − 1752
if (*fname == '\0') /* quick rejection. */
+ − 1753
return 1;
+ − 1754
+ − 1755
/* !!! FIXME: This codeblock sucks. */
+ − 1756
if (h->mountPoint != NULL) /* NULL mountpoint means "/". */
+ − 1757
{
+ − 1758
size_t mntpntlen = strlen(h->mountPoint);
+ − 1759
size_t len = strlen(fname);
+ − 1760
assert(mntpntlen > 1); /* root mount points should be NULL. */
+ − 1761
/* not under the mountpoint, so skip this archive. */
+ − 1762
BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0);
+ − 1763
/* !!! FIXME: Case insensitive? */
+ − 1764
retval = strncmp(h->mountPoint, fname, mntpntlen-1);
+ − 1765
BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0);
+ − 1766
if (len > mntpntlen-1) /* corner case... */
+ − 1767
BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0);
+ − 1768
fname += mntpntlen-1; /* move to start of actual archive path. */
+ − 1769
if (*fname == '/')
+ − 1770
fname++;
+ − 1771
*_fname = fname; /* skip mountpoint for later use. */
+ − 1772
retval = 1; /* may be reset, below. */
+ − 1773
} /* if */
+ − 1774
+ − 1775
start = fname;
+ − 1776
if (!allowSymLinks)
+ − 1777
{
+ − 1778
while (1)
+ − 1779
{
+ − 1780
PHYSFS_Stat statbuf;
+ − 1781
int rc = 0;
+ − 1782
end = strchr(start, '/');
+ − 1783
+ − 1784
if (end != NULL) *end = '\0';
+ − 1785
rc = h->funcs->stat(h->opaque, fname, &retval, &statbuf);
+ − 1786
if (rc)
+ − 1787
rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
+ − 1788
if (end != NULL) *end = '/';
+ − 1789
+ − 1790
/* insecure path (has a disallowed symlink in it)? */
+ − 1791
BAIL_IF_MACRO(rc, PHYSFS_ERR_SYMLINK_FORBIDDEN, 0);
+ − 1792
+ − 1793
/* break out early if path element is missing. */
+ − 1794
if (!retval)
+ − 1795
{
+ − 1796
/*
+ − 1797
* We need to clear it if it's the last element of the path,
+ − 1798
* since this might be a non-existant file we're opening
+ − 1799
* for writing...
+ − 1800
*/
+ − 1801
if ((end == NULL) || (allowMissing))
+ − 1802
retval = 1;
+ − 1803
break;
+ − 1804
} /* if */
+ − 1805
+ − 1806
if (end == NULL)
+ − 1807
break;
+ − 1808
+ − 1809
start = end + 1;
+ − 1810
} /* while */
+ − 1811
} /* if */
+ − 1812
+ − 1813
return retval;
+ − 1814
} /* verifyPath */
+ − 1815
+ − 1816
+ − 1817
static int doMkdir(const char *_dname, char *dname)
+ − 1818
{
+ − 1819
DirHandle *h;
+ − 1820
char *start;
+ − 1821
char *end;
+ − 1822
int retval = 0;
+ − 1823
int exists = 1; /* force existance check on first path element. */
+ − 1824
+ − 1825
BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), ERRPASS, 0);
+ − 1826
+ − 1827
__PHYSFS_platformGrabMutex(stateLock);
+ − 1828
BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
+ − 1829
h = writeDir;
+ − 1830
BAIL_IF_MACRO_MUTEX(!verifyPath(h, &dname, 1), ERRPASS, stateLock, 0);
+ − 1831
+ − 1832
start = dname;
+ − 1833
while (1)
+ − 1834
{
+ − 1835
end = strchr(start, '/');
+ − 1836
if (end != NULL)
+ − 1837
*end = '\0';
+ − 1838
+ − 1839
/* only check for existance if all parent dirs existed, too... */
+ − 1840
if (exists)
+ − 1841
{
+ − 1842
PHYSFS_Stat statbuf;
+ − 1843
const int rc = h->funcs->stat(h->opaque, dname, &exists, &statbuf);
+ − 1844
retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY));
+ − 1845
} /* if */
+ − 1846
+ − 1847
if (!exists)
+ − 1848
retval = h->funcs->mkdir(h->opaque, dname);
+ − 1849
+ − 1850
if (!retval)
+ − 1851
break;
+ − 1852
+ − 1853
if (end == NULL)
+ − 1854
break;
+ − 1855
+ − 1856
*end = '/';
+ − 1857
start = end + 1;
+ − 1858
} /* while */
+ − 1859
+ − 1860
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1861
return retval;
+ − 1862
} /* doMkdir */
+ − 1863
+ − 1864
+ − 1865
int PHYSFS_mkdir(const char *_dname)
+ − 1866
{
+ − 1867
int retval = 0;
+ − 1868
char *dname;
+ − 1869
size_t len;
+ − 1870
+ − 1871
BAIL_IF_MACRO(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1872
len = strlen(_dname) + 1;
+ − 1873
dname = (char *) __PHYSFS_smallAlloc(len);
+ − 1874
BAIL_IF_MACRO(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 1875
retval = doMkdir(_dname, dname);
+ − 1876
__PHYSFS_smallFree(dname);
+ − 1877
return retval;
+ − 1878
} /* PHYSFS_mkdir */
+ − 1879
+ − 1880
+ − 1881
static int doDelete(const char *_fname, char *fname)
+ − 1882
{
+ − 1883
int retval;
+ − 1884
DirHandle *h;
+ − 1885
BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), ERRPASS, 0);
+ − 1886
+ − 1887
__PHYSFS_platformGrabMutex(stateLock);
+ − 1888
+ − 1889
BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
+ − 1890
h = writeDir;
+ − 1891
BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), ERRPASS, stateLock, 0);
+ − 1892
retval = h->funcs->remove(h->opaque, fname);
+ − 1893
+ − 1894
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1895
return retval;
+ − 1896
} /* doDelete */
+ − 1897
+ − 1898
+ − 1899
int PHYSFS_delete(const char *_fname)
+ − 1900
{
+ − 1901
int retval;
+ − 1902
char *fname;
+ − 1903
size_t len;
+ − 1904
+ − 1905
BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 1906
len = strlen(_fname) + 1;
+ − 1907
fname = (char *) __PHYSFS_smallAlloc(len);
+ − 1908
BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 1909
retval = doDelete(_fname, fname);
+ − 1910
__PHYSFS_smallFree(fname);
+ − 1911
return retval;
+ − 1912
} /* PHYSFS_delete */
+ − 1913
+ − 1914
+ − 1915
const char *PHYSFS_getRealDir(const char *_fname)
+ − 1916
{
+ − 1917
const char *retval = NULL;
+ − 1918
char *fname = NULL;
+ − 1919
size_t len;
+ − 1920
+ − 1921
BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ − 1922
len = strlen(_fname) + 1;
+ − 1923
fname = __PHYSFS_smallAlloc(len);
+ − 1924
BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 1925
if (sanitizePlatformIndependentPath(_fname, fname))
+ − 1926
{
+ − 1927
DirHandle *i;
+ − 1928
__PHYSFS_platformGrabMutex(stateLock);
+ − 1929
for (i = searchPath; i != NULL; i = i->next)
+ − 1930
{
+ − 1931
char *arcfname = fname;
+ − 1932
if (partOfMountPoint(i, arcfname))
+ − 1933
{
+ − 1934
retval = i->dirName;
+ − 1935
break;
+ − 1936
} /* if */
+ − 1937
else if (verifyPath(i, &arcfname, 0))
+ − 1938
{
+ − 1939
PHYSFS_Stat statbuf;
+ − 1940
int exists = 0;
+ − 1941
if (i->funcs->stat(i->opaque, arcfname, &exists, &statbuf))
+ − 1942
{
+ − 1943
if (exists)
+ − 1944
retval = i->dirName;
+ − 1945
break;
+ − 1946
} /* if */
+ − 1947
} /* if */
+ − 1948
} /* for */
+ − 1949
__PHYSFS_platformReleaseMutex(stateLock);
+ − 1950
} /* if */
+ − 1951
+ − 1952
__PHYSFS_smallFree(fname);
+ − 1953
return retval;
+ − 1954
} /* PHYSFS_getRealDir */
+ − 1955
+ − 1956
+ − 1957
static int locateInStringList(const char *str,
+ − 1958
char **list,
+ − 1959
PHYSFS_uint32 *pos)
+ − 1960
{
+ − 1961
PHYSFS_uint32 len = *pos;
+ − 1962
PHYSFS_uint32 half_len;
+ − 1963
PHYSFS_uint32 lo = 0;
+ − 1964
PHYSFS_uint32 middle;
+ − 1965
int cmp;
+ − 1966
+ − 1967
while (len > 0)
+ − 1968
{
+ − 1969
half_len = len >> 1;
+ − 1970
middle = lo + half_len;
+ − 1971
cmp = strcmp(list[middle], str);
+ − 1972
+ − 1973
if (cmp == 0) /* it's in the list already. */
+ − 1974
return 1;
+ − 1975
else if (cmp > 0)
+ − 1976
len = half_len;
+ − 1977
else
+ − 1978
{
+ − 1979
lo = middle + 1;
+ − 1980
len -= half_len + 1;
+ − 1981
} /* else */
+ − 1982
} /* while */
+ − 1983
+ − 1984
*pos = lo;
+ − 1985
return 0;
+ − 1986
} /* locateInStringList */
+ − 1987
+ − 1988
+ − 1989
static void enumFilesCallback(void *data, const char *origdir, const char *str)
+ − 1990
{
+ − 1991
PHYSFS_uint32 pos;
+ − 1992
void *ptr;
+ − 1993
char *newstr;
+ − 1994
EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+ − 1995
+ − 1996
/*
+ − 1997
* See if file is in the list already, and if not, insert it in there
+ − 1998
* alphabetically...
+ − 1999
*/
+ − 2000
pos = pecd->size;
+ − 2001
if (locateInStringList(str, pecd->list, &pos))
+ − 2002
return; /* already in the list. */
+ − 2003
+ − 2004
ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+ − 2005
newstr = (char *) allocator.Malloc(strlen(str) + 1);
+ − 2006
if (ptr != NULL)
+ − 2007
pecd->list = (char **) ptr;
+ − 2008
+ − 2009
if ((ptr == NULL) || (newstr == NULL))
+ − 2010
return; /* better luck next time. */
+ − 2011
+ − 2012
strcpy(newstr, str);
+ − 2013
+ − 2014
if (pos != pecd->size)
+ − 2015
{
+ − 2016
memmove(&pecd->list[pos+1], &pecd->list[pos],
+ − 2017
sizeof (char *) * ((pecd->size) - pos));
+ − 2018
} /* if */
+ − 2019
+ − 2020
pecd->list[pos] = newstr;
+ − 2021
pecd->size++;
+ − 2022
} /* enumFilesCallback */
+ − 2023
+ − 2024
+ − 2025
char **PHYSFS_enumerateFiles(const char *path)
+ − 2026
{
+ − 2027
EnumStringListCallbackData ecd;
+ − 2028
memset(&ecd, '\0', sizeof (ecd));
+ − 2029
ecd.list = (char **) allocator.Malloc(sizeof (char *));
+ − 2030
BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 2031
PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd);
+ − 2032
ecd.list[ecd.size] = NULL;
+ − 2033
return ecd.list;
+ − 2034
} /* PHYSFS_enumerateFiles */
+ − 2035
+ − 2036
+ − 2037
/*
+ − 2038
* Broke out to seperate function so we can use stack allocation gratuitously.
+ − 2039
*/
+ − 2040
static void enumerateFromMountPoint(DirHandle *i, const char *arcfname,
+ − 2041
PHYSFS_EnumFilesCallback callback,
+ − 2042
const char *_fname, void *data)
+ − 2043
{
+ − 2044
const size_t len = strlen(arcfname);
+ − 2045
char *ptr = NULL;
+ − 2046
char *end = NULL;
+ − 2047
const size_t slen = strlen(i->mountPoint) + 1;
+ − 2048
char *mountPoint = (char *) __PHYSFS_smallAlloc(slen);
+ − 2049
+ − 2050
if (mountPoint == NULL)
+ − 2051
return; /* oh well. */
+ − 2052
+ − 2053
strcpy(mountPoint, i->mountPoint);
+ − 2054
ptr = mountPoint + ((len) ? len + 1 : 0);
+ − 2055
end = strchr(ptr, '/');
+ − 2056
assert(end); /* should always find a terminating '/'. */
+ − 2057
*end = '\0';
+ − 2058
callback(data, _fname, ptr);
+ − 2059
__PHYSFS_smallFree(mountPoint);
+ − 2060
} /* enumerateFromMountPoint */
+ − 2061
+ − 2062
+ − 2063
/* !!! FIXME: this should report error conditions. */
+ − 2064
void PHYSFS_enumerateFilesCallback(const char *_fname,
+ − 2065
PHYSFS_EnumFilesCallback callback,
+ − 2066
void *data)
+ − 2067
{
+ − 2068
size_t len;
+ − 2069
char *fname;
+ − 2070
+ − 2071
BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
+ − 2072
BAIL_IF_MACRO(!callback, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
+ − 2073
+ − 2074
len = strlen(_fname) + 1;
+ − 2075
fname = (char *) __PHYSFS_smallAlloc(len);
+ − 2076
BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/;
+ − 2077
+ − 2078
if (sanitizePlatformIndependentPath(_fname, fname))
+ − 2079
{
+ − 2080
DirHandle *i;
+ − 2081
int noSyms;
+ − 2082
+ − 2083
__PHYSFS_platformGrabMutex(stateLock);
+ − 2084
noSyms = !allowSymLinks;
+ − 2085
for (i = searchPath; i != NULL; i = i->next)
+ − 2086
{
+ − 2087
char *arcfname = fname;
+ − 2088
if (partOfMountPoint(i, arcfname))
+ − 2089
enumerateFromMountPoint(i, arcfname, callback, _fname, data);
+ − 2090
+ − 2091
else if (verifyPath(i, &arcfname, 0))
+ − 2092
{
+ − 2093
i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
+ − 2094
callback, _fname, data);
+ − 2095
} /* else if */
+ − 2096
} /* for */
+ − 2097
__PHYSFS_platformReleaseMutex(stateLock);
+ − 2098
} /* if */
+ − 2099
+ − 2100
__PHYSFS_smallFree(fname);
+ − 2101
} /* PHYSFS_enumerateFilesCallback */
+ − 2102
+ − 2103
+ − 2104
int PHYSFS_exists(const char *fname)
+ − 2105
{
+ − 2106
return (PHYSFS_getRealDir(fname) != NULL);
+ − 2107
} /* PHYSFS_exists */
+ − 2108
+ − 2109
+ − 2110
PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname)
+ − 2111
{
+ − 2112
PHYSFS_Stat statbuf;
+ − 2113
BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, -1);
+ − 2114
return statbuf.modtime;
+ − 2115
} /* PHYSFS_getLastModTime */
+ − 2116
+ − 2117
+ − 2118
int PHYSFS_isDirectory(const char *fname)
+ − 2119
{
+ − 2120
PHYSFS_Stat statbuf;
+ − 2121
BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
+ − 2122
return (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
+ − 2123
} /* PHYSFS_isDirectory */
+ − 2124
+ − 2125
+ − 2126
int PHYSFS_isSymbolicLink(const char *fname)
+ − 2127
{
+ − 2128
PHYSFS_Stat statbuf;
+ − 2129
BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
+ − 2130
return (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
+ − 2131
} /* PHYSFS_isSymbolicLink */
+ − 2132
+ − 2133
+ − 2134
static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
+ − 2135
{
+ − 2136
FileHandle *fh = NULL;
+ − 2137
size_t len;
+ − 2138
char *fname;
+ − 2139
+ − 2140
BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 2141
len = strlen(_fname) + 1;
+ − 2142
fname = (char *) __PHYSFS_smallAlloc(len);
+ − 2143
BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 2144
+ − 2145
if (sanitizePlatformIndependentPath(_fname, fname))
+ − 2146
{
+ − 2147
PHYSFS_Io *io = NULL;
+ − 2148
DirHandle *h = NULL;
+ − 2149
const PHYSFS_Archiver *f;
+ − 2150
+ − 2151
__PHYSFS_platformGrabMutex(stateLock);
+ − 2152
+ − 2153
GOTO_IF_MACRO(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd);
+ − 2154
+ − 2155
h = writeDir;
+ − 2156
GOTO_IF_MACRO(!verifyPath(h, &fname, 0), ERRPASS, doOpenWriteEnd);
+ − 2157
+ − 2158
f = h->funcs;
+ − 2159
if (appending)
+ − 2160
io = f->openAppend(h->opaque, fname);
+ − 2161
else
+ − 2162
io = f->openWrite(h->opaque, fname);
+ − 2163
+ − 2164
GOTO_IF_MACRO(!io, ERRPASS, doOpenWriteEnd);
+ − 2165
+ − 2166
fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+ − 2167
if (fh == NULL)
+ − 2168
{
+ − 2169
io->destroy(io);
+ − 2170
GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd);
+ − 2171
} /* if */
+ − 2172
else
+ − 2173
{
+ − 2174
memset(fh, '\0', sizeof (FileHandle));
+ − 2175
fh->io = io;
+ − 2176
fh->dirHandle = h;
+ − 2177
fh->next = openWriteList;
+ − 2178
openWriteList = fh;
+ − 2179
} /* else */
+ − 2180
+ − 2181
doOpenWriteEnd:
+ − 2182
__PHYSFS_platformReleaseMutex(stateLock);
+ − 2183
} /* if */
+ − 2184
+ − 2185
__PHYSFS_smallFree(fname);
+ − 2186
return ((PHYSFS_File *) fh);
+ − 2187
} /* doOpenWrite */
+ − 2188
+ − 2189
+ − 2190
PHYSFS_File *PHYSFS_openWrite(const char *filename)
+ − 2191
{
+ − 2192
return doOpenWrite(filename, 0);
+ − 2193
} /* PHYSFS_openWrite */
+ − 2194
+ − 2195
+ − 2196
PHYSFS_File *PHYSFS_openAppend(const char *filename)
+ − 2197
{
+ − 2198
return doOpenWrite(filename, 1);
+ − 2199
} /* PHYSFS_openAppend */
+ − 2200
+ − 2201
+ − 2202
PHYSFS_File *PHYSFS_openRead(const char *_fname)
+ − 2203
{
+ − 2204
FileHandle *fh = NULL;
+ − 2205
char *fname;
+ − 2206
size_t len;
+ − 2207
+ − 2208
BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 2209
len = strlen(_fname) + 1;
+ − 2210
fname = (char *) __PHYSFS_smallAlloc(len);
+ − 2211
BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 2212
+ − 2213
if (sanitizePlatformIndependentPath(_fname, fname))
+ − 2214
{
+ − 2215
int fileExists = 0;
+ − 2216
DirHandle *i = NULL;
+ − 2217
PHYSFS_Io *io = NULL;
+ − 2218
+ − 2219
__PHYSFS_platformGrabMutex(stateLock);
+ − 2220
+ − 2221
GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd);
+ − 2222
+ − 2223
for (i = searchPath; (i != NULL) && (!fileExists); i = i->next)
+ − 2224
{
+ − 2225
char *arcfname = fname;
+ − 2226
if (verifyPath(i, &arcfname, 0))
+ − 2227
{
+ − 2228
io = i->funcs->openRead(i->opaque, arcfname, &fileExists);
+ − 2229
if (io)
+ − 2230
break;
+ − 2231
} /* if */
+ − 2232
} /* for */
+ − 2233
+ − 2234
GOTO_IF_MACRO(!io, ERRPASS, openReadEnd);
+ − 2235
+ − 2236
fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+ − 2237
if (fh == NULL)
+ − 2238
{
+ − 2239
io->destroy(io);
+ − 2240
GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd);
+ − 2241
} /* if */
+ − 2242
+ − 2243
memset(fh, '\0', sizeof (FileHandle));
+ − 2244
fh->io = io;
+ − 2245
fh->forReading = 1;
+ − 2246
fh->dirHandle = i;
+ − 2247
fh->next = openReadList;
+ − 2248
openReadList = fh;
+ − 2249
+ − 2250
openReadEnd:
+ − 2251
__PHYSFS_platformReleaseMutex(stateLock);
+ − 2252
} /* if */
+ − 2253
+ − 2254
__PHYSFS_smallFree(fname);
+ − 2255
return ((PHYSFS_File *) fh);
+ − 2256
} /* PHYSFS_openRead */
+ − 2257
+ − 2258
+ − 2259
static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
+ − 2260
{
+ − 2261
FileHandle *prev = NULL;
+ − 2262
FileHandle *i;
+ − 2263
int rc = 1;
+ − 2264
+ − 2265
for (i = *list; i != NULL; i = i->next)
+ − 2266
{
+ − 2267
if (i == handle) /* handle is in this list? */
+ − 2268
{
+ − 2269
PHYSFS_Io *io = handle->io;
+ − 2270
PHYSFS_uint8 *tmp = handle->buffer;
+ − 2271
rc = PHYSFS_flush((PHYSFS_File *) handle);
+ − 2272
if (!rc)
+ − 2273
return -1;
+ − 2274
io->destroy(io);
+ − 2275
+ − 2276
if (tmp != NULL) /* free any associated buffer. */
+ − 2277
allocator.Free(tmp);
+ − 2278
+ − 2279
if (prev == NULL)
+ − 2280
*list = handle->next;
+ − 2281
else
+ − 2282
prev->next = handle->next;
+ − 2283
+ − 2284
allocator.Free(handle);
+ − 2285
return 1;
+ − 2286
} /* if */
+ − 2287
prev = i;
+ − 2288
} /* for */
+ − 2289
+ − 2290
return 0;
+ − 2291
} /* closeHandleInOpenList */
+ − 2292
+ − 2293
+ − 2294
int PHYSFS_close(PHYSFS_File *_handle)
+ − 2295
{
+ − 2296
FileHandle *handle = (FileHandle *) _handle;
+ − 2297
int rc;
+ − 2298
+ − 2299
__PHYSFS_platformGrabMutex(stateLock);
+ − 2300
+ − 2301
/* -1 == close failure. 0 == not found. 1 == success. */
+ − 2302
rc = closeHandleInOpenList(&openReadList, handle);
+ − 2303
BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
+ − 2304
if (!rc)
+ − 2305
{
+ − 2306
rc = closeHandleInOpenList(&openWriteList, handle);
+ − 2307
BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
+ − 2308
} /* if */
+ − 2309
+ − 2310
__PHYSFS_platformReleaseMutex(stateLock);
+ − 2311
BAIL_IF_MACRO(!rc, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 2312
return 1;
+ − 2313
} /* PHYSFS_close */
+ − 2314
+ − 2315
+ − 2316
static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
+ − 2317
PHYSFS_uint64 len)
+ − 2318
{
+ − 2319
PHYSFS_Io *io = NULL;
+ − 2320
PHYSFS_sint64 retval = 0;
+ − 2321
PHYSFS_uint32 buffered = 0;
+ − 2322
PHYSFS_sint64 rc = 0;
+ − 2323
+ − 2324
if (len == 0)
+ − 2325
return 0;
+ − 2326
+ − 2327
buffered = fh->buffill - fh->bufpos;
+ − 2328
if (buffered >= len) /* totally in the buffer, just copy and return! */
+ − 2329
{
+ − 2330
memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len);
+ − 2331
fh->bufpos += (PHYSFS_uint32) len;
+ − 2332
return (PHYSFS_sint64) len;
+ − 2333
} /* else if */
+ − 2334
+ − 2335
if (buffered > 0) /* partially in the buffer... */
+ − 2336
{
+ − 2337
memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered);
+ − 2338
buffer = ((PHYSFS_uint8 *) buffer) + buffered;
+ − 2339
len -= buffered;
+ − 2340
retval = buffered;
+ − 2341
fh->buffill = fh->bufpos = 0;
+ − 2342
} /* if */
+ − 2343
+ − 2344
/* if you got here, the buffer is drained and we still need bytes. */
+ − 2345
assert(len > 0);
+ − 2346
+ − 2347
io = fh->io;
+ − 2348
if (len >= fh->bufsize) /* need more than the buffer takes. */
+ − 2349
{
+ − 2350
/* leave buffer empty, go right to output instead. */
+ − 2351
rc = io->read(io, buffer, len);
+ − 2352
if (rc < 0)
+ − 2353
return ((retval == 0) ? rc : retval);
+ − 2354
return retval + rc;
+ − 2355
} /* if */
+ − 2356
+ − 2357
/* need less than buffer can take. Fill buffer. */
+ − 2358
rc = io->read(io, fh->buffer, fh->bufsize);
+ − 2359
if (rc < 0)
+ − 2360
return ((retval == 0) ? rc : retval);
+ − 2361
+ − 2362
assert(fh->bufpos == 0);
+ − 2363
fh->buffill = (PHYSFS_uint32) rc;
+ − 2364
rc = doBufferedRead(fh, buffer, len); /* go from the start, again. */
+ − 2365
if (rc < 0)
+ − 2366
return ((retval == 0) ? rc : retval);
+ − 2367
+ − 2368
return retval + rc;
+ − 2369
} /* doBufferedRead */
+ − 2370
+ − 2371
+ − 2372
PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer,
+ − 2373
PHYSFS_uint32 size, PHYSFS_uint32 count)
+ − 2374
{
+ − 2375
const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
+ − 2376
const PHYSFS_sint64 retval = PHYSFS_readBytes(handle, buffer, len);
+ − 2377
return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
+ − 2378
} /* PHYSFS_read */
+ − 2379
+ − 2380
+ − 2381
PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
+ − 2382
PHYSFS_uint64 len)
+ − 2383
{
+ − 2384
FileHandle *fh = (FileHandle *) handle;
+ − 2385
+ − 2386
#ifdef PHYSFS_NO_64BIT_SUPPORT
+ − 2387
const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
+ − 2388
#else
+ − 2389
const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
+ − 2390
#endif
+ − 2391
+ − 2392
if (!__PHYSFS_ui64FitsAddressSpace(len))
+ − 2393
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ − 2394
+ − 2395
BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ − 2396
BAIL_IF_MACRO(!fh->forReading, PHYSFS_ERR_OPEN_FOR_WRITING, -1);
+ − 2397
BAIL_IF_MACRO(len == 0, ERRPASS, 0);
+ − 2398
if (fh->buffer)
+ − 2399
return doBufferedRead(fh, buffer, len);
+ − 2400
+ − 2401
return fh->io->read(fh->io, buffer, len);
+ − 2402
} /* PHYSFS_readBytes */
+ − 2403
+ − 2404
+ − 2405
static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer,
+ − 2406
PHYSFS_uint64 len)
+ − 2407
{
+ − 2408
FileHandle *fh = (FileHandle *) handle;
+ − 2409
+ − 2410
/* whole thing fits in the buffer? */
+ − 2411
if ( (((PHYSFS_uint64) fh->buffill) + len) < fh->bufsize )
+ − 2412
{
+ − 2413
memcpy(fh->buffer + fh->buffill, buffer, (size_t) len);
+ − 2414
fh->buffill += (PHYSFS_uint32) len;
+ − 2415
return (PHYSFS_sint64) len;
+ − 2416
} /* if */
+ − 2417
+ − 2418
/* would overflow buffer. Flush and then write the new objects, too. */
+ − 2419
BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, -1);
+ − 2420
return fh->io->write(fh->io, buffer, len);
+ − 2421
} /* doBufferedWrite */
+ − 2422
+ − 2423
+ − 2424
PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer,
+ − 2425
PHYSFS_uint32 size, PHYSFS_uint32 count)
+ − 2426
{
+ − 2427
const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
+ − 2428
const PHYSFS_sint64 retval = PHYSFS_writeBytes(handle, buffer, len);
+ − 2429
return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
+ − 2430
} /* PHYSFS_write */
+ − 2431
+ − 2432
+ − 2433
PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer,
+ − 2434
PHYSFS_uint64 len)
+ − 2435
{
+ − 2436
FileHandle *fh = (FileHandle *) handle;
+ − 2437
+ − 2438
#ifdef PHYSFS_NO_64BIT_SUPPORT
+ − 2439
const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
+ − 2440
#else
+ − 2441
const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
+ − 2442
#endif
+ − 2443
+ − 2444
if (!__PHYSFS_ui64FitsAddressSpace(len))
+ − 2445
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ − 2446
+ − 2447
BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ − 2448
BAIL_IF_MACRO(fh->forReading, PHYSFS_ERR_OPEN_FOR_READING, -1);
+ − 2449
BAIL_IF_MACRO(len == 0, ERRPASS, 0);
+ − 2450
if (fh->buffer)
+ − 2451
return doBufferedWrite(handle, buffer, len);
+ − 2452
+ − 2453
return fh->io->write(fh->io, buffer, len);
+ − 2454
} /* PHYSFS_write */
+ − 2455
+ − 2456
+ − 2457
int PHYSFS_eof(PHYSFS_File *handle)
+ − 2458
{
+ − 2459
FileHandle *fh = (FileHandle *) handle;
+ − 2460
+ − 2461
if (!fh->forReading) /* never EOF on files opened for write/append. */
+ − 2462
return 0;
+ − 2463
+ − 2464
/* can't be eof if buffer isn't empty */
+ − 2465
if (fh->bufpos == fh->buffill)
+ − 2466
{
+ − 2467
/* check the Io. */
+ − 2468
PHYSFS_Io *io = fh->io;
+ − 2469
const PHYSFS_sint64 pos = io->tell(io);
+ − 2470
const PHYSFS_sint64 len = io->length(io);
+ − 2471
if ((pos < 0) || (len < 0))
+ − 2472
return 0; /* beats me. */
+ − 2473
return (pos >= len);
+ − 2474
} /* if */
+ − 2475
+ − 2476
return 0;
+ − 2477
} /* PHYSFS_eof */
+ − 2478
+ − 2479
+ − 2480
PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+ − 2481
{
+ − 2482
FileHandle *fh = (FileHandle *) handle;
+ − 2483
const PHYSFS_sint64 pos = fh->io->tell(fh->io);
+ − 2484
const PHYSFS_sint64 retval = fh->forReading ?
+ − 2485
(pos - fh->buffill) + fh->bufpos :
+ − 2486
(pos + fh->buffill);
+ − 2487
return retval;
+ − 2488
} /* PHYSFS_tell */
+ − 2489
+ − 2490
+ − 2491
int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+ − 2492
{
+ − 2493
FileHandle *fh = (FileHandle *) handle;
+ − 2494
BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
+ − 2495
+ − 2496
if (fh->buffer && fh->forReading)
+ − 2497
{
+ − 2498
/* avoid throwing away our precious buffer if seeking within it. */
+ − 2499
PHYSFS_sint64 offset = pos - PHYSFS_tell(handle);
+ − 2500
if ( /* seeking within the already-buffered range? */
+ − 2501
((offset >= 0) && (offset <= fh->buffill - fh->bufpos)) /* fwd */
+ − 2502
|| ((offset < 0) && (-offset <= fh->bufpos)) /* backward */ )
+ − 2503
{
+ − 2504
fh->bufpos += (PHYSFS_uint32) offset;
+ − 2505
return 1; /* successful seek */
+ − 2506
} /* if */
+ − 2507
} /* if */
+ − 2508
+ − 2509
/* we have to fall back to a 'raw' seek. */
+ − 2510
fh->buffill = fh->bufpos = 0;
+ − 2511
return fh->io->seek(fh->io, pos);
+ − 2512
} /* PHYSFS_seek */
+ − 2513
+ − 2514
+ − 2515
PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+ − 2516
{
+ − 2517
PHYSFS_Io *io = ((FileHandle *) handle)->io;
+ − 2518
return io->length(io);
+ − 2519
} /* PHYSFS_filelength */
+ − 2520
+ − 2521
+ − 2522
int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
+ − 2523
{
+ − 2524
FileHandle *fh = (FileHandle *) handle;
+ − 2525
PHYSFS_uint32 bufsize;
+ − 2526
+ − 2527
/* !!! FIXME: actually, why use 32 bits here? */
+ − 2528
/*BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, "buffer must fit in 32-bits", 0);*/
+ − 2529
BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ − 2530
bufsize = (PHYSFS_uint32) _bufsize;
+ − 2531
+ − 2532
BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
+ − 2533
+ − 2534
/*
+ − 2535
* For reads, we need to move the file pointer to where it would be
+ − 2536
* if we weren't buffering, so that the next read will get the
+ − 2537
* right chunk of stuff from the file. PHYSFS_flush() handles writes.
+ − 2538
*/
+ − 2539
if ((fh->forReading) && (fh->buffill != fh->bufpos))
+ − 2540
{
+ − 2541
PHYSFS_uint64 pos;
+ − 2542
const PHYSFS_sint64 curpos = fh->io->tell(fh->io);
+ − 2543
BAIL_IF_MACRO(curpos == -1, ERRPASS, 0);
+ − 2544
pos = ((curpos - fh->buffill) + fh->bufpos);
+ − 2545
BAIL_IF_MACRO(!fh->io->seek(fh->io, pos), ERRPASS, 0);
+ − 2546
} /* if */
+ − 2547
+ − 2548
if (bufsize == 0) /* delete existing buffer. */
+ − 2549
{
+ − 2550
if (fh->buffer)
+ − 2551
{
+ − 2552
allocator.Free(fh->buffer);
+ − 2553
fh->buffer = NULL;
+ − 2554
} /* if */
+ − 2555
} /* if */
+ − 2556
+ − 2557
else
+ − 2558
{
+ − 2559
PHYSFS_uint8 *newbuf;
+ − 2560
newbuf = (PHYSFS_uint8 *) allocator.Realloc(fh->buffer, bufsize);
+ − 2561
BAIL_IF_MACRO(!newbuf, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ − 2562
fh->buffer = newbuf;
+ − 2563
} /* else */
+ − 2564
+ − 2565
fh->bufsize = bufsize;
+ − 2566
fh->buffill = fh->bufpos = 0;
+ − 2567
return 1;
+ − 2568
} /* PHYSFS_setBuffer */
+ − 2569
+ − 2570
+ − 2571
int PHYSFS_flush(PHYSFS_File *handle)
+ − 2572
{
+ − 2573
FileHandle *fh = (FileHandle *) handle;
+ − 2574
PHYSFS_Io *io;
+ − 2575
PHYSFS_sint64 rc;
+ − 2576
+ − 2577
if ((fh->forReading) || (fh->bufpos == fh->buffill))
+ − 2578
return 1; /* open for read or buffer empty are successful no-ops. */
+ − 2579
+ − 2580
/* dump buffer to disk. */
+ − 2581
io = fh->io;
+ − 2582
rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
+ − 2583
BAIL_IF_MACRO(rc <= 0, ERRPASS, 0);
+ − 2584
fh->bufpos = fh->buffill = 0;
+ − 2585
return io->flush(io);
+ − 2586
} /* PHYSFS_flush */
+ − 2587
+ − 2588
+ − 2589
int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
+ − 2590
{
+ − 2591
int retval = 0;
+ − 2592
char *fname;
+ − 2593
size_t len;
+ − 2594
+ − 2595
BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ − 2596
BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ − 2597
len = strlen(_fname) + 1;
+ − 2598
fname = (char *) __PHYSFS_smallAlloc(len);
+ − 2599
BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, -1);
+ − 2600
+ − 2601
/* set some sane defaults... */
+ − 2602
stat->filesize = -1;
+ − 2603
stat->modtime = -1;
+ − 2604
stat->createtime = -1;
+ − 2605
stat->accesstime = -1;
+ − 2606
stat->filetype = PHYSFS_FILETYPE_OTHER;
+ − 2607
stat->readonly = 1; /* !!! FIXME */
+ − 2608
+ − 2609
if (sanitizePlatformIndependentPath(_fname, fname))
+ − 2610
{
+ − 2611
if (*fname == '\0')
+ − 2612
{
+ − 2613
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ − 2614
stat->readonly = !writeDir; /* Writeable if we have a writeDir */
+ − 2615
retval = 1;
+ − 2616
} /* if */
+ − 2617
else
+ − 2618
{
+ − 2619
DirHandle *i;
+ − 2620
int exists = 0;
+ − 2621
__PHYSFS_platformGrabMutex(stateLock);
+ − 2622
for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+ − 2623
{
+ − 2624
char *arcfname = fname;
+ − 2625
exists = partOfMountPoint(i, arcfname);
+ − 2626
if (exists)
+ − 2627
{
+ − 2628
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ − 2629
stat->readonly = 1; /* !!! FIXME */
+ − 2630
retval = 1;
+ − 2631
} /* if */
+ − 2632
else if (verifyPath(i, &arcfname, 0))
+ − 2633
{
+ − 2634
/* !!! FIXME: this test is wrong and should be elsewhere. */
+ − 2635
stat->readonly = !(writeDir &&
+ − 2636
(strcmp(writeDir->dirName, i->dirName) == 0));
+ − 2637
retval = i->funcs->stat(i->opaque, arcfname, &exists, stat);
+ − 2638
} /* else if */
+ − 2639
} /* for */
+ − 2640
__PHYSFS_platformReleaseMutex(stateLock);
+ − 2641
} /* else */
+ − 2642
} /* if */
+ − 2643
+ − 2644
__PHYSFS_smallFree(fname);
+ − 2645
return retval;
+ − 2646
} /* PHYSFS_stat */
+ − 2647
+ − 2648
+ − 2649
int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
+ − 2650
{
+ − 2651
return (io->read(io, buf, len) == len);
+ − 2652
} /* __PHYSFS_readAll */
+ − 2653
+ − 2654
+ − 2655
void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len)
+ − 2656
{
+ − 2657
void *useHeap = ((ptr == NULL) ? ((void *) 1) : ((void *) 0));
+ − 2658
if (useHeap) /* too large for stack allocation or alloca() failed. */
+ − 2659
ptr = allocator.Malloc(len+sizeof (void *));
+ − 2660
+ − 2661
if (ptr != NULL)
+ − 2662
{
+ − 2663
void **retval = (void **) ptr;
+ − 2664
/*printf("%s alloc'd (%d) bytes at (%p).\n",
+ − 2665
useHeap ? "heap" : "stack", (int) len, ptr);*/
+ − 2666
*retval = useHeap;
+ − 2667
return retval + 1;
+ − 2668
} /* if */
+ − 2669
+ − 2670
return NULL; /* allocation failed. */
+ − 2671
} /* __PHYSFS_initSmallAlloc */
+ − 2672
+ − 2673
+ − 2674
void __PHYSFS_smallFree(void *ptr)
+ − 2675
{
+ − 2676
if (ptr != NULL)
+ − 2677
{
+ − 2678
void **block = ((void **) ptr) - 1;
+ − 2679
const int useHeap = (*block != 0);
+ − 2680
if (useHeap)
+ − 2681
allocator.Free(block);
+ − 2682
/*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/
+ − 2683
} /* if */
+ − 2684
} /* __PHYSFS_smallFree */
+ − 2685
+ − 2686
+ − 2687
int PHYSFS_setAllocator(const PHYSFS_Allocator *a)
+ − 2688
{
+ − 2689
BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
+ − 2690
externalAllocator = (a != NULL);
+ − 2691
if (externalAllocator)
+ − 2692
memcpy(&allocator, a, sizeof (PHYSFS_Allocator));
+ − 2693
+ − 2694
return 1;
+ − 2695
} /* PHYSFS_setAllocator */
+ − 2696
+ − 2697
+ − 2698
const PHYSFS_Allocator *PHYSFS_getAllocator(void)
+ − 2699
{
+ − 2700
BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
+ − 2701
return &allocator;
+ − 2702
} /* PHYSFS_getAllocator */
+ − 2703
+ − 2704
+ − 2705
static void *mallocAllocatorMalloc(PHYSFS_uint64 s)
+ − 2706
{
+ − 2707
if (!__PHYSFS_ui64FitsAddressSpace(s))
+ − 2708
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 2709
#undef malloc
+ − 2710
return malloc((size_t) s);
+ − 2711
} /* mallocAllocatorMalloc */
+ − 2712
+ − 2713
+ − 2714
static void *mallocAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+ − 2715
{
+ − 2716
if (!__PHYSFS_ui64FitsAddressSpace(s))
+ − 2717
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ − 2718
#undef realloc
+ − 2719
return realloc(ptr, (size_t) s);
+ − 2720
} /* mallocAllocatorRealloc */
+ − 2721
+ − 2722
+ − 2723
static void mallocAllocatorFree(void *ptr)
+ − 2724
{
+ − 2725
#undef free
+ − 2726
free(ptr);
+ − 2727
} /* mallocAllocatorFree */
+ − 2728
+ − 2729
+ − 2730
static void setDefaultAllocator(void)
+ − 2731
{
+ − 2732
assert(!externalAllocator);
+ − 2733
if (!__PHYSFS_platformSetDefaultAllocator(&allocator))
+ − 2734
{
+ − 2735
allocator.Init = NULL;
+ − 2736
allocator.Deinit = NULL;
+ − 2737
allocator.Malloc = mallocAllocatorMalloc;
+ − 2738
allocator.Realloc = mallocAllocatorRealloc;
+ − 2739
allocator.Free = mallocAllocatorFree;
+ − 2740
} /* if */
+ − 2741
} /* setDefaultAllocator */
+ − 2742
+ − 2743
/* end of physfs.c ... */
+ − 2744