physfs.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  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. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <assert.h>
  14. #include "physfs.h"
  15. #define __PHYSICSFS_INTERNAL__
  16. #include "physfs_internal.h"
  17. typedef struct __PHYSFS_ERRMSGTYPE__
  18. {
  19. int tid;
  20. int errorAvailable;
  21. char errorString[80];
  22. struct __PHYSFS_ERRMSGTYPE__ *next;
  23. } ErrMsg;
  24. typedef struct __PHYSFS_DIRINFO__
  25. {
  26. char *dirName;
  27. DirHandle *dirHandle;
  28. struct __PHYSFS_DIRINFO__ *next;
  29. } DirInfo;
  30. typedef struct __PHYSFS_FILEHANDLELIST__
  31. {
  32. PHYSFS_file *handle;
  33. struct __PHYSFS_FILEHANDLELIST__ *next;
  34. } FileHandleList;
  35. /* The various i/o drivers... */
  36. #if (defined PHYSFS_SUPPORTS_ZIP)
  37. extern const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP;
  38. extern const DirFunctions __PHYSFS_DirFunctions_ZIP;
  39. #endif
  40. extern const DirFunctions __PHYSFS_DirFunctions_DIR;
  41. static const PHYSFS_ArchiveInfo *supported_types[] =
  42. {
  43. #if (defined PHYSFS_SUPPORTS_ZIP)
  44. &__PHYSFS_ArchiveInfo_ZIP,
  45. #endif
  46. NULL
  47. };
  48. static const DirFunctions *dirFunctions[] =
  49. {
  50. #if (defined PHYSFS_SUPPORTS_ZIP)
  51. &__PHYSFS_DirFunctions_ZIP,
  52. #endif
  53. &__PHYSFS_DirFunctions_DIR,
  54. NULL
  55. };
  56. /* General PhysicsFS state ... */
  57. static int initialized = 0;
  58. static ErrMsg *errorMessages = NULL;
  59. static DirInfo *searchPath = NULL;
  60. static DirInfo *writeDir = NULL;
  61. static FileHandleList *openWriteList = NULL;
  62. static FileHandleList *openReadList = NULL;
  63. static char *baseDir = NULL;
  64. static char *userDir = NULL;
  65. static int allowSymLinks = 0;
  66. /* functions ... */
  67. static ErrMsg *findErrorForCurrentThread(void)
  68. {
  69. ErrMsg *i;
  70. int tid;
  71. if (errorMessages != NULL)
  72. {
  73. tid = __PHYSFS_platformGetThreadID();
  74. for (i = errorMessages; i != NULL; i = i->next)
  75. {
  76. if (i->tid == tid)
  77. return(i);
  78. } /* for */
  79. } /* if */
  80. return(NULL); /* no error available. */
  81. } /* findErrorForCurrentThread */
  82. void __PHYSFS_setError(const char *str)
  83. {
  84. ErrMsg *err;
  85. if (str == NULL)
  86. return;
  87. err = findErrorForCurrentThread();
  88. if (err == NULL)
  89. {
  90. err = (ErrMsg *) malloc(sizeof (ErrMsg));
  91. if (err == NULL)
  92. return; /* uhh...? */
  93. err->tid = __PHYSFS_platformGetThreadID();
  94. err->next = errorMessages;
  95. errorMessages = err;
  96. } /* if */
  97. err->errorAvailable = 1;
  98. strncpy(err->errorString, str, sizeof (err->errorString));
  99. err->errorString[sizeof (err->errorString) - 1] = '\0';
  100. } /* __PHYSFS_setError */
  101. static void freeErrorMessages(void)
  102. {
  103. ErrMsg *i;
  104. ErrMsg *next;
  105. for (i = errorMessages; i != NULL; i = next)
  106. {
  107. next = i;
  108. free(i);
  109. } /* for */
  110. } /* freeErrorMessages */
  111. const char *PHYSFS_getLastError(void)
  112. {
  113. ErrMsg *err = findErrorForCurrentThread();
  114. if ((err == NULL) || (!err->errorAvailable))
  115. return(NULL);
  116. err->errorAvailable = 0;
  117. return(err->errorString);
  118. } /* PHYSFS_getLastError */
  119. void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
  120. {
  121. if (ver != NULL)
  122. {
  123. ver->major = PHYSFS_VER_MAJOR;
  124. ver->minor = PHYSFS_VER_MINOR;
  125. ver->patch = PHYSFS_VER_PATCH;
  126. } /* if */
  127. } /* PHYSFS_getLinkedVersion */
  128. static DirHandle *openDirectory(const char *d, int forWriting)
  129. {
  130. const DirFunctions **i;
  131. for (i = dirFunctions; *i != NULL; i++)
  132. {
  133. if ((*i)->isArchive(d, forWriting))
  134. return( (*i)->openArchive(d, forWriting) );
  135. } /* for */
  136. __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
  137. return(NULL);
  138. } /* openDirectory */
  139. static DirInfo *buildDirInfo(const char *newDir, int forWriting)
  140. {
  141. DirHandle *dirHandle = NULL;
  142. DirInfo *di = NULL;
  143. BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
  144. dirHandle = openDirectory(newDir, forWriting);
  145. BAIL_IF_MACRO(dirHandle == NULL, NULL, 0);
  146. di = (DirInfo *) malloc(sizeof (DirInfo));
  147. if (di == NULL)
  148. dirHandle->funcs->dirClose(dirHandle);
  149. BAIL_IF_MACRO(di == NULL, ERR_OUT_OF_MEMORY, 0);
  150. di->dirName = (char *) malloc(strlen(newDir) + 1);
  151. if (di->dirName == NULL)
  152. {
  153. free(di);
  154. dirHandle->funcs->dirClose(dirHandle);
  155. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  156. return(0);
  157. } /* if */
  158. di->next = NULL;
  159. di->dirHandle = dirHandle;
  160. strcpy(di->dirName, newDir);
  161. return(di);
  162. } /* buildDirInfo */
  163. static int freeDirInfo(DirInfo *di, FileHandleList *openList)
  164. {
  165. FileHandleList *i;
  166. if (di == NULL)
  167. return(1);
  168. for (i = openList; i != NULL; i = i->next)
  169. {
  170. const DirHandle *h = ((FileHandle *) i->handle->opaque)->dirHandle;
  171. BAIL_IF_MACRO(h == di->dirHandle, ERR_FILES_STILL_OPEN, 0);
  172. } /* for */
  173. di->dirHandle->funcs->dirClose(di->dirHandle);
  174. free(di->dirName);
  175. free(di);
  176. return(1);
  177. } /* freeDirInfo */
  178. static char *calculateUserDir(void)
  179. {
  180. char *retval = NULL;
  181. const char *str = NULL;
  182. str = __PHYSFS_platformGetUserDir();
  183. if (str != NULL)
  184. retval = (char *) str;
  185. else
  186. {
  187. const char *dirsep = PHYSFS_getDirSeparator();
  188. const char *uname = __PHYSFS_platformGetUserName();
  189. str = (uname != NULL) ? uname : "default";
  190. retval = (char *) malloc(strlen(baseDir) + strlen(str) +
  191. (strlen(dirsep) * 2) + 6);
  192. if (retval == NULL)
  193. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  194. else
  195. sprintf(retval, "%s%susers%s%s", baseDir, dirsep, dirsep, str);
  196. if (uname != NULL)
  197. free((void *) uname);
  198. } /* else */
  199. return(retval);
  200. } /* calculateUserDir */
  201. static char *calculateBaseDir(const char *argv0)
  202. {
  203. assert(0); return(NULL);
  204. } /* calculateBaseDir */
  205. int PHYSFS_init(const char *argv0)
  206. {
  207. BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
  208. BAIL_IF_MACRO(argv0 == NULL, ERR_INVALID_ARGUMENT, 0);
  209. baseDir = calculateBaseDir(argv0);
  210. BAIL_IF_MACRO(baseDir == NULL, NULL, 0);
  211. userDir = calculateUserDir();
  212. if (userDir == NULL)
  213. {
  214. free(baseDir);
  215. baseDir = NULL;
  216. return(0);
  217. } /* if */
  218. initialized = 1;
  219. return(1);
  220. } /* PHYSFS_init */
  221. static int closeFileHandleList(FileHandleList **list)
  222. {
  223. FileHandleList *i;
  224. FileHandleList *next = NULL;
  225. FileHandle *h;
  226. for (i = *list; i != NULL; i = next)
  227. {
  228. next = i->next;
  229. h = (FileHandle *) (i->handle->opaque);
  230. if (!h->funcs->fileClose(i->handle->opaque))
  231. {
  232. *list = i;
  233. return(0);
  234. } /* if */
  235. free(i->handle);
  236. free(i);
  237. } /* for */
  238. *list = NULL;
  239. return(1);
  240. } /* closeFileHandleList */
  241. static void freeSearchPath(void)
  242. {
  243. DirInfo *i;
  244. DirInfo *next = NULL;
  245. closeFileHandleList(&openReadList);
  246. if (searchPath != NULL)
  247. {
  248. for (i = searchPath; i != NULL; i = next)
  249. {
  250. next = i;
  251. freeDirInfo(i, openReadList);
  252. } /* for */
  253. searchPath = NULL;
  254. } /* if */
  255. } /* freeSearchPath */
  256. int PHYSFS_deinit(void)
  257. {
  258. BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
  259. closeFileHandleList(&openWriteList);
  260. BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), ERR_FILES_STILL_OPEN, 0);
  261. freeSearchPath();
  262. freeErrorMessages();
  263. if (baseDir != NULL)
  264. {
  265. free(baseDir);
  266. baseDir = NULL;
  267. } /* if */
  268. if (userDir != NULL)
  269. {
  270. free(userDir);
  271. userDir = NULL;
  272. } /* if */
  273. allowSymLinks = 0;
  274. initialized = 0;
  275. return(1);
  276. } /* PHYSFS_deinit */
  277. const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
  278. {
  279. return(supported_types);
  280. } /* PHYSFS_supportedArchiveTypes */
  281. void PHYSFS_freeList(void *list)
  282. {
  283. void **i;
  284. for (i = (void **) list; *i != NULL; i++)
  285. free(*i);
  286. free(list);
  287. } /* PHYSFS_freeList */
  288. const char *PHYSFS_getDirSeparator(void)
  289. {
  290. return(__PHYSFS_platformDirSeparator);
  291. } /* PHYSFS_getDirSeparator */
  292. char **PHYSFS_getCdRomDirs(void)
  293. {
  294. return(__PHYSFS_platformDetectAvailableCDs());
  295. } /* PHYSFS_getCdRomDirs */
  296. const char *PHYSFS_getBaseDir(void)
  297. {
  298. return(baseDir); /* this is calculated in PHYSFS_init()... */
  299. } /* PHYSFS_getBaseDir */
  300. const char *PHYSFS_getUserDir(void)
  301. {
  302. return(userDir); /* this is calculated in PHYSFS_init()... */
  303. } /* PHYSFS_getUserDir */
  304. const char *PHYSFS_getWriteDir(void)
  305. {
  306. if (writeDir == NULL)
  307. return(NULL);
  308. return(writeDir->dirName);
  309. } /* PHYSFS_getWriteDir */
  310. int PHYSFS_setWriteDir(const char *newDir)
  311. {
  312. if (writeDir != NULL)
  313. {
  314. BAIL_IF_MACRO(!freeDirInfo(writeDir, openWriteList), NULL, 0);
  315. writeDir = NULL;
  316. } /* if */
  317. if (newDir != NULL)
  318. {
  319. writeDir = buildDirInfo(newDir, 1);
  320. return(writeDir != NULL);
  321. } /* if */
  322. return(1);
  323. } /* PHYSFS_setWriteDir */
  324. int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
  325. {
  326. DirInfo *di = buildDirInfo(newDir, 0);
  327. BAIL_IF_MACRO(di == NULL, NULL, 0);
  328. if (appendToPath)
  329. {
  330. di->next = searchPath;
  331. searchPath = di;
  332. } /* if */
  333. else
  334. {
  335. DirInfo *i = searchPath;
  336. DirInfo *prev = NULL;
  337. di->next = NULL;
  338. while (i != NULL)
  339. prev = i;
  340. if (prev == NULL)
  341. searchPath = di;
  342. else
  343. prev->next = di;
  344. } /* else */
  345. return(1);
  346. } /* PHYSFS_addToSearchPath */
  347. int PHYSFS_removeFromSearchPath(const char *oldDir)
  348. {
  349. DirInfo *i;
  350. DirInfo *prev = NULL;
  351. DirInfo *next = NULL;
  352. BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
  353. for (i = searchPath; i != NULL; i = i->next)
  354. {
  355. if (strcmp(i->dirName, oldDir) == 0)
  356. {
  357. next = i->next;
  358. BAIL_IF_MACRO(!freeDirInfo(i, openReadList), NULL, 0);
  359. if (prev == NULL)
  360. searchPath = next;
  361. else
  362. prev->next = next;
  363. return(1);
  364. } /* if */
  365. prev = i;
  366. } /* for */
  367. __PHYSFS_setError(ERR_NOT_IN_SEARCH_PATH);
  368. return(0);
  369. } /* PHYSFS_removeFromSearchPath */
  370. char **PHYSFS_getSearchPath(void)
  371. {
  372. int count = 1;
  373. int x;
  374. DirInfo *i;
  375. char **retval;
  376. for (i = searchPath; i != NULL; i = i->next)
  377. count++;
  378. retval = (char **) malloc(sizeof (char *) * count);
  379. BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
  380. count--;
  381. retval[count] = NULL;
  382. for (i = searchPath, x = 0; x < count; i = i->next, x++)
  383. {
  384. retval[x] = (char *) malloc(strlen(i->dirName) + 1);
  385. if (retval[x] == NULL) /* this is friggin' ugly. */
  386. {
  387. while (x > 0)
  388. {
  389. x--;
  390. free(retval[x]);
  391. } /* while */
  392. free(retval);
  393. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  394. return(NULL);
  395. } /* if */
  396. strcpy(retval[x], i->dirName);
  397. } /* for */
  398. return(retval);
  399. } /* PHYSFS_getSearchPath */
  400. int PHYSFS_setSaneConfig(const char *appName, const char *archiveExt,
  401. int includeCdRoms, int archivesFirst)
  402. {
  403. const char *basedir = PHYSFS_getBaseDir();
  404. const char *userdir = PHYSFS_getUserDir();
  405. const char *dirsep = PHYSFS_getDirSeparator();
  406. char *str;
  407. int rc;
  408. /* set write dir... */
  409. str = malloc(strlen(userdir) + (strlen(appName) * 2) +
  410. (strlen(dirsep) * 2) + 2);
  411. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  412. sprintf(str, "%s%s.%s", userdir, dirsep, appName);
  413. rc = PHYSFS_setWriteDir(str);
  414. BAIL_IF_MACRO(!rc, NULL, 0);
  415. /* Put write dir related dirs on search path... */
  416. PHYSFS_addToSearchPath(str, 1);
  417. PHYSFS_mkdir(appName); /* don't care if this fails. */
  418. strcat(str, dirsep);
  419. strcat(str, appName);
  420. PHYSFS_addToSearchPath(str, 1);
  421. free(str);
  422. /* Put base path stuff on search path... */
  423. PHYSFS_addToSearchPath(basedir, 1);
  424. str = malloc(strlen(basedir) + (strlen(appName) * 2) +
  425. (strlen(dirsep) * 2) + 2);
  426. if (str != NULL)
  427. {
  428. sprintf(str, "%s%s.%s", basedir, dirsep, appName);
  429. PHYSFS_addToSearchPath(str, 1);
  430. free(str);
  431. } /* if */
  432. /* handle CD-ROMs... */
  433. if (includeCdRoms)
  434. {
  435. char **cds = PHYSFS_getCdRomDirs();
  436. char **i;
  437. for (i = cds; *i != NULL; i++)
  438. {
  439. PHYSFS_addToSearchPath(*i, 1);
  440. str = malloc(strlen(*i) + strlen(appName) + strlen(dirsep) + 1);
  441. if (str != NULL)
  442. {
  443. sprintf(str, "%s%s%s", *i, dirsep, appName);
  444. PHYSFS_addToSearchPath(str, 1);
  445. free(str);
  446. } /* if */
  447. } /* for */
  448. PHYSFS_freeList(cds);
  449. } /* if */
  450. /* Root out archives, and add them to search path... */
  451. if (archiveExt != NULL)
  452. {
  453. char **rc = PHYSFS_enumerateFiles("");
  454. char **i;
  455. int extlen = strlen(archiveExt);
  456. char *ext;
  457. for (i = rc; *i != NULL; i++)
  458. {
  459. int l = strlen(*i);
  460. if ((l > extlen) && ((*i)[l - extlen - 1] == '.'));
  461. {
  462. ext = (*i) + (l - extlen);
  463. if (__PHYSFS_platformStricmp(ext, archiveExt) == 0)
  464. {
  465. const char *d = PHYSFS_getRealDir(*i);
  466. str = malloc(strlen(d) + strlen(dirsep) + l + 1);
  467. if (str != NULL)
  468. {
  469. sprintf(str, "%s%s%s", d, dirsep, *i);
  470. PHYSFS_addToSearchPath(str, archivesFirst == 0);
  471. free(str);
  472. } /* if */
  473. } /* if */
  474. } /* if */
  475. } /* for */
  476. PHYSFS_freeList(rc);
  477. } /* if */
  478. return(1);
  479. } /* PHYSFS_setSaneConfig */
  480. void PHYSFS_permitSymbolicLinks(int allow)
  481. {
  482. allowSymLinks = allow;
  483. } /* PHYSFS_permitSymbolicLinks */
  484. /* string manipulation in C makes my ass itch. */
  485. char *__PHYSFS_convertToDependent(const char *prepend,
  486. const char *dirName,
  487. const char *append)
  488. {
  489. const char *dirsep = PHYSFS_getDirSeparator();
  490. int sepsize = strlen(dirsep);
  491. char *str;
  492. char *i1;
  493. char *i2;
  494. size_t allocSize;
  495. allocSize = strlen(dirName) + 1;
  496. if (prepend != NULL)
  497. allocSize += strlen(prepend) + sepsize;
  498. if (append != NULL)
  499. allocSize += strlen(append) + sepsize;
  500. /* make sure there's enough space if the dir separator is bigger. */
  501. if (sepsize > 1)
  502. {
  503. str = (char *) dirName;
  504. do
  505. {
  506. str = strchr(str, '/');
  507. if (str != NULL)
  508. {
  509. allocSize += (sepsize - 1);
  510. str++;
  511. } /* if */
  512. } while (str != NULL);
  513. } /* if */
  514. str = (char *) malloc(allocSize);
  515. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, NULL);
  516. if (prepend == NULL)
  517. *str = '\0';
  518. else
  519. {
  520. strcpy(str, prepend);
  521. strcat(str, dirsep);
  522. } /* else */
  523. for (i1 = (char *) dirName, i2 = str + strlen(str); *i1; i1++, i2++)
  524. {
  525. if (*i1 == '/')
  526. {
  527. strcpy(i2, dirsep);
  528. i2 += sepsize;
  529. } /* if */
  530. else
  531. {
  532. *i2 = *i1;
  533. } /* else */
  534. } /* for */
  535. *i2 = '\0';
  536. if (append)
  537. {
  538. strcat(str, dirsep);
  539. strcpy(str, append);
  540. } /* if */
  541. return(str);
  542. } /* __PHYSFS_convertToDependentNotation */
  543. int __PHYSFS_verifySecurity(DirHandle *h, const char *fname)
  544. {
  545. int retval = 1;
  546. char *start;
  547. char *end;
  548. char *str;
  549. start = str = malloc(strlen(fname) + 1);
  550. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  551. strcpy(str, fname);
  552. while (1)
  553. {
  554. end = strchr(start, '/');
  555. if (end != NULL)
  556. *end = '\0';
  557. if ( (strcmp(start, ".") == 0) ||
  558. (strcmp(start, "..") == 0) ||
  559. (strchr(start, '\\') != NULL) ||
  560. (strchr(start, ':') != NULL) )
  561. {
  562. __PHYSFS_setError(ERR_INSECURE_FNAME);
  563. retval = 0;
  564. break;
  565. } /* if */
  566. if ((!allowSymLinks) && (h->funcs->isSymLink(h, str)))
  567. {
  568. __PHYSFS_setError(ERR_SYMLINK_DISALLOWED);
  569. retval = 0;
  570. break;
  571. } /* if */
  572. if (end == NULL)
  573. break;
  574. *end = '/';
  575. start = end + 1;
  576. } /* while */
  577. free(str);
  578. return(retval);
  579. } /* __PHYSFS_verifySecurity */
  580. int PHYSFS_mkdir(const char *dirName)
  581. {
  582. DirHandle *h;
  583. char *str;
  584. char *start;
  585. char *end;
  586. int retval = 0;
  587. BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, 0);
  588. h = writeDir->dirHandle;
  589. BAIL_IF_MACRO(h->funcs->mkdir == NULL, ERR_NOT_SUPPORTED, 0);
  590. BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, dirName), NULL, 0);
  591. start = str = malloc(strlen(dirName) + 1);
  592. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  593. strcpy(str, dirName);
  594. while (1)
  595. {
  596. end = strchr(start, '/');
  597. if (end != NULL)
  598. *end = '\0';
  599. retval = h->funcs->mkdir(h, str);
  600. if (!retval)
  601. break;
  602. if (end == NULL)
  603. break;
  604. *end = '/';
  605. start = end + 1;
  606. } /* while */
  607. free(str);
  608. return(retval);
  609. } /* PHYSFS_mkdir */
  610. int PHYSFS_delete(const char *fname)
  611. {
  612. DirHandle *h;
  613. BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, 0);
  614. h = writeDir->dirHandle;
  615. BAIL_IF_MACRO(h->funcs->remove == NULL, ERR_NOT_SUPPORTED, 0);
  616. BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, fname), NULL, 0);
  617. return(h->funcs->remove(h, fname));
  618. } /* PHYSFS_delete */
  619. const char *PHYSFS_getRealDir(const char *filename)
  620. {
  621. DirInfo *i;
  622. for (i = searchPath; i != NULL; i = i->next)
  623. {
  624. DirHandle *h = i->dirHandle;
  625. if (__PHYSFS_verifySecurity(h, filename))
  626. {
  627. if (h->funcs->exists(h, filename))
  628. return(i->dirName);
  629. } /* if */
  630. } /* for */
  631. return(NULL);
  632. } /* PHYSFS_getRealDir */
  633. static int countList(LinkedStringList *list)
  634. {
  635. int retval = 0;
  636. LinkedStringList *i;
  637. assert(list != NULL);
  638. for (i = list; i != NULL; i = i->next)
  639. retval++;
  640. return(retval);
  641. } /* countList */
  642. static char **convertStringListToPhysFSList(LinkedStringList *finalList)
  643. {
  644. int i;
  645. LinkedStringList *next = NULL;
  646. int len = countList(finalList);
  647. char **retval = (char **) malloc((len + 1) * sizeof (char *));
  648. if (retval == NULL)
  649. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  650. for (i = 0; i < len; i++)
  651. {
  652. next = finalList->next;
  653. if (retval == NULL)
  654. free(finalList->str);
  655. else
  656. retval[i] = finalList->str;
  657. free(finalList);
  658. finalList = next;
  659. } /* for */
  660. if (retval != NULL);
  661. retval[i] = NULL;
  662. return(retval);
  663. } /* convertStringListToPhysFSList */
  664. static void insertStringListItem(LinkedStringList **final,
  665. LinkedStringList *item)
  666. {
  667. LinkedStringList *i;
  668. LinkedStringList *prev = NULL;
  669. int rc;
  670. for (i = *final; i != NULL; i = i->next)
  671. {
  672. rc = strcmp(i->str, item->str);
  673. if (rc == 0) /* already in list. */
  674. {
  675. free(item->str);
  676. free(item);
  677. return;
  678. } /* if */
  679. else if (rc > 0) /* insertion point. */
  680. {
  681. if (prev == NULL)
  682. *final = item;
  683. else
  684. prev->next = item;
  685. item->next = i;
  686. return;
  687. } /* else if */
  688. prev = i;
  689. } /* for */
  690. } /* insertStringListItem */
  691. /* if we run out of memory anywhere in here, we give back what we can. */
  692. static void interpolateStringLists(LinkedStringList **final,
  693. LinkedStringList *newList)
  694. {
  695. LinkedStringList *next = NULL;
  696. while (newList != NULL)
  697. {
  698. next = newList->next;
  699. insertStringListItem(final, newList);
  700. newList = next;
  701. } /* while */
  702. } /* interpolateStringLists */
  703. char **PHYSFS_enumerateFiles(const char *path)
  704. {
  705. DirInfo *i;
  706. char **retval = NULL;
  707. LinkedStringList *rc;
  708. LinkedStringList *finalList = NULL;
  709. for (i = searchPath; i != NULL; i = i->next)
  710. {
  711. DirHandle *h = i->dirHandle;
  712. if (__PHYSFS_verifySecurity(h, path))
  713. {
  714. rc = h->funcs->enumerateFiles(h, path);
  715. interpolateStringLists(&finalList, rc);
  716. } /* if */
  717. } /* for */
  718. retval = convertStringListToPhysFSList(finalList);
  719. return(retval);
  720. } /* PHYSFS_enumerateFiles */
  721. int PHYSFS_exists(const char *fname)
  722. {
  723. return(PHYSFS_getRealDir(fname) != NULL);
  724. } /* PHYSFS_exists */
  725. int PHYSFS_isDirectory(const char *fname)
  726. {
  727. DirInfo *i;
  728. for (i = searchPath; i != NULL; i = i->next)
  729. {
  730. DirHandle *h = i->dirHandle;
  731. if (__PHYSFS_verifySecurity(h, fname))
  732. {
  733. if (h->funcs->exists(h, fname))
  734. return(h->funcs->isDirectory(h, fname));
  735. } /* if */
  736. } /* for */
  737. return(0);
  738. } /* PHYSFS_isDirectory */
  739. int PHYSFS_isSymbolicLink(const char *fname)
  740. {
  741. DirInfo *i;
  742. if (!allowSymLinks)
  743. return(0);
  744. for (i = searchPath; i != NULL; i = i->next)
  745. {
  746. DirHandle *h = i->dirHandle;
  747. if (__PHYSFS_verifySecurity(h, fname))
  748. {
  749. if (h->funcs->exists(h, fname))
  750. return(h->funcs->isSymLink(h, fname));
  751. } /* if */
  752. } /* for */
  753. return(0);
  754. } /* PHYSFS_isSymbolicLink */
  755. static PHYSFS_file *doOpenWrite(const char *fname, int appending)
  756. {
  757. PHYSFS_file *retval = (PHYSFS_file *) malloc(sizeof (PHYSFS_file));
  758. FileHandle *rc = NULL;
  759. DirHandle *h = (writeDir == NULL) ? NULL : writeDir->dirHandle;
  760. const DirFunctions *f = (h == NULL) ? NULL : h->funcs;
  761. FileHandleList *list;
  762. BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
  763. BAIL_IF_MACRO(!h, ERR_NO_WRITE_DIR, NULL);
  764. BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, fname), NULL, NULL);
  765. list = (FileHandleList *) malloc(sizeof (FileHandleList));
  766. BAIL_IF_MACRO(!list, ERR_OUT_OF_MEMORY, NULL);
  767. rc = (appending) ? f->openAppend(h, fname) : f->openWrite(h, fname);
  768. if (rc == NULL)
  769. {
  770. free(list);
  771. free(retval);
  772. retval = NULL;
  773. } /* if */
  774. else
  775. {
  776. retval->opaque = (void *) rc;
  777. list->handle = retval;
  778. list->next = openWriteList;
  779. openWriteList = list;
  780. } /* else */
  781. return(retval);
  782. } /* doOpenWrite */
  783. PHYSFS_file *PHYSFS_openWrite(const char *filename)
  784. {
  785. return(doOpenWrite(filename, 0));
  786. } /* PHYSFS_openWrite */
  787. PHYSFS_file *PHYSFS_openAppend(const char *filename)
  788. {
  789. return(doOpenWrite(filename, 1));
  790. } /* PHYSFS_openAppend */
  791. PHYSFS_file *PHYSFS_openRead(const char *fname)
  792. {
  793. PHYSFS_file *retval = (PHYSFS_file *) malloc(sizeof (PHYSFS_file));
  794. FileHandle *rc = NULL;
  795. FileHandleList *list;
  796. DirInfo *i;
  797. BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
  798. list = (FileHandleList *) malloc(sizeof (FileHandleList));
  799. BAIL_IF_MACRO(!list, ERR_OUT_OF_MEMORY, NULL);
  800. for (i = searchPath; i != NULL; i = i->next)
  801. {
  802. DirHandle *h = i->dirHandle;
  803. if (__PHYSFS_verifySecurity(h, fname))
  804. {
  805. rc = h->funcs->openRead(h, fname);
  806. if (rc != NULL)
  807. break;
  808. } /* if */
  809. } /* for */
  810. if (rc == NULL)
  811. {
  812. free(list);
  813. free(retval);
  814. retval = NULL;
  815. } /* if */
  816. else
  817. {
  818. retval->opaque = (void *) rc;
  819. list->handle = retval;
  820. list->next = openReadList;
  821. openReadList = list;
  822. } /* else */
  823. return(retval);
  824. } /* PHYSFS_openRead */
  825. int PHYSFS_close(PHYSFS_file *handle)
  826. {
  827. FileHandle *h = (FileHandle *) handle->opaque;
  828. FileHandleList *i;
  829. FileHandleList *prev;
  830. FileHandleList **_lists[] = { &openWriteList, &openReadList, NULL };
  831. FileHandleList ***lists = _lists; /* gay. */
  832. int rc;
  833. while (lists != NULL)
  834. {
  835. for (i = *(*lists), prev = NULL; i != NULL; prev = i, i = i->next)
  836. {
  837. if (i->handle == handle)
  838. {
  839. rc = h->funcs->fileClose(h);
  840. if (!rc)
  841. return(0);
  842. if (prev == NULL)
  843. *(*lists) = i->next;
  844. else
  845. prev->next = i->next;
  846. free(handle);
  847. free(i);
  848. return(1);
  849. } /* if */
  850. } /* for */
  851. lists++;
  852. } /* while */
  853. __PHYSFS_setError(ERR_NOT_A_HANDLE);
  854. return(0);
  855. } /* PHYSFS_close */
  856. int PHYSFS_read(PHYSFS_file *handle, void *buffer,
  857. unsigned int objSize, unsigned int objCount)
  858. {
  859. FileHandle *h = (FileHandle *) handle->opaque;
  860. assert(h != NULL);
  861. assert(h->funcs != NULL);
  862. BAIL_IF_MACRO(h->funcs->read == NULL, ERR_NOT_SUPPORTED, -1);
  863. return(h->funcs->read(h, buffer, objSize, objCount));
  864. } /* PHYSFS_read */
  865. int PHYSFS_write(PHYSFS_file *handle, void *buffer,
  866. unsigned int objSize, unsigned int objCount)
  867. {
  868. FileHandle *h = (FileHandle *) handle->opaque;
  869. assert(h != NULL);
  870. assert(h->funcs != NULL);
  871. BAIL_IF_MACRO(h->funcs->write == NULL, ERR_NOT_SUPPORTED, -1);
  872. return(h->funcs->write(h, buffer, objSize, objCount));
  873. } /* PHYSFS_write */
  874. int PHYSFS_eof(PHYSFS_file *handle)
  875. {
  876. FileHandle *h = (FileHandle *) handle->opaque;
  877. assert(h != NULL);
  878. assert(h->funcs != NULL);
  879. BAIL_IF_MACRO(h->funcs->eof == NULL, ERR_NOT_SUPPORTED, -1);
  880. return(h->funcs->eof(h));
  881. } /* PHYSFS_eof */
  882. int PHYSFS_tell(PHYSFS_file *handle)
  883. {
  884. FileHandle *h = (FileHandle *) handle->opaque;
  885. assert(h != NULL);
  886. assert(h->funcs != NULL);
  887. BAIL_IF_MACRO(h->funcs->tell == NULL, ERR_NOT_SUPPORTED, -1);
  888. return(h->funcs->tell(h));
  889. } /* PHYSFS_tell */
  890. int PHYSFS_seek(PHYSFS_file *handle, int pos)
  891. {
  892. FileHandle *h = (FileHandle *) handle->opaque;
  893. assert(h != NULL);
  894. assert(h->funcs != NULL);
  895. BAIL_IF_MACRO(h->funcs->seek == NULL, ERR_NOT_SUPPORTED, 0);
  896. return(h->funcs->seek(h, pos));
  897. } /* PHYSFS_seek */
  898. /* end of physfs.c ... */