physfs.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  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 in the source's root directory.
  7. *
  8. * This file written by Ryan C. Gordon.
  9. */
  10. #if HAVE_CONFIG_H
  11. # include <config.h>
  12. #endif
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <fcntl.h>
  17. #include <errno.h>
  18. #include <assert.h>
  19. #include "physfs.h"
  20. #define __PHYSICSFS_INTERNAL__
  21. #include "physfs_internal.h"
  22. typedef struct __PHYSFS_ERRMSGTYPE__
  23. {
  24. PHYSFS_uint64 tid;
  25. int errorAvailable;
  26. char errorString[80];
  27. struct __PHYSFS_ERRMSGTYPE__ *next;
  28. } ErrMsg;
  29. typedef struct __PHYSFS_DIRINFO__
  30. {
  31. char *dirName;
  32. DirHandle *dirHandle;
  33. struct __PHYSFS_DIRINFO__ *next;
  34. } PhysDirInfo;
  35. typedef struct __PHYSFS_FILEHANDLELIST__
  36. {
  37. PHYSFS_file handle;
  38. struct __PHYSFS_FILEHANDLELIST__ *next;
  39. } FileHandleList;
  40. /* The various i/o drivers... */
  41. #if (defined PHYSFS_SUPPORTS_ZIP)
  42. extern const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP;
  43. extern const DirFunctions __PHYSFS_DirFunctions_ZIP;
  44. #endif
  45. #if (defined PHYSFS_SUPPORTS_GRP)
  46. extern const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP;
  47. extern const DirFunctions __PHYSFS_DirFunctions_GRP;
  48. #endif
  49. #if (defined PHYSFS_SUPPORTS_QPAK)
  50. extern const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_QPAK;
  51. extern const DirFunctions __PHYSFS_DirFunctions_QPAK;
  52. #endif
  53. extern const DirFunctions __PHYSFS_DirFunctions_DIR;
  54. // !!! FIXME: This is stored with dirFunctions now, too.
  55. static const PHYSFS_ArchiveInfo *supported_types[] =
  56. {
  57. #if (defined PHYSFS_SUPPORTS_ZIP)
  58. &__PHYSFS_ArchiveInfo_ZIP,
  59. #endif
  60. #if (defined PHYSFS_SUPPORTS_GRP)
  61. &__PHYSFS_ArchiveInfo_GRP,
  62. #endif
  63. #if (defined PHYSFS_SUPPORTS_QPAK)
  64. &__PHYSFS_ArchiveInfo_QPAK,
  65. #endif
  66. NULL
  67. };
  68. static const DirFunctions *dirFunctions[] =
  69. {
  70. #if (defined PHYSFS_SUPPORTS_ZIP)
  71. &__PHYSFS_DirFunctions_ZIP,
  72. #endif
  73. #if (defined PHYSFS_SUPPORTS_GRP)
  74. &__PHYSFS_DirFunctions_GRP,
  75. #endif
  76. #if (defined PHYSFS_SUPPORTS_QPAK)
  77. &__PHYSFS_DirFunctions_QPAK,
  78. #endif
  79. &__PHYSFS_DirFunctions_DIR,
  80. NULL
  81. };
  82. /* General PhysicsFS state ... */
  83. static int initialized = 0;
  84. static ErrMsg *errorMessages = NULL;
  85. static PhysDirInfo *searchPath = NULL;
  86. static PhysDirInfo *writeDir = NULL;
  87. static FileHandleList *openWriteList = NULL;
  88. static FileHandleList *openReadList = NULL;
  89. static char *baseDir = NULL;
  90. static char *userDir = NULL;
  91. static int allowSymLinks = 0;
  92. /* mutexes ... */
  93. static void *errorLock = NULL; /* protects error message list. */
  94. static void *stateLock = NULL; /* protects other PhysFS static state. */
  95. /* functions ... */
  96. static ErrMsg *findErrorForCurrentThread(void)
  97. {
  98. ErrMsg *i;
  99. PHYSFS_uint64 tid;
  100. if (errorLock != NULL)
  101. __PHYSFS_platformGrabMutex(errorLock);
  102. if (errorMessages != NULL)
  103. {
  104. tid = __PHYSFS_platformGetThreadID();
  105. for (i = errorMessages; i != NULL; i = i->next)
  106. {
  107. if (i->tid == tid)
  108. {
  109. if (errorLock != NULL)
  110. __PHYSFS_platformReleaseMutex(errorLock);
  111. return(i);
  112. } /* if */
  113. } /* for */
  114. } /* if */
  115. if (errorLock != NULL)
  116. __PHYSFS_platformReleaseMutex(errorLock);
  117. return(NULL); /* no error available. */
  118. } /* findErrorForCurrentThread */
  119. void __PHYSFS_setError(const char *str)
  120. {
  121. ErrMsg *err;
  122. if (str == NULL)
  123. return;
  124. err = findErrorForCurrentThread();
  125. if (err == NULL)
  126. {
  127. err = (ErrMsg *) malloc(sizeof (ErrMsg));
  128. if (err == NULL)
  129. return; /* uhh...? */
  130. memset((void *) err, '\0', sizeof (ErrMsg));
  131. err->tid = __PHYSFS_platformGetThreadID();
  132. if (errorLock != NULL)
  133. __PHYSFS_platformGrabMutex(errorLock);
  134. err->next = errorMessages;
  135. errorMessages = err;
  136. if (errorLock != NULL)
  137. __PHYSFS_platformReleaseMutex(errorLock);
  138. } /* if */
  139. err->errorAvailable = 1;
  140. strncpy(err->errorString, str, sizeof (err->errorString));
  141. err->errorString[sizeof (err->errorString) - 1] = '\0';
  142. } /* __PHYSFS_setError */
  143. const char *PHYSFS_getLastError(void)
  144. {
  145. ErrMsg *err = findErrorForCurrentThread();
  146. if ((err == NULL) || (!err->errorAvailable))
  147. return(NULL);
  148. err->errorAvailable = 0;
  149. return(err->errorString);
  150. } /* PHYSFS_getLastError */
  151. /* MAKE SURE that errorLock is held before calling this! */
  152. static void freeErrorMessages(void)
  153. {
  154. ErrMsg *i;
  155. ErrMsg *next;
  156. for (i = errorMessages; i != NULL; i = next)
  157. {
  158. next = i->next;
  159. free(i);
  160. } /* for */
  161. errorMessages = NULL;
  162. } /* freeErrorMessages */
  163. void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
  164. {
  165. if (ver != NULL)
  166. {
  167. ver->major = PHYSFS_VER_MAJOR;
  168. ver->minor = PHYSFS_VER_MINOR;
  169. ver->patch = PHYSFS_VER_PATCH;
  170. } /* if */
  171. } /* PHYSFS_getLinkedVersion */
  172. static const char *find_filename_extension(const char *fname)
  173. {
  174. const char *retval = strchr(fname, '.');
  175. const char *p = retval;
  176. while (p != NULL)
  177. {
  178. p = strchr(p + 1, '.');
  179. if (p != NULL)
  180. retval = p;
  181. } /* while */
  182. if (retval != NULL)
  183. retval++; /* skip '.' */
  184. return(retval);
  185. } /* find_filename_extension */
  186. static DirHandle *openDirectory(const char *d, int forWriting)
  187. {
  188. const DirFunctions **i;
  189. const char *ext;
  190. BAIL_IF_MACRO(!__PHYSFS_platformExists(d), ERR_NO_SUCH_FILE, NULL);
  191. ext = find_filename_extension(d);
  192. if (ext != NULL)
  193. {
  194. /* Look for archivers with matching file extensions first... */
  195. for (i = dirFunctions; *i != NULL; i++)
  196. {
  197. if (__PHYSFS_platformStricmp(ext, (*i)->info->extension) == 0)
  198. {
  199. if ((*i)->isArchive(d, forWriting))
  200. return( (*i)->openArchive(d, forWriting) );
  201. } /* if */
  202. } /* for */
  203. /* failing an exact file extension match, try all the others... */
  204. for (i = dirFunctions; *i != NULL; i++)
  205. {
  206. if (__PHYSFS_platformStricmp(ext, (*i)->info->extension) != 0)
  207. {
  208. if ((*i)->isArchive(d, forWriting))
  209. return( (*i)->openArchive(d, forWriting) );
  210. } /* if */
  211. } /* for */
  212. } /* if */
  213. else /* no extension? Try them all. */
  214. {
  215. for (i = dirFunctions; *i != NULL; i++)
  216. {
  217. if ((*i)->isArchive(d, forWriting))
  218. return( (*i)->openArchive(d, forWriting) );
  219. } /* for */
  220. } /* else */
  221. __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
  222. return(NULL);
  223. } /* openDirectory */
  224. static PhysDirInfo *buildDirInfo(const char *newDir, int forWriting)
  225. {
  226. DirHandle *dirHandle = NULL;
  227. PhysDirInfo *di = NULL;
  228. BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
  229. dirHandle = openDirectory(newDir, forWriting);
  230. BAIL_IF_MACRO(dirHandle == NULL, NULL, 0);
  231. di = (PhysDirInfo *) malloc(sizeof (PhysDirInfo));
  232. if (di == NULL)
  233. {
  234. dirHandle->funcs->dirClose(dirHandle);
  235. BAIL_IF_MACRO(di == NULL, ERR_OUT_OF_MEMORY, 0);
  236. } /* if */
  237. di->dirName = (char *) malloc(strlen(newDir) + 1);
  238. if (di->dirName == NULL)
  239. {
  240. free(di);
  241. dirHandle->funcs->dirClose(dirHandle);
  242. BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
  243. } /* if */
  244. di->next = NULL;
  245. di->dirHandle = dirHandle;
  246. strcpy(di->dirName, newDir);
  247. return(di);
  248. } /* buildDirInfo */
  249. /* MAKE SURE you've got the stateLock held before calling this! */
  250. static int freeDirInfo(PhysDirInfo *di, FileHandleList *openList)
  251. {
  252. FileHandleList *i;
  253. if (di == NULL)
  254. return(1);
  255. for (i = openList; i != NULL; i = i->next)
  256. {
  257. const DirHandle *h = ((FileHandle *) &(i->handle.opaque))->dirHandle;
  258. BAIL_IF_MACRO(h == di->dirHandle, ERR_FILES_STILL_OPEN, 0);
  259. } /* for */
  260. di->dirHandle->funcs->dirClose(di->dirHandle);
  261. free(di->dirName);
  262. free(di);
  263. return(1);
  264. } /* freeDirInfo */
  265. static char *calculateUserDir(void)
  266. {
  267. char *retval = NULL;
  268. const char *str = NULL;
  269. str = __PHYSFS_platformGetUserDir();
  270. if (str != NULL)
  271. retval = (char *) str;
  272. else
  273. {
  274. const char *dirsep = PHYSFS_getDirSeparator();
  275. const char *uname = __PHYSFS_platformGetUserName();
  276. str = (uname != NULL) ? uname : "default";
  277. retval = (char *) malloc(strlen(baseDir) + strlen(str) +
  278. strlen(dirsep) + 6);
  279. if (retval == NULL)
  280. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  281. else
  282. sprintf(retval, "%susers%s%s", baseDir, dirsep, str);
  283. if (uname != NULL)
  284. free((void *) uname);
  285. } /* else */
  286. return(retval);
  287. } /* calculateUserDir */
  288. static int appendDirSep(char **dir)
  289. {
  290. const char *dirsep = PHYSFS_getDirSeparator();
  291. char *ptr;
  292. if (strcmp((*dir + strlen(*dir)) - strlen(dirsep), dirsep) == 0)
  293. return(1);
  294. ptr = realloc(*dir, strlen(*dir) + strlen(dirsep) + 1);
  295. if (!ptr)
  296. {
  297. free(*dir);
  298. return(0);
  299. } /* if */
  300. strcat(ptr, dirsep);
  301. *dir = ptr;
  302. return(1);
  303. } /* appendDirSep */
  304. static char *calculateBaseDir(const char *argv0)
  305. {
  306. const char *dirsep = PHYSFS_getDirSeparator();
  307. char *retval;
  308. char *ptr;
  309. /*
  310. * See if the platform driver wants to handle this for us...
  311. */
  312. retval = __PHYSFS_platformCalcBaseDir(argv0);
  313. if (retval != NULL)
  314. return(retval);
  315. /*
  316. * Determine if there's a path on argv0. If there is, that's the base dir.
  317. */
  318. ptr = strstr(argv0, dirsep);
  319. if (ptr != NULL)
  320. {
  321. char *p = ptr;
  322. size_t size;
  323. while (p != NULL)
  324. {
  325. ptr = p;
  326. p = strstr(p + 1, dirsep);
  327. } /* while */
  328. size = (size_t) (ptr - argv0);
  329. retval = (char *) malloc(size + 1);
  330. BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
  331. memcpy(retval, argv0, size);
  332. retval[size] = '\0';
  333. return(retval);
  334. } /* if */
  335. /*
  336. * Last ditch effort: it's the current working directory. (*shrug*)
  337. */
  338. retval = __PHYSFS_platformCurrentDir();
  339. if(retval != NULL) {
  340. return(retval);
  341. }
  342. /*
  343. * Ok, current directory doesn't exist, use the root directory.
  344. * Not a good alternative, but it only happens if the current
  345. * directory was deleted from under the program.
  346. */
  347. retval = (char *) malloc(strlen(dirsep) + 1);
  348. strcpy(retval, dirsep);
  349. return(retval);
  350. } /* calculateBaseDir */
  351. static int initializeMutexes(void)
  352. {
  353. errorLock = __PHYSFS_platformCreateMutex();
  354. if (errorLock == NULL)
  355. goto initializeMutexes_failed;
  356. stateLock = __PHYSFS_platformCreateMutex();
  357. if (stateLock == NULL)
  358. goto initializeMutexes_failed;
  359. return(1); /* success. */
  360. initializeMutexes_failed:
  361. if (errorLock != NULL)
  362. __PHYSFS_platformDestroyMutex(errorLock);
  363. if (stateLock != NULL)
  364. __PHYSFS_platformDestroyMutex(stateLock);
  365. errorLock = stateLock = NULL;
  366. return(0); /* failed. */
  367. } /* initializeMutexes */
  368. int PHYSFS_init(const char *argv0)
  369. {
  370. char *ptr;
  371. BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
  372. BAIL_IF_MACRO(!__PHYSFS_platformInit(), NULL, 0);
  373. BAIL_IF_MACRO(!initializeMutexes(), NULL, 0);
  374. baseDir = calculateBaseDir(argv0);
  375. BAIL_IF_MACRO(baseDir == NULL, NULL, 0);
  376. ptr = __PHYSFS_platformRealPath(baseDir);
  377. free(baseDir);
  378. BAIL_IF_MACRO(ptr == NULL, NULL, 0);
  379. baseDir = ptr;
  380. BAIL_IF_MACRO(!appendDirSep(&baseDir), NULL, 0);
  381. userDir = calculateUserDir();
  382. if (userDir != NULL)
  383. {
  384. ptr = __PHYSFS_platformRealPath(userDir);
  385. free(userDir);
  386. userDir = ptr;
  387. } /* if */
  388. if ((userDir == NULL) || (!appendDirSep(&userDir)))
  389. {
  390. free(baseDir);
  391. baseDir = NULL;
  392. return(0);
  393. } /* if */
  394. initialized = 1;
  395. /* This makes sure that the error subsystem is initialized. */
  396. __PHYSFS_setError(PHYSFS_getLastError());
  397. return(1);
  398. } /* PHYSFS_init */
  399. /* MAKE SURE you hold stateLock before calling this! */
  400. static int closeFileHandleList(FileHandleList **list)
  401. {
  402. FileHandleList *i;
  403. FileHandleList *next = NULL;
  404. FileHandle *h;
  405. for (i = *list; i != NULL; i = next)
  406. {
  407. next = i->next;
  408. h = (FileHandle *) (i->handle.opaque);
  409. if (!h->funcs->fileClose(h))
  410. {
  411. *list = i;
  412. return(0);
  413. } /* if */
  414. free(i);
  415. } /* for */
  416. *list = NULL;
  417. return(1);
  418. } /* closeFileHandleList */
  419. /* MAKE SURE you hold the stateLock before calling this! */
  420. static void freeSearchPath(void)
  421. {
  422. PhysDirInfo *i;
  423. PhysDirInfo *next = NULL;
  424. closeFileHandleList(&openReadList);
  425. if (searchPath != NULL)
  426. {
  427. for (i = searchPath; i != NULL; i = next)
  428. {
  429. next = i->next;
  430. freeDirInfo(i, openReadList);
  431. } /* for */
  432. searchPath = NULL;
  433. } /* if */
  434. } /* freeSearchPath */
  435. int PHYSFS_deinit(void)
  436. {
  437. BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
  438. BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), NULL, 0);
  439. closeFileHandleList(&openWriteList);
  440. BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), ERR_FILES_STILL_OPEN, 0);
  441. freeSearchPath();
  442. freeErrorMessages();
  443. if (baseDir != NULL)
  444. {
  445. free(baseDir);
  446. baseDir = NULL;
  447. } /* if */
  448. if (userDir != NULL)
  449. {
  450. free(userDir);
  451. userDir = NULL;
  452. } /* if */
  453. allowSymLinks = 0;
  454. initialized = 0;
  455. __PHYSFS_platformDestroyMutex(errorLock);
  456. __PHYSFS_platformDestroyMutex(stateLock);
  457. errorLock = stateLock = NULL;
  458. return(1);
  459. } /* PHYSFS_deinit */
  460. const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
  461. {
  462. return(supported_types);
  463. } /* PHYSFS_supportedArchiveTypes */
  464. void PHYSFS_freeList(void *list)
  465. {
  466. void **i;
  467. for (i = (void **) list; *i != NULL; i++)
  468. free(*i);
  469. free(list);
  470. } /* PHYSFS_freeList */
  471. const char *PHYSFS_getDirSeparator(void)
  472. {
  473. return(__PHYSFS_platformDirSeparator);
  474. } /* PHYSFS_getDirSeparator */
  475. char **PHYSFS_getCdRomDirs(void)
  476. {
  477. return(__PHYSFS_platformDetectAvailableCDs());
  478. } /* PHYSFS_getCdRomDirs */
  479. const char *PHYSFS_getBaseDir(void)
  480. {
  481. return(baseDir); /* this is calculated in PHYSFS_init()... */
  482. } /* PHYSFS_getBaseDir */
  483. const char *PHYSFS_getUserDir(void)
  484. {
  485. return(userDir); /* this is calculated in PHYSFS_init()... */
  486. } /* PHYSFS_getUserDir */
  487. const char *PHYSFS_getWriteDir(void)
  488. {
  489. const char *retval = NULL;
  490. __PHYSFS_platformGrabMutex(stateLock);
  491. if (writeDir != NULL)
  492. retval = writeDir->dirName;
  493. __PHYSFS_platformReleaseMutex(stateLock);
  494. return(retval);
  495. } /* PHYSFS_getWriteDir */
  496. int PHYSFS_setWriteDir(const char *newDir)
  497. {
  498. int retval = 1;
  499. __PHYSFS_platformGrabMutex(stateLock);
  500. if (writeDir != NULL)
  501. {
  502. BAIL_IF_MACRO_MUTEX(!freeDirInfo(writeDir, openWriteList), NULL,
  503. stateLock, 0);
  504. writeDir = NULL;
  505. } /* if */
  506. if (newDir != NULL)
  507. {
  508. writeDir = buildDirInfo(newDir, 1);
  509. retval = (writeDir != NULL);
  510. } /* if */
  511. __PHYSFS_platformReleaseMutex(stateLock);
  512. return(retval);
  513. } /* PHYSFS_setWriteDir */
  514. int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
  515. {
  516. PhysDirInfo *di;
  517. PhysDirInfo *prev = NULL;
  518. PhysDirInfo *i;
  519. __PHYSFS_platformGrabMutex(stateLock);
  520. for (i = searchPath; i != NULL; i = i->next)
  521. {
  522. /* already in search path? */
  523. BAIL_IF_MACRO_MUTEX(strcmp(newDir, i->dirName)==0, NULL, stateLock, 1);
  524. prev = i;
  525. } /* for */
  526. di = buildDirInfo(newDir, 0);
  527. BAIL_IF_MACRO_MUTEX(di == NULL, NULL, stateLock, 0);
  528. if (appendToPath)
  529. {
  530. di->next = NULL;
  531. if (prev == NULL)
  532. searchPath = di;
  533. else
  534. prev->next = di;
  535. } /* if */
  536. else
  537. {
  538. di->next = searchPath;
  539. searchPath = di;
  540. } /* else */
  541. __PHYSFS_platformReleaseMutex(stateLock);
  542. return(1);
  543. } /* PHYSFS_addToSearchPath */
  544. int PHYSFS_removeFromSearchPath(const char *oldDir)
  545. {
  546. PhysDirInfo *i;
  547. PhysDirInfo *prev = NULL;
  548. PhysDirInfo *next = NULL;
  549. BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
  550. __PHYSFS_platformGrabMutex(stateLock);
  551. for (i = searchPath; i != NULL; i = i->next)
  552. {
  553. if (strcmp(i->dirName, oldDir) == 0)
  554. {
  555. next = i->next;
  556. BAIL_IF_MACRO_MUTEX(!freeDirInfo(i, openReadList), NULL,
  557. stateLock, 0);
  558. if (prev == NULL)
  559. searchPath = next;
  560. else
  561. prev->next = next;
  562. BAIL_MACRO_MUTEX(NULL, stateLock, 1);
  563. } /* if */
  564. prev = i;
  565. } /* for */
  566. BAIL_MACRO_MUTEX(ERR_NOT_IN_SEARCH_PATH, stateLock, 0);
  567. } /* PHYSFS_removeFromSearchPath */
  568. char **PHYSFS_getSearchPath(void)
  569. {
  570. int count = 1;
  571. int x;
  572. PhysDirInfo *i;
  573. char **retval;
  574. __PHYSFS_platformGrabMutex(stateLock);
  575. for (i = searchPath; i != NULL; i = i->next)
  576. count++;
  577. retval = (char **) malloc(sizeof (char *) * count);
  578. BAIL_IF_MACRO_MUTEX(!retval, ERR_OUT_OF_MEMORY, stateLock, NULL);
  579. count--;
  580. retval[count] = NULL;
  581. for (i = searchPath, x = 0; x < count; i = i->next, x++)
  582. {
  583. retval[x] = (char *) malloc(strlen(i->dirName) + 1);
  584. if (retval[x] == NULL) /* this is friggin' ugly. */
  585. {
  586. while (x > 0)
  587. {
  588. x--;
  589. free(retval[x]);
  590. } /* while */
  591. free(retval);
  592. BAIL_MACRO_MUTEX(ERR_OUT_OF_MEMORY, stateLock, NULL);
  593. } /* if */
  594. strcpy(retval[x], i->dirName);
  595. } /* for */
  596. __PHYSFS_platformReleaseMutex(stateLock);
  597. return(retval);
  598. } /* PHYSFS_getSearchPath */
  599. int PHYSFS_setSaneConfig(const char *organization, const char *appName,
  600. const char *archiveExt, int includeCdRoms,
  601. int archivesFirst)
  602. {
  603. const char *basedir = PHYSFS_getBaseDir();
  604. const char *userdir = PHYSFS_getUserDir();
  605. const char *dirsep = PHYSFS_getDirSeparator();
  606. char *str;
  607. BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
  608. /* set write dir... */
  609. str = malloc(strlen(userdir) + (strlen(organization) * 2) +
  610. (strlen(appName) * 2) + (strlen(dirsep) * 3) + 2);
  611. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  612. sprintf(str, "%s.%s%s%s", userdir, organization, dirsep, appName);
  613. if (!PHYSFS_setWriteDir(str))
  614. {
  615. int no_write = 0;
  616. sprintf(str, ".%s/%s", organization, appName);
  617. if ( (PHYSFS_setWriteDir(userdir)) &&
  618. (PHYSFS_mkdir(str)) )
  619. {
  620. sprintf(str, "%s.%s%s%s", userdir, organization, dirsep, appName);
  621. if (!PHYSFS_setWriteDir(str))
  622. no_write = 1;
  623. } /* if */
  624. else
  625. {
  626. no_write = 1;
  627. } /* else */
  628. if (no_write)
  629. {
  630. PHYSFS_setWriteDir(NULL); /* just in case. */
  631. free(str);
  632. BAIL_MACRO(ERR_CANT_SET_WRITE_DIR, 0);
  633. } /* if */
  634. } /* if */
  635. /* Put write dir first in search path... */
  636. PHYSFS_addToSearchPath(str, 0);
  637. free(str);
  638. /* Put base path on search path... */
  639. PHYSFS_addToSearchPath(basedir, 1);
  640. /* handle CD-ROMs... */
  641. if (includeCdRoms)
  642. {
  643. char **cds = PHYSFS_getCdRomDirs();
  644. char **i;
  645. for (i = cds; *i != NULL; i++)
  646. PHYSFS_addToSearchPath(*i, 1);
  647. PHYSFS_freeList(cds);
  648. } /* if */
  649. /* Root out archives, and add them to search path... */
  650. if (archiveExt != NULL)
  651. {
  652. char **rc = PHYSFS_enumerateFiles("/");
  653. char **i;
  654. size_t extlen = strlen(archiveExt);
  655. char *ext;
  656. for (i = rc; *i != NULL; i++)
  657. {
  658. size_t l = strlen(*i);
  659. if ((l > extlen) && ((*i)[l - extlen - 1] == '.'))
  660. {
  661. ext = (*i) + (l - extlen);
  662. if (__PHYSFS_platformStricmp(ext, archiveExt) == 0)
  663. {
  664. const char *d = PHYSFS_getRealDir(*i);
  665. str = malloc(strlen(d) + strlen(dirsep) + l + 1);
  666. if (str != NULL)
  667. {
  668. sprintf(str, "%s%s%s", d, dirsep, *i);
  669. PHYSFS_addToSearchPath(str, archivesFirst == 0);
  670. free(str);
  671. } /* if */
  672. } /* if */
  673. } /* if */
  674. } /* for */
  675. PHYSFS_freeList(rc);
  676. } /* if */
  677. return(1);
  678. } /* PHYSFS_setSaneConfig */
  679. void PHYSFS_permitSymbolicLinks(int allow)
  680. {
  681. allowSymLinks = allow;
  682. } /* PHYSFS_permitSymbolicLinks */
  683. /* string manipulation in C makes my ass itch. */
  684. char * __PHYSFS_convertToDependent(const char *prepend,
  685. const char *dirName,
  686. const char *append)
  687. {
  688. const char *dirsep = __PHYSFS_platformDirSeparator;
  689. size_t sepsize = strlen(dirsep);
  690. char *str;
  691. char *i1;
  692. char *i2;
  693. size_t allocSize;
  694. while (*dirName == '/')
  695. dirName++;
  696. allocSize = strlen(dirName) + 1;
  697. if (prepend != NULL)
  698. allocSize += strlen(prepend) + sepsize;
  699. if (append != NULL)
  700. allocSize += strlen(append) + sepsize;
  701. /* make sure there's enough space if the dir separator is bigger. */
  702. if (sepsize > 1)
  703. {
  704. str = (char *) dirName;
  705. do
  706. {
  707. str = strchr(str, '/');
  708. if (str != NULL)
  709. {
  710. allocSize += (sepsize - 1);
  711. str++;
  712. } /* if */
  713. } while (str != NULL);
  714. } /* if */
  715. str = (char *) malloc(allocSize);
  716. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, NULL);
  717. if (prepend == NULL)
  718. *str = '\0';
  719. else
  720. {
  721. strcpy(str, prepend);
  722. strcat(str, dirsep);
  723. } /* else */
  724. for (i1 = (char *) dirName, i2 = str + strlen(str); *i1; i1++, i2++)
  725. {
  726. if (*i1 == '/')
  727. {
  728. strcpy(i2, dirsep);
  729. i2 += sepsize;
  730. } /* if */
  731. else
  732. {
  733. *i2 = *i1;
  734. } /* else */
  735. } /* for */
  736. *i2 = '\0';
  737. if (append)
  738. {
  739. strcat(str, dirsep);
  740. strcpy(str, append);
  741. } /* if */
  742. return(str);
  743. } /* __PHYSFS_convertToDependent */
  744. int __PHYSFS_verifySecurity(DirHandle *h, const char *fname)
  745. {
  746. int retval = 1;
  747. char *start;
  748. char *end;
  749. char *str;
  750. start = str = malloc(strlen(fname) + 1);
  751. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  752. strcpy(str, fname);
  753. while (1)
  754. {
  755. end = strchr(start, '/');
  756. if (end != NULL)
  757. *end = '\0';
  758. if ( (strcmp(start, ".") == 0) ||
  759. (strcmp(start, "..") == 0) ||
  760. (strchr(start, '\\') != NULL) ||
  761. (strchr(start, ':') != NULL) )
  762. {
  763. __PHYSFS_setError(ERR_INSECURE_FNAME);
  764. retval = 0;
  765. break;
  766. } /* if */
  767. if ((!allowSymLinks) && (h->funcs->isSymLink(h, str)))
  768. {
  769. __PHYSFS_setError(ERR_SYMLINK_DISALLOWED);
  770. retval = 0;
  771. break;
  772. } /* if */
  773. if (end == NULL)
  774. break;
  775. *end = '/';
  776. start = end + 1;
  777. } /* while */
  778. free(str);
  779. return(retval);
  780. } /* __PHYSFS_verifySecurity */
  781. int PHYSFS_mkdir(const char *dname)
  782. {
  783. DirHandle *h;
  784. char *str;
  785. char *start;
  786. char *end;
  787. int retval = 0;
  788. BAIL_IF_MACRO(dname == NULL, ERR_INVALID_ARGUMENT, 0);
  789. while (*dname == '/')
  790. dname++;
  791. __PHYSFS_platformGrabMutex(stateLock);
  792. BAIL_IF_MACRO_MUTEX(writeDir == NULL, ERR_NO_WRITE_DIR, stateLock, 0);
  793. h = writeDir->dirHandle;
  794. BAIL_IF_MACRO_MUTEX(!h->funcs->mkdir, ERR_NOT_SUPPORTED, stateLock, 0);
  795. BAIL_IF_MACRO_MUTEX(!__PHYSFS_verifySecurity(h, dname), NULL, stateLock, 0);
  796. start = str = malloc(strlen(dname) + 1);
  797. BAIL_IF_MACRO_MUTEX(str == NULL, ERR_OUT_OF_MEMORY, stateLock, 0);
  798. strcpy(str, dname);
  799. while (1)
  800. {
  801. end = strchr(start, '/');
  802. if (end != NULL)
  803. *end = '\0';
  804. retval = h->funcs->mkdir(h, str);
  805. if (!retval)
  806. break;
  807. if (end == NULL)
  808. break;
  809. *end = '/';
  810. start = end + 1;
  811. } /* while */
  812. __PHYSFS_platformReleaseMutex(stateLock);
  813. free(str);
  814. return(retval);
  815. } /* PHYSFS_mkdir */
  816. int PHYSFS_delete(const char *fname)
  817. {
  818. int retval;
  819. DirHandle *h;
  820. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
  821. while (*fname == '/')
  822. fname++;
  823. __PHYSFS_platformGrabMutex(stateLock);
  824. BAIL_IF_MACRO_MUTEX(writeDir == NULL, ERR_NO_WRITE_DIR, stateLock, 0);
  825. h = writeDir->dirHandle;
  826. BAIL_IF_MACRO_MUTEX(!h->funcs->remove, ERR_NOT_SUPPORTED, stateLock, 0);
  827. BAIL_IF_MACRO_MUTEX(!__PHYSFS_verifySecurity(h, fname), NULL, stateLock, 0);
  828. retval = h->funcs->remove(h, fname);
  829. __PHYSFS_platformReleaseMutex(stateLock);
  830. return(retval);
  831. } /* PHYSFS_delete */
  832. const char *PHYSFS_getRealDir(const char *filename)
  833. {
  834. PhysDirInfo *i;
  835. while (*filename == '/')
  836. filename++;
  837. __PHYSFS_platformGrabMutex(stateLock);
  838. for (i = searchPath; i != NULL; i = i->next)
  839. {
  840. DirHandle *h = i->dirHandle;
  841. if (__PHYSFS_verifySecurity(h, filename))
  842. {
  843. if (!h->funcs->exists(h, filename))
  844. __PHYSFS_setError(ERR_NO_SUCH_FILE);
  845. else
  846. {
  847. __PHYSFS_platformReleaseMutex(stateLock);
  848. return(i->dirName);
  849. } /* else */
  850. } /* if */
  851. } /* for */
  852. __PHYSFS_platformReleaseMutex(stateLock);
  853. return(NULL);
  854. } /* PHYSFS_getRealDir */
  855. static int countList(LinkedStringList *list)
  856. {
  857. int retval = 0;
  858. LinkedStringList *i;
  859. for (i = list; i != NULL; i = i->next)
  860. retval++;
  861. return(retval);
  862. } /* countList */
  863. static char **convertStringListToPhysFSList(LinkedStringList *finalList)
  864. {
  865. int i;
  866. LinkedStringList *next = NULL;
  867. int len = countList(finalList);
  868. char **retval = (char **) malloc((len + 1) * sizeof (char *));
  869. if (retval == NULL)
  870. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  871. for (i = 0; i < len; i++)
  872. {
  873. next = finalList->next;
  874. if (retval == NULL)
  875. free(finalList->str);
  876. else
  877. retval[i] = finalList->str;
  878. free(finalList);
  879. finalList = next;
  880. } /* for */
  881. if (retval != NULL)
  882. retval[i] = NULL;
  883. return(retval);
  884. } /* convertStringListToPhysFSList */
  885. static void insertStringListItem(LinkedStringList **final,
  886. LinkedStringList *item)
  887. {
  888. LinkedStringList *i;
  889. LinkedStringList *prev = NULL;
  890. int rc;
  891. for (i = *final; i != NULL; i = i->next)
  892. {
  893. rc = strcmp(i->str, item->str);
  894. if (rc > 0) /* insertion point. */
  895. break;
  896. else if (rc == 0) /* already in list. */
  897. {
  898. free(item->str);
  899. free(item);
  900. return;
  901. } /* else if */
  902. prev = i;
  903. } /* for */
  904. /*
  905. * If we are here, we are either at the insertion point.
  906. * This may be the end of the list, or the list may be empty, too.
  907. */
  908. if (prev == NULL)
  909. *final = item;
  910. else
  911. prev->next = item;
  912. item->next = i;
  913. } /* insertStringListItem */
  914. /* if we run out of memory anywhere in here, we give back what we can. */
  915. static void interpolateStringLists(LinkedStringList **final,
  916. LinkedStringList *newList)
  917. {
  918. LinkedStringList *next = NULL;
  919. while (newList != NULL)
  920. {
  921. next = newList->next;
  922. insertStringListItem(final, newList);
  923. newList = next;
  924. } /* while */
  925. } /* interpolateStringLists */
  926. char **PHYSFS_enumerateFiles(const char *path)
  927. {
  928. PhysDirInfo *i;
  929. char **retval = NULL;
  930. LinkedStringList *rc;
  931. LinkedStringList *finalList = NULL;
  932. int omitSymLinks = !allowSymLinks;
  933. BAIL_IF_MACRO(path == NULL, ERR_INVALID_ARGUMENT, NULL);
  934. while (*path == '/')
  935. path++;
  936. __PHYSFS_platformGrabMutex(stateLock);
  937. for (i = searchPath; i != NULL; i = i->next)
  938. {
  939. DirHandle *h = i->dirHandle;
  940. if (__PHYSFS_verifySecurity(h, path))
  941. {
  942. rc = h->funcs->enumerateFiles(h, path, omitSymLinks);
  943. interpolateStringLists(&finalList, rc);
  944. } /* if */
  945. } /* for */
  946. __PHYSFS_platformReleaseMutex(stateLock);
  947. retval = convertStringListToPhysFSList(finalList);
  948. return(retval);
  949. } /* PHYSFS_enumerateFiles */
  950. int PHYSFS_exists(const char *fname)
  951. {
  952. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
  953. while (*fname == '/')
  954. fname++;
  955. return(PHYSFS_getRealDir(fname) != NULL);
  956. } /* PHYSFS_exists */
  957. PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname)
  958. {
  959. PhysDirInfo *i;
  960. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
  961. while (*fname == '/')
  962. fname++;
  963. if (*fname == '\0') /* eh...punt if it's the root dir. */
  964. return(1);
  965. __PHYSFS_platformGrabMutex(stateLock);
  966. for (i = searchPath; i != NULL; i = i->next)
  967. {
  968. DirHandle *h = i->dirHandle;
  969. if (__PHYSFS_verifySecurity(h, fname))
  970. {
  971. if (!h->funcs->exists(h, fname))
  972. __PHYSFS_setError(ERR_NO_SUCH_FILE);
  973. else
  974. {
  975. PHYSFS_sint64 retval = -1;
  976. if (h->funcs->getLastModTime == NULL)
  977. __PHYSFS_setError(ERR_NOT_SUPPORTED);
  978. else
  979. retval = h->funcs->getLastModTime(h, fname);
  980. __PHYSFS_platformReleaseMutex(stateLock);
  981. return(retval);
  982. } /* else */
  983. } /* if */
  984. } /* for */
  985. __PHYSFS_platformReleaseMutex(stateLock);
  986. return(-1); /* error set in verifysecurity/exists */
  987. } /* PHYSFS_getLastModTime */
  988. int PHYSFS_isDirectory(const char *fname)
  989. {
  990. PhysDirInfo *i;
  991. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
  992. while (*fname == '/')
  993. fname++;
  994. if (*fname == '\0')
  995. return(1);
  996. __PHYSFS_platformGrabMutex(stateLock);
  997. for (i = searchPath; i != NULL; i = i->next)
  998. {
  999. DirHandle *h = i->dirHandle;
  1000. if (__PHYSFS_verifySecurity(h, fname))
  1001. {
  1002. if (!h->funcs->exists(h, fname))
  1003. __PHYSFS_setError(ERR_NO_SUCH_FILE);
  1004. else
  1005. {
  1006. int retval = h->funcs->isDirectory(h, fname);
  1007. __PHYSFS_platformReleaseMutex(stateLock);
  1008. return(retval);
  1009. } /* else */
  1010. } /* if */
  1011. } /* for */
  1012. __PHYSFS_platformReleaseMutex(stateLock);
  1013. return(0);
  1014. } /* PHYSFS_isDirectory */
  1015. int PHYSFS_isSymbolicLink(const char *fname)
  1016. {
  1017. PhysDirInfo *i;
  1018. if (!allowSymLinks)
  1019. return(0);
  1020. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
  1021. while (*fname == '/')
  1022. fname++;
  1023. __PHYSFS_platformGrabMutex(stateLock);
  1024. for (i = searchPath; i != NULL; i = i->next)
  1025. {
  1026. DirHandle *h = i->dirHandle;
  1027. if (__PHYSFS_verifySecurity(h, fname))
  1028. {
  1029. if (!h->funcs->exists(h, fname))
  1030. __PHYSFS_setError(ERR_NO_SUCH_FILE);
  1031. else
  1032. {
  1033. int retval = h->funcs->isSymLink(h, fname);
  1034. __PHYSFS_platformReleaseMutex(stateLock);
  1035. return(retval);
  1036. } /* else */
  1037. } /* if */
  1038. } /* for */
  1039. __PHYSFS_platformReleaseMutex(stateLock);
  1040. return(0);
  1041. } /* PHYSFS_isSymbolicLink */
  1042. static PHYSFS_file *doOpenWrite(const char *fname, int appending)
  1043. {
  1044. PHYSFS_file *retval = NULL;
  1045. FileHandle *rc = NULL;
  1046. DirHandle *h;
  1047. const DirFunctions *f;
  1048. FileHandleList *list;
  1049. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, NULL);
  1050. while (*fname == '/')
  1051. fname++;
  1052. __PHYSFS_platformGrabMutex(stateLock);
  1053. h = (writeDir == NULL) ? NULL : writeDir->dirHandle;
  1054. BAIL_IF_MACRO_MUTEX(!h, ERR_NO_WRITE_DIR, stateLock, NULL);
  1055. BAIL_IF_MACRO_MUTEX(!__PHYSFS_verifySecurity(h, fname), NULL,
  1056. stateLock, NULL);
  1057. list = (FileHandleList *) malloc(sizeof (FileHandleList));
  1058. BAIL_IF_MACRO_MUTEX(!list, ERR_OUT_OF_MEMORY, stateLock, NULL);
  1059. f = h->funcs;
  1060. rc = (appending) ? f->openAppend(h, fname) : f->openWrite(h, fname);
  1061. if (rc == NULL)
  1062. free(list);
  1063. else
  1064. {
  1065. list->handle.opaque = (void *) rc;
  1066. list->next = openWriteList;
  1067. openWriteList = list;
  1068. retval = &(list->handle);
  1069. } /* else */
  1070. __PHYSFS_platformReleaseMutex(stateLock);
  1071. return(retval);
  1072. } /* doOpenWrite */
  1073. PHYSFS_file *PHYSFS_openWrite(const char *filename)
  1074. {
  1075. return(doOpenWrite(filename, 0));
  1076. } /* PHYSFS_openWrite */
  1077. PHYSFS_file *PHYSFS_openAppend(const char *filename)
  1078. {
  1079. return(doOpenWrite(filename, 1));
  1080. } /* PHYSFS_openAppend */
  1081. PHYSFS_file *PHYSFS_openRead(const char *fname)
  1082. {
  1083. PHYSFS_file *retval;
  1084. FileHandle *rc = NULL;
  1085. FileHandleList *list;
  1086. PhysDirInfo *i;
  1087. BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, NULL);
  1088. while (*fname == '/')
  1089. fname++;
  1090. __PHYSFS_platformGrabMutex(stateLock);
  1091. BAIL_IF_MACRO_MUTEX(!searchPath, ERR_NOT_IN_SEARCH_PATH, stateLock, NULL);
  1092. for (i = searchPath; i != NULL; i = i->next)
  1093. {
  1094. DirHandle *h = i->dirHandle;
  1095. if (__PHYSFS_verifySecurity(h, fname))
  1096. {
  1097. rc = h->funcs->openRead(h, fname);
  1098. if (rc != NULL)
  1099. break;
  1100. } /* if */
  1101. } /* for */
  1102. BAIL_IF_MACRO_MUTEX(rc == NULL, NULL, stateLock, NULL);
  1103. list = (FileHandleList *) malloc(sizeof (FileHandleList));
  1104. BAIL_IF_MACRO(!list, ERR_OUT_OF_MEMORY, NULL);
  1105. list->handle.opaque = (void *) rc;
  1106. list->next = openReadList;
  1107. openReadList = list;
  1108. retval = &(list->handle);
  1109. __PHYSFS_platformReleaseMutex(stateLock);
  1110. return(retval);
  1111. } /* PHYSFS_openRead */
  1112. static int closeHandleInOpenList(FileHandleList **list, PHYSFS_file *handle)
  1113. {
  1114. FileHandle *h = (FileHandle *) handle->opaque;
  1115. FileHandleList *prev = NULL;
  1116. FileHandleList *i;
  1117. int rc;
  1118. for (i = *list; i != NULL; i = i->next)
  1119. {
  1120. if (&i->handle == handle) /* handle is in this list? */
  1121. {
  1122. rc = h->funcs->fileClose(h);
  1123. if (!rc)
  1124. return(-1);
  1125. if (prev == NULL)
  1126. *list = i->next;
  1127. else
  1128. prev->next = i->next;
  1129. free(i);
  1130. return(1);
  1131. } /* if */
  1132. prev = i;
  1133. } /* for */
  1134. return(0);
  1135. } /* closeHandleInOpenList */
  1136. int PHYSFS_close(PHYSFS_file *handle)
  1137. {
  1138. int rc;
  1139. __PHYSFS_platformGrabMutex(stateLock);
  1140. /* -1 == close failure. 0 == not found. 1 == success. */
  1141. rc = closeHandleInOpenList(&openReadList, handle);
  1142. BAIL_IF_MACRO_MUTEX(rc == -1, NULL, stateLock, 0);
  1143. if (!rc)
  1144. {
  1145. rc = closeHandleInOpenList(&openWriteList, handle);
  1146. BAIL_IF_MACRO_MUTEX(rc == -1, NULL, stateLock, 0);
  1147. } /* if */
  1148. __PHYSFS_platformReleaseMutex(stateLock);
  1149. BAIL_IF_MACRO(!rc, ERR_NOT_A_HANDLE, 0);
  1150. return(1);
  1151. } /* PHYSFS_close */
  1152. PHYSFS_sint64 PHYSFS_read(PHYSFS_file *handle, void *buffer,
  1153. PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
  1154. {
  1155. FileHandle *h = (FileHandle *) handle->opaque;
  1156. assert(h != NULL);
  1157. assert(h->funcs != NULL);
  1158. BAIL_IF_MACRO(h->funcs->read == NULL, ERR_NOT_SUPPORTED, -1);
  1159. return(h->funcs->read(h, buffer, objSize, objCount));
  1160. } /* PHYSFS_read */
  1161. PHYSFS_sint64 PHYSFS_write(PHYSFS_file *handle, const void *buffer,
  1162. PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
  1163. {
  1164. FileHandle *h = (FileHandle *) handle->opaque;
  1165. assert(h != NULL);
  1166. assert(h->funcs != NULL);
  1167. BAIL_IF_MACRO(h->funcs->write == NULL, ERR_NOT_SUPPORTED, -1);
  1168. return(h->funcs->write(h, buffer, objSize, objCount));
  1169. } /* PHYSFS_write */
  1170. int PHYSFS_eof(PHYSFS_file *handle)
  1171. {
  1172. FileHandle *h = (FileHandle *) handle->opaque;
  1173. assert(h != NULL);
  1174. assert(h->funcs != NULL);
  1175. BAIL_IF_MACRO(h->funcs->eof == NULL, ERR_NOT_SUPPORTED, -1);
  1176. return(h->funcs->eof(h));
  1177. } /* PHYSFS_eof */
  1178. PHYSFS_sint64 PHYSFS_tell(PHYSFS_file *handle)
  1179. {
  1180. FileHandle *h = (FileHandle *) handle->opaque;
  1181. assert(h != NULL);
  1182. assert(h->funcs != NULL);
  1183. BAIL_IF_MACRO(h->funcs->tell == NULL, ERR_NOT_SUPPORTED, -1);
  1184. return(h->funcs->tell(h));
  1185. } /* PHYSFS_tell */
  1186. int PHYSFS_seek(PHYSFS_file *handle, PHYSFS_uint64 pos)
  1187. {
  1188. FileHandle *h = (FileHandle *) handle->opaque;
  1189. assert(h != NULL);
  1190. assert(h->funcs != NULL);
  1191. BAIL_IF_MACRO(h->funcs->seek == NULL, ERR_NOT_SUPPORTED, 0);
  1192. BAIL_IF_MACRO(pos < 0, ERR_INVALID_ARGUMENT, 0);
  1193. return(h->funcs->seek(h, pos));
  1194. } /* PHYSFS_seek */
  1195. PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_file *handle)
  1196. {
  1197. FileHandle *h = (FileHandle *) handle->opaque;
  1198. assert(h != NULL);
  1199. assert(h->funcs != NULL);
  1200. BAIL_IF_MACRO(h->funcs->fileLength == NULL, ERR_NOT_SUPPORTED, 0);
  1201. return(h->funcs->fileLength(h));
  1202. } /* PHYSFS_filelength */
  1203. LinkedStringList *__PHYSFS_addToLinkedStringList(LinkedStringList *retval,
  1204. LinkedStringList **prev,
  1205. const char *str,
  1206. PHYSFS_sint32 len)
  1207. {
  1208. LinkedStringList *l;
  1209. l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
  1210. BAIL_IF_MACRO(l == NULL, ERR_OUT_OF_MEMORY, retval);
  1211. if (len < 0)
  1212. len = strlen(str);
  1213. l->str = (char *) malloc(len + 1);
  1214. if (l->str == NULL)
  1215. {
  1216. free(l);
  1217. BAIL_MACRO(ERR_OUT_OF_MEMORY, retval);
  1218. } /* if */
  1219. strncpy(l->str, str, len);
  1220. l->str[len] = '\0';
  1221. if (retval == NULL)
  1222. retval = l;
  1223. else
  1224. (*prev)->next = l;
  1225. *prev = l;
  1226. l->next = NULL;
  1227. return(retval);
  1228. } /* __PHYSFS_addToLinkedStringList */
  1229. /* end of physfs.c ... */