physfs.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  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->close(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->close(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->close(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->close(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_convertToDependentNotation(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. *str = '\0';
  517. if (prepend)
  518. {
  519. strcpy(str, prepend);
  520. strcat(str, dirsep);
  521. } /* if */
  522. for (i1 = (char *) dirName, i2 = str + strlen(str); *i1; i1++, i2++)
  523. {
  524. if (*i1 == '/')
  525. {
  526. strcpy(i2, dirsep);
  527. i2 += sepsize;
  528. } /* if */
  529. else
  530. {
  531. *i2 = *i1;
  532. } /* else */
  533. } /* for */
  534. *i2 = '\0';
  535. if (append)
  536. {
  537. strcat(str, dirsep);
  538. strcpy(str, append);
  539. } /* if */
  540. return(str);
  541. } /* __PHYSFS_convertToDependentNotation */
  542. int __PHYSFS_verifySecurity(DirHandle *h, const char *fname)
  543. {
  544. int retval = 1;
  545. char *start;
  546. char *end;
  547. char *str;
  548. start = str = malloc(strlen(fname) + 1);
  549. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  550. strcpy(str, fname);
  551. while (1)
  552. {
  553. end = strchr(start, '/');
  554. if (end != NULL)
  555. *end = '\0';
  556. if ( (strcmp(start, ".") == 0) ||
  557. (strcmp(start, "..") == 0) ||
  558. (strchr(start, ':') != NULL) )
  559. {
  560. __PHYSFS_setError(ERR_INSECURE_FNAME);
  561. retval = 0;
  562. break;
  563. } /* if */
  564. if ((!allowSymLinks) && (h->funcs->isSymLink(h, str)))
  565. {
  566. __PHYSFS_setError(ERR_SYMLINK_DISALLOWED);
  567. retval = 0;
  568. break;
  569. } /* if */
  570. if (end == NULL)
  571. break;
  572. *end = '/';
  573. start = end + 1;
  574. } /* while */
  575. free(str);
  576. return(retval);
  577. } /* __PHYSFS_verifySecurity */
  578. int PHYSFS_mkdir(const char *dirName)
  579. {
  580. DirHandle *h;
  581. char *str;
  582. char *start;
  583. char *end;
  584. int retval = 0;
  585. BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, 0);
  586. h = writeDir->dirHandle;
  587. BAIL_IF_MACRO(h->funcs->mkdir == NULL, ERR_NOT_SUPPORTED, 0);
  588. BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, dirName), NULL, 0);
  589. start = str = malloc(strlen(dirName) + 1);
  590. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  591. strcpy(str, dirName);
  592. while (1)
  593. {
  594. end = strchr(start, '/');
  595. if (end != NULL)
  596. *end = '\0';
  597. retval = h->funcs->mkdir(h, str);
  598. if (!retval)
  599. break;
  600. if (end == NULL)
  601. break;
  602. *end = '/';
  603. start = end + 1;
  604. } /* while */
  605. free(str);
  606. return(retval);
  607. } /* PHYSFS_mkdir */
  608. int PHYSFS_delete(const char *fname)
  609. {
  610. DirHandle *h;
  611. BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, 0);
  612. h = writeDir->dirHandle;
  613. BAIL_IF_MACRO(h->funcs->remove == NULL, ERR_NOT_SUPPORTED, 0);
  614. BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, fname), NULL, 0);
  615. return(h->funcs->remove(h, fname));
  616. } /* PHYSFS_delete */
  617. const char *PHYSFS_getRealDir(const char *filename)
  618. {
  619. DirInfo *i;
  620. for (i = searchPath; i != NULL; i = i->next)
  621. {
  622. DirHandle *h = i->dirHandle;
  623. if (__PHYSFS_verifySecurity(h, filename))
  624. {
  625. if (h->funcs->exists(h, filename))
  626. return(i->dirName);
  627. } /* if */
  628. } /* for */
  629. return(NULL);
  630. } /* PHYSFS_getRealDir */
  631. static int countList(LinkedStringList *list)
  632. {
  633. int retval = 0;
  634. LinkedStringList *i;
  635. assert(list != NULL);
  636. for (i = list; i != NULL; i = i->next)
  637. retval++;
  638. return(retval);
  639. } /* countList */
  640. static char **convertStringListToPhysFSList(LinkedStringList *finalList)
  641. {
  642. int i;
  643. LinkedStringList *next = NULL;
  644. int len = countList(finalList);
  645. char **retval = (char **) malloc((len + 1) * sizeof (char *));
  646. if (retval == NULL)
  647. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  648. for (i = 0; i < len; i++)
  649. {
  650. next = finalList->next;
  651. if (retval == NULL)
  652. free(finalList->str);
  653. else
  654. retval[i] = finalList->str;
  655. free(finalList);
  656. finalList = next;
  657. } /* for */
  658. if (retval != NULL);
  659. retval[i] = NULL;
  660. return(retval);
  661. } /* convertStringListToPhysFSList */
  662. static void insertStringListItem(LinkedStringList **final,
  663. LinkedStringList *item)
  664. {
  665. LinkedStringList *i;
  666. LinkedStringList *prev = NULL;
  667. int rc;
  668. for (i = *final; i != NULL; i = i->next)
  669. {
  670. rc = strcmp(i->str, item->str);
  671. if (rc == 0) /* already in list. */
  672. {
  673. free(item->str);
  674. free(item);
  675. return;
  676. } /* if */
  677. else if (rc > 0) /* insertion point. */
  678. {
  679. if (prev == NULL)
  680. *final = item;
  681. else
  682. prev->next = item;
  683. item->next = i;
  684. return;
  685. } /* else if */
  686. prev = i;
  687. } /* for */
  688. } /* insertStringListItem */
  689. /* if we run out of memory anywhere in here, we give back what we can. */
  690. static void interpolateStringLists(LinkedStringList **final,
  691. LinkedStringList *newList)
  692. {
  693. LinkedStringList *next = NULL;
  694. while (newList != NULL)
  695. {
  696. next = newList->next;
  697. insertStringListItem(final, newList);
  698. newList = next;
  699. } /* while */
  700. } /* interpolateStringLists */
  701. char **PHYSFS_enumerateFiles(const char *path)
  702. {
  703. DirInfo *i;
  704. char **retval = NULL;
  705. LinkedStringList *rc;
  706. LinkedStringList *finalList = NULL;
  707. for (i = searchPath; i != NULL; i = i->next)
  708. {
  709. DirHandle *h = i->dirHandle;
  710. if (__PHYSFS_verifySecurity(h, path))
  711. {
  712. rc = h->funcs->enumerateFiles(h, path);
  713. interpolateStringLists(&finalList, rc);
  714. } /* if */
  715. } /* for */
  716. retval = convertStringListToPhysFSList(finalList);
  717. return(retval);
  718. } /* PHYSFS_enumerateFiles */
  719. int PHYSFS_exists(const char *fname)
  720. {
  721. return(PHYSFS_getRealDir(fname) != NULL);
  722. } /* PHYSFS_exists */
  723. int PHYSFS_isDirectory(const char *fname)
  724. {
  725. DirInfo *i;
  726. for (i = searchPath; i != NULL; i = i->next)
  727. {
  728. DirHandle *h = i->dirHandle;
  729. if (__PHYSFS_verifySecurity(h, fname))
  730. {
  731. if (h->funcs->exists(h, fname))
  732. return(h->funcs->isDirectory(h, fname));
  733. } /* if */
  734. } /* for */
  735. return(0);
  736. } /* PHYSFS_isDirectory */
  737. int PHYSFS_isSymbolicLink(const char *fname)
  738. {
  739. DirInfo *i;
  740. if (!allowSymLinks)
  741. return(0);
  742. for (i = searchPath; i != NULL; i = i->next)
  743. {
  744. DirHandle *h = i->dirHandle;
  745. if (__PHYSFS_verifySecurity(h, fname))
  746. {
  747. if (h->funcs->exists(h, fname))
  748. return(h->funcs->isSymLink(h, fname));
  749. } /* if */
  750. } /* for */
  751. return(0);
  752. } /* PHYSFS_isSymbolicLink */
  753. /**
  754. * Open a file for writing, in platform-independent notation and in relation
  755. * to the write path as the root of the writable filesystem. The specified
  756. * file is created if it doesn't exist. If it does exist, it is truncated to
  757. * zero bytes, and the writing offset is set to the start.
  758. *
  759. * @param filename File to open.
  760. * @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  761. * of the error can be gleaned from PHYSFS_getLastError().
  762. */
  763. PHYSFS_file *PHYSFS_openWrite(const char *filename)
  764. {
  765. return NULL;
  766. } /* PHYSFS_openWrite */
  767. /**
  768. * Open a file for writing, in platform-independent notation and in relation
  769. * to the write path as the root of the writable filesystem. The specified
  770. * file is created if it doesn't exist. If it does exist, the writing offset
  771. * is set to the end of the file, so the first write will be the byte after
  772. * the end.
  773. *
  774. * @param filename File to open.
  775. * @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  776. * of the error can be gleaned from PHYSFS_getLastError().
  777. */
  778. PHYSFS_file *PHYSFS_openAppend(const char *filename)
  779. {
  780. return NULL;
  781. } /* PHYSFS_openAppend */
  782. /**
  783. * Open a file for reading, in platform-independent notation. The search path
  784. * is checked one at a time until a matching file is found, in which case an
  785. * abstract filehandle is associated with it, and reading may be done.
  786. * The reading offset is set to the first byte of the file.
  787. *
  788. * @param filename File to open.
  789. * @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  790. * of the error can be gleaned from PHYSFS_getLastError().
  791. */
  792. PHYSFS_file *PHYSFS_openRead(const char *filename)
  793. {
  794. return NULL;
  795. } /* PHYSFS_openRead */
  796. int PHYSFS_close(PHYSFS_file *handle)
  797. {
  798. FileHandle *h = (FileHandle *) handle->opaque;
  799. FileHandleList *i;
  800. FileHandleList *prev;
  801. FileHandleList **_lists[] = { &openWriteList, &openReadList, NULL };
  802. FileHandleList ***lists = _lists; /* gay. */
  803. int rc;
  804. while (lists != NULL)
  805. {
  806. for (i = *(*lists), prev = NULL; i != NULL; prev = i, i = i->next)
  807. {
  808. if (((FileHandle *) i->handle->opaque) == h)
  809. {
  810. rc = h->funcs->close(h);
  811. if (!rc)
  812. return(0);
  813. if (prev == NULL)
  814. *(*lists) = i->next;
  815. else
  816. prev->next = i->next;
  817. free(i);
  818. free(handle);
  819. return(1);
  820. } /* if */
  821. } /* for */
  822. lists++;
  823. } /* while */
  824. __PHYSFS_setError(ERR_NOT_A_HANDLE);
  825. return(0);
  826. } /* PHYSFS_close */
  827. int PHYSFS_read(PHYSFS_file *handle, void *buffer,
  828. unsigned int objSize, unsigned int objCount)
  829. {
  830. FileHandle *h = (FileHandle *) handle->opaque;
  831. assert(h != NULL);
  832. assert(h->funcs != NULL);
  833. BAIL_IF_MACRO(h->funcs->read == NULL, ERR_NOT_SUPPORTED, -1);
  834. return(h->funcs->read(h, buffer, objSize, objCount));
  835. } /* PHYSFS_read */
  836. int PHYSFS_write(PHYSFS_file *handle, void *buffer,
  837. unsigned int objSize, unsigned int objCount)
  838. {
  839. FileHandle *h = (FileHandle *) handle->opaque;
  840. assert(h != NULL);
  841. assert(h->funcs != NULL);
  842. BAIL_IF_MACRO(h->funcs->write == NULL, ERR_NOT_SUPPORTED, -1);
  843. return(h->funcs->write(h, buffer, objSize, objCount));
  844. } /* PHYSFS_write */
  845. int PHYSFS_eof(PHYSFS_file *handle)
  846. {
  847. FileHandle *h = (FileHandle *) handle->opaque;
  848. assert(h != NULL);
  849. assert(h->funcs != NULL);
  850. BAIL_IF_MACRO(h->funcs->eof == NULL, ERR_NOT_SUPPORTED, -1);
  851. return(h->funcs->eof(h));
  852. } /* PHYSFS_eof */
  853. int PHYSFS_tell(PHYSFS_file *handle)
  854. {
  855. FileHandle *h = (FileHandle *) handle->opaque;
  856. assert(h != NULL);
  857. assert(h->funcs != NULL);
  858. BAIL_IF_MACRO(h->funcs->tell == NULL, ERR_NOT_SUPPORTED, -1);
  859. return(h->funcs->tell(h));
  860. } /* PHYSFS_tell */
  861. int PHYSFS_seek(PHYSFS_file *handle, int pos)
  862. {
  863. FileHandle *h = (FileHandle *) handle->opaque;
  864. assert(h != NULL);
  865. assert(h->funcs != NULL);
  866. BAIL_IF_MACRO(h->funcs->seek == NULL, ERR_NOT_SUPPORTED, 0);
  867. return(h->funcs->seek(h, pos));
  868. } /* PHYSFS_seek */
  869. /* end of physfs.c ... */