archiver_iso9660.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /*
  2. * ISO9660 support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE.txt in the source's root directory.
  5. *
  6. * This file written by Christoph Nelles.
  7. */
  8. /* !!! FIXME: this file needs Ryanification. */
  9. /*
  10. * Handles CD-ROM disk images (and raw CD-ROM devices).
  11. *
  12. * Not supported:
  13. * - RockRidge
  14. * - Non 2048 Sectors
  15. * - UDF
  16. *
  17. * Deviations from the standard
  18. * - Ignores mandatory sort order
  19. * - Allows various invalid file names
  20. *
  21. * Problems
  22. * - Ambiguities in the standard
  23. */
  24. #if (defined PHYSFS_SUPPORTS_GRP)
  25. #define __PHYSICSFS_INTERNAL__
  26. #include "physfs_internal.h"
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <time.h>
  30. /* cache files smaller than this completely in memory */
  31. #define ISO9660_FULLCACHEMAXSIZE 2048
  32. /* !!! FIXME: this is going to cause trouble. */
  33. #pragma pack(push) /* push current alignment to stack */
  34. #pragma pack(1) /* set alignment to 1 byte boundary */
  35. /* This is the format as defined by the standard
  36. typedef struct
  37. {
  38. PHYSFS_uint32 lsb;
  39. PHYSFS_uint32 msb;
  40. } ISOBB32bit; // 32byte Both Byte type, means the value first in LSB then in MSB
  41. typedef struct
  42. {
  43. PHYSFS_uint16 lsb;
  44. PHYSFS_uint16 msb;
  45. } ISOBB16bit; // 16byte Both Byte type, means the value first in LSB then in MSB
  46. */
  47. /* define better ones to simplify coding (less if's) */
  48. #if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
  49. #define ISOBB32bit(name) PHYSFS_uint32 name; PHYSFS_uint32 __dummy_##name;
  50. #define ISOBB16bit(name) PHYSFS_uint16 name; PHYSFS_uint16 __dummy_##name;
  51. #else
  52. #define ISOBB32bit(name) PHYSFS_uint32 __dummy_##name; PHYSFS_uint32 name;
  53. #define ISOBB16bit(name) PHYSFS_uint16 __dummy_##name; PHYSFS_uint16 name;
  54. #endif
  55. typedef struct
  56. {
  57. char year[4];
  58. char month[2];
  59. char day[2];
  60. char hour[2];
  61. char minute[2];
  62. char second[2];
  63. char centisec[2];
  64. PHYSFS_sint8 offset; /* in 15min from GMT */
  65. } ISO9660VolumeTimestamp;
  66. typedef struct
  67. {
  68. PHYSFS_uint8 year;
  69. PHYSFS_uint8 month;
  70. PHYSFS_uint8 day;
  71. PHYSFS_uint8 hour;
  72. PHYSFS_uint8 minute;
  73. PHYSFS_uint8 second;
  74. PHYSFS_sint8 offset;
  75. } ISO9660FileTimestamp;
  76. typedef struct
  77. {
  78. unsigned existence:1;
  79. unsigned directory:1;
  80. unsigned associated_file:1;
  81. unsigned record:1;
  82. unsigned protection:1;
  83. unsigned reserved:2;
  84. unsigned multiextent:1;
  85. } ISO9660FileFlags;
  86. typedef struct
  87. {
  88. PHYSFS_uint8 length;
  89. PHYSFS_uint8 attribute_length;
  90. ISOBB32bit(extent_location)
  91. ISOBB32bit(data_length)
  92. ISO9660FileTimestamp timestamp;
  93. ISO9660FileFlags file_flags;
  94. PHYSFS_uint8 file_unit_size;
  95. PHYSFS_uint8 gap_size;
  96. ISOBB16bit(vol_seq_no)
  97. PHYSFS_uint8 len_fi;
  98. char unused;
  99. } ISO9660RootDirectoryRecord;
  100. /* this structure is combined for all Volume descriptor types */
  101. typedef struct
  102. {
  103. PHYSFS_uint8 type;
  104. char identifier[5];
  105. PHYSFS_uint8 version;
  106. PHYSFS_uint8 flags;
  107. char system_identifier[32];
  108. char volume_identifier[32];
  109. char unused2[8];
  110. ISOBB32bit(space_size)
  111. PHYSFS_uint8 escape_sequences[32];
  112. ISOBB16bit(vol_set_size)
  113. ISOBB16bit(vol_seq_no)
  114. ISOBB16bit(block_size)
  115. ISOBB32bit(path_table_size)
  116. /* PHYSFS_uint32 path_table_start_lsb; // why didn't they use both byte type?
  117. PHYSFS_uint32 opt_path_table_start_lsb;
  118. PHYSFS_uint32 path_table_start_msb;
  119. PHYSFS_uint32 opt_path_table_start_msb;*/
  120. #if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
  121. PHYSFS_uint32 path_table_start;
  122. PHYSFS_uint32 opt_path_table_start;
  123. PHYSFS_uint32 unused6;
  124. PHYSFS_uint32 unused7;
  125. #else
  126. PHYSFS_uint32 unused6;
  127. PHYSFS_uint32 unused7;
  128. PHYSFS_uint32 path_table_start;
  129. PHYSFS_uint32 opt_path_table_start;
  130. #endif
  131. ISO9660RootDirectoryRecord rootdirectory;
  132. char set_identifier[128];
  133. char publisher_identifier[128];
  134. char preparer_identifer[128];
  135. char application_identifier[128];
  136. char copyright_file_identifier[37];
  137. char abstract_file_identifier[37];
  138. char bibliographic_file_identifier[37];
  139. ISO9660VolumeTimestamp creation_timestamp;
  140. ISO9660VolumeTimestamp modification_timestamp;
  141. ISO9660VolumeTimestamp expiration_timestamp;
  142. ISO9660VolumeTimestamp effective_timestamp;
  143. PHYSFS_uint8 file_structure_version;
  144. char unused4;
  145. char application_use[512];
  146. char unused5[653];
  147. } ISO9660VolumeDescriptor;
  148. typedef struct
  149. {
  150. PHYSFS_uint8 recordlen;
  151. PHYSFS_uint8 extattributelen;
  152. ISOBB32bit(extentpos)
  153. ISOBB32bit(datalen)
  154. ISO9660FileTimestamp recordtime;
  155. ISO9660FileFlags flags;
  156. PHYSFS_uint8 file_unit_size;
  157. PHYSFS_uint8 interleave_gap;
  158. ISOBB16bit(volseqno)
  159. PHYSFS_uint8 filenamelen;
  160. char filename[222]; /* This is not exact, but makes reading easier */
  161. } ISO9660FileDescriptor;
  162. typedef struct
  163. {
  164. ISOBB16bit(owner)
  165. ISOBB16bit(group)
  166. PHYSFS_uint16 flags; /* not implemented*/
  167. ISO9660VolumeTimestamp create_time; /* yes, not file timestamp */
  168. ISO9660VolumeTimestamp mod_time;
  169. ISO9660VolumeTimestamp expire_time;
  170. ISO9660VolumeTimestamp effective_time;
  171. PHYSFS_uint8 record_format;
  172. PHYSFS_uint8 record_attributes;
  173. ISOBB16bit(record_len)
  174. char system_identifier[32];
  175. char system_use[64];
  176. PHYSFS_uint8 version;
  177. ISOBB16bit(escape_len)
  178. char reserved[64];
  179. /** further fields not implemented */
  180. } ISO9660ExtAttributeRec;
  181. #pragma pack(pop) /* restore original alignment from stack */
  182. typedef struct
  183. {
  184. void *fhandle;
  185. PHYSFS_uint32 rootdirstart;
  186. PHYSFS_uint32 rootdirsize;
  187. PHYSFS_uint64 currpos;
  188. int isjoliet;
  189. char *path;
  190. void *mutex;
  191. } ISO9660Handle;
  192. typedef struct __ISO9660FileHandle
  193. {
  194. PHYSFS_sint64 filesize;
  195. PHYSFS_uint64 currpos;
  196. PHYSFS_uint64 startblock;
  197. ISO9660Handle *isohandle;
  198. PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer,
  199. PHYSFS_uint64 len);
  200. int (*seek)(struct __ISO9660FileHandle *filehandle, PHYSFS_sint64 offset);
  201. int (*close)(struct __ISO9660FileHandle *filehandle);
  202. /* !!! FIXME: anonymouse union is going to cause problems. */
  203. union
  204. {
  205. char *cacheddata; /* data of file when cached */
  206. void *filehandle; /* handle to separate opened file */
  207. };
  208. } ISO9660FileHandle;
  209. /*******************************************************************************
  210. * Time conversion functions
  211. ******************************************************************************/
  212. static PHYSFS_sint64 iso_mktime(ISO9660FileTimestamp *timestamp)
  213. {
  214. struct tm tm;
  215. tm.tm_year = timestamp->year;
  216. tm.tm_mon = timestamp->month - 1;
  217. tm.tm_mday = timestamp->day;
  218. tm.tm_hour = timestamp->hour;
  219. tm.tm_min = timestamp->minute;
  220. tm.tm_sec = timestamp->second;
  221. /* Ignore GMT offset for now... */
  222. return mktime(&tm);
  223. } /* iso_mktime */
  224. static int iso_atoi2(char *text)
  225. {
  226. return ((text[0] - 40) * 10) + (text[1] - 40);
  227. } /* iso_atoi2 */
  228. static int iso_atoi4(char *text)
  229. {
  230. return ((text[0] - 40) * 1000) + ((text[1] - 40) * 100) +
  231. ((text[2] - 40) * 10) + (text[3] - 40);
  232. } /* iso_atoi4 */
  233. static PHYSFS_sint64 iso_volume_mktime(ISO9660VolumeTimestamp *timestamp)
  234. {
  235. struct tm tm;
  236. tm.tm_year = iso_atoi4(timestamp->year);
  237. tm.tm_mon = iso_atoi2(timestamp->month) - 1;
  238. tm.tm_mday = iso_atoi2(timestamp->day);
  239. tm.tm_hour = iso_atoi2(timestamp->hour);
  240. tm.tm_min = iso_atoi2(timestamp->minute);
  241. tm.tm_sec = iso_atoi2(timestamp->second);
  242. /* this allows values outside the range of a unix timestamp... sanitize them */
  243. PHYSFS_sint64 value = mktime(&tm);
  244. return value == -1 ? 0 : value;
  245. } /* iso_volume_mktime */
  246. /*******************************************************************************
  247. * Filename extraction
  248. ******************************************************************************/
  249. static int iso_extractfilenameISO(ISO9660FileDescriptor *descriptor,
  250. char *filename, int *version)
  251. {
  252. *filename = '\0';
  253. if (descriptor->flags.directory)
  254. {
  255. strncpy(filename, descriptor->filename, descriptor->filenamelen);
  256. filename[descriptor->filenamelen] = '\0';
  257. *version = 0;
  258. } /* if */
  259. else
  260. {
  261. /* find last SEPARATOR2 */
  262. int pos = 0;
  263. int lastfound = -1;
  264. for(;pos < descriptor->filenamelen; pos++)
  265. if (descriptor->filename[pos] == ';')
  266. lastfound = pos;
  267. BAIL_IF_MACRO(lastfound < 1, ERR_BAD_FILENAME, -1);
  268. BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), ERR_BAD_FILENAME, -1);
  269. strncpy(filename, descriptor->filename, lastfound);
  270. if (filename[lastfound - 1] == '.')
  271. filename[lastfound - 1] = '\0'; /* consume trailing ., as done in all implementations */
  272. else
  273. filename[lastfound] = '\0';
  274. *version = atoi(descriptor->filename + lastfound);
  275. } /* else */
  276. return 0;
  277. } /* iso_extractfilenameISO */
  278. static int iso_extractfilenameUCS2(ISO9660FileDescriptor *descriptor,
  279. char *filename, int *version)
  280. {
  281. PHYSFS_uint16 tmp[128];
  282. PHYSFS_uint16 *src;
  283. int len;
  284. *filename = '\0';
  285. *version = 1; /* Joliet does not have versions.. at least not on my images */
  286. src = (PHYSFS_uint16*) descriptor->filename;
  287. len = descriptor->filenamelen / 2;
  288. tmp[len] = 0;
  289. while(len--)
  290. tmp[len] = PHYSFS_swapUBE16(src[len]);
  291. PHYSFS_utf8FromUcs2(tmp, filename, 255);
  292. return 0;
  293. } /* iso_extractfilenameUCS2 */
  294. static int iso_extractfilename(ISO9660Handle *handle,
  295. ISO9660FileDescriptor *descriptor, char *filename,int *version)
  296. {
  297. if (handle->isjoliet)
  298. return iso_extractfilenameUCS2(descriptor, filename, version);
  299. else
  300. return iso_extractfilenameISO(descriptor, filename, version);
  301. } /* iso_extractfilename */
  302. /*******************************************************************************
  303. * Basic image read functions
  304. ******************************************************************************/
  305. static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where,
  306. void *buffer, PHYSFS_uint64 len)
  307. {
  308. BAIL_IF_MACRO(!__PHYSFS_platformGrabMutex(handle->mutex),
  309. ERR_LOCK_VIOLATION, -1);
  310. int rc = -1;
  311. if (where != handle->currpos)
  312. GOTO_IF_MACRO(!__PHYSFS_platformSeek(handle->fhandle,where), NULL,
  313. unlockme);
  314. rc = __PHYSFS_platformRead(handle->fhandle, buffer, len);
  315. if (rc == -1)
  316. {
  317. handle->currpos = (PHYSFS_uint64) -1;
  318. GOTO_MACRO(NULL, unlockme);
  319. } /* if */
  320. handle->currpos += rc;
  321. unlockme:
  322. __PHYSFS_platformReleaseMutex(handle->mutex);
  323. return rc;
  324. } /* iso_readimage */
  325. static PHYSFS_sint64 iso_readfiledescriptor(ISO9660Handle *handle,
  326. PHYSFS_uint64 where,
  327. ISO9660FileDescriptor *descriptor)
  328. {
  329. PHYSFS_sint64 rc = iso_readimage(handle, where, descriptor,
  330. sizeof (descriptor->recordlen));
  331. BAIL_IF_MACRO(rc == -1, NULL, -1);
  332. BAIL_IF_MACRO(rc != 1, ERR_CORRUPTED, -1);
  333. if (descriptor->recordlen == 0)
  334. return 0; /* fill bytes at the end of a sector */
  335. rc = iso_readimage(handle, where + 1, &descriptor->extattributelen,
  336. descriptor->recordlen - sizeof(descriptor->recordlen));
  337. BAIL_IF_MACRO(rc == -1, NULL, -1);
  338. BAIL_IF_MACRO(rc != 1, ERR_CORRUPTED, -1);
  339. return 0;
  340. } /* iso_readfiledescriptor */
  341. static void iso_extractsubpath(char *path, char **subpath)
  342. {
  343. *subpath = strchr(path,'/');
  344. if (*subpath != 0)
  345. {
  346. **subpath = 0;
  347. *subpath +=1;
  348. } /* if */
  349. } /* iso_extractsubpath */
  350. /*
  351. * Don't use path tables, they are not necessarily faster, but more complicated
  352. * to implement as they store only directories and not files, so searching for
  353. * a file needs to branch to the directory extent sooner or later.
  354. */
  355. static int iso_find_dir_entry(ISO9660Handle *handle,const char *path,
  356. ISO9660FileDescriptor *descriptor, int *exists)
  357. {
  358. char *subpath = 0;
  359. PHYSFS_uint64 readpos, end_of_dir;
  360. char filename[255];
  361. char pathcopy[256];
  362. char *mypath;
  363. int version = 0;
  364. strcpy(pathcopy, path);
  365. mypath = pathcopy;
  366. *exists = 0;
  367. readpos = handle->rootdirstart;
  368. end_of_dir = handle->rootdirstart + handle->rootdirsize;
  369. iso_extractsubpath(mypath, &subpath);
  370. while (1)
  371. {
  372. BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, descriptor), NULL, -1);
  373. /* recordlen = 0 -> no more entries or fill entry */
  374. if (!descriptor->recordlen)
  375. {
  376. /* if we are in the last sector of the directory & it's 0 -> end */
  377. if ((end_of_dir - 2048) <= (readpos -1))
  378. break; /* finished */
  379. /* else skip to the next sector & continue; */
  380. readpos = (((readpos - 1) / 2048) + 1) * 2048;
  381. continue;
  382. } /* if */
  383. readpos += descriptor->recordlen;
  384. if (descriptor->filenamelen == 1 && (descriptor->filename[0] == 0
  385. || descriptor->filename[0] == 1))
  386. continue; /* special ones, ignore */
  387. BAIL_IF_MACRO(
  388. iso_extractfilename(handle, descriptor, filename, &version),
  389. NULL, -1);
  390. if (strcmp(filename, mypath) == 0)
  391. {
  392. if ( (subpath == 0) || (subpath[0] == 0) )
  393. {
  394. *exists = 1;
  395. return 0; /* no subpaths left and we found the entry */
  396. } /* if */
  397. if (descriptor->flags.directory)
  398. {
  399. /* shorten the path to the subpath */
  400. mypath = subpath;
  401. iso_extractsubpath(mypath, &subpath);
  402. /* gosub to the new directory extent */
  403. readpos = descriptor->extentpos * 2048;
  404. end_of_dir = readpos + descriptor->datalen;
  405. } /* if */
  406. else
  407. {
  408. /* we're at a file but have a remaining subpath -> no match */
  409. return 0;
  410. } /* else */
  411. } /* if */
  412. } /* while */
  413. return 0;
  414. } /* iso_find_dir_entry */
  415. static int iso_read_ext_attributes(ISO9660Handle *handle, int block,
  416. ISO9660ExtAttributeRec *attributes)
  417. {
  418. return iso_readimage(handle, block * 2048, attributes,
  419. sizeof(ISO9660ExtAttributeRec));
  420. } /* iso_read_ext_attributes */
  421. /*******************************************************************************
  422. * Archive management functions
  423. ******************************************************************************/
  424. static int ISO9660_isArchive(const char *filename, int forWriting)
  425. {
  426. char magicnumber[6] = {0,0,0,0,0,0};
  427. void *in;
  428. BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
  429. in = __PHYSFS_platformOpenRead(filename);
  430. BAIL_IF_MACRO(in == NULL, NULL, 0);
  431. /* Skip system area to magic number in Volume descriptor */
  432. if (__PHYSFS_platformSeek(in, 32769) == 0)
  433. {
  434. __PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
  435. BAIL_MACRO(NULL, 0);
  436. } /* if */
  437. /* Read magic number */
  438. if (__PHYSFS_platformRead(in, magicnumber, 5) != 5)
  439. {
  440. __PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
  441. BAIL_MACRO(NULL, 0);
  442. } /* if */
  443. __PHYSFS_platformClose(in);
  444. return (strcmp(magicnumber, "CD001") == 0);
  445. } /* ISO9660_isArchive */
  446. static void *ISO9660_openArchive(const char *filename, int forWriting)
  447. {
  448. ISO9660Handle *handle;
  449. int founddescriptor = 0;
  450. int foundjoliet = 0;
  451. BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
  452. handle = allocator.Malloc(sizeof(ISO9660Handle));
  453. GOTO_IF_MACRO(!handle, ERR_OUT_OF_MEMORY, errorcleanup);
  454. handle->path = 0;
  455. handle->mutex= 0;
  456. handle->fhandle = 0;
  457. handle->path = allocator.Malloc(strlen(filename) + 1);
  458. GOTO_IF_MACRO(!handle->path, ERR_OUT_OF_MEMORY, errorcleanup);
  459. strcpy(handle->path, filename);
  460. handle->mutex = __PHYSFS_platformCreateMutex();
  461. GOTO_IF_MACRO(!handle->mutex, "Cannot create Mutex", errorcleanup);
  462. handle->fhandle = __PHYSFS_platformOpenRead(filename);
  463. GOTO_IF_MACRO(!handle->fhandle, NULL, errorcleanup);
  464. /* seek Primary Volume Descriptor */
  465. GOTO_IF_MACRO(!__PHYSFS_platformSeek(handle->fhandle, 32768), ERR_SEEK_ERROR, errorcleanup);
  466. while (1)
  467. {
  468. ISO9660VolumeDescriptor descriptor;
  469. GOTO_IF_MACRO(__PHYSFS_platformRead(handle->fhandle, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), "Cannot read from image", errorcleanup);
  470. GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, ERR_NOT_AN_ARCHIVE, errorcleanup);
  471. if (descriptor.type == 255)
  472. {
  473. /* type 255 terminates the volume descriptor list */
  474. if (founddescriptor)
  475. return handle; /* ok, we've found one volume descriptor */
  476. else
  477. GOTO_MACRO(ERR_CORRUPTED, errorcleanup);
  478. } /* if */
  479. if (descriptor.type == 1 && !founddescriptor)
  480. {
  481. handle->currpos = __PHYSFS_platformTell(handle->fhandle);
  482. handle->rootdirstart =
  483. descriptor.rootdirectory.extent_location * 2048;
  484. handle->rootdirsize =
  485. descriptor.rootdirectory.data_length;
  486. handle->isjoliet = 0;
  487. founddescriptor = 1; /* continue search for joliet */
  488. } /* if */
  489. if (descriptor.type == 2 && !foundjoliet)
  490. {
  491. /* check if is joliet */
  492. PHYSFS_uint8 *s = descriptor.escape_sequences;
  493. int joliet = !(descriptor.flags & 1)
  494. && (s[0] == 0x25)
  495. && (s[1] == 0x2F)
  496. && ((s[2] == 0x40) || (s[2] == 0x43) || (s[2] == 0x45));
  497. if (!joliet)
  498. continue;
  499. handle->currpos = __PHYSFS_platformTell(handle->fhandle);
  500. handle->rootdirstart =
  501. descriptor.rootdirectory.extent_location * 2048;
  502. handle->rootdirsize =
  503. descriptor.rootdirectory.data_length;
  504. handle->isjoliet = 1;
  505. founddescriptor = 1;
  506. foundjoliet = 1;
  507. } /* if */
  508. } /* while */
  509. GOTO_MACRO(ERR_CORRUPTED, errorcleanup); /* not found. */
  510. errorcleanup:
  511. if (handle)
  512. {
  513. if (handle->fhandle)
  514. __PHYSFS_platformClose(handle->fhandle);
  515. if (handle->path)
  516. allocator.Free(handle->path);
  517. if (handle->mutex)
  518. __PHYSFS_platformDestroyMutex(handle->mutex);
  519. } /* if */
  520. return NULL;
  521. } /* ISO9660_openArchive */
  522. static void ISO9660_dirClose(dvoid *opaque)
  523. {
  524. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  525. __PHYSFS_platformClose(handle->fhandle);
  526. __PHYSFS_platformDestroyMutex(handle->mutex);
  527. allocator.Free(handle->path);
  528. allocator.Free(handle);
  529. } /* ISO9660_dirClose */
  530. /*******************************************************************************
  531. * Read functions
  532. ******************************************************************************/
  533. static PHYSFS_uint32 iso_file_read_mem(ISO9660FileHandle *filehandle,
  534. void *buffer, PHYSFS_uint64 len)
  535. {
  536. /* check remaining bytes & max obj which can be fetched */
  537. const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
  538. if (bytesleft < len)
  539. len = bytesleft;
  540. if (len == 0)
  541. return 0;
  542. memcpy(buffer, filehandle->cacheddata + filehandle->currpos, (size_t) len);
  543. filehandle->currpos += len;
  544. return (PHYSFS_uint32) len;
  545. } /* iso_file_read_mem */
  546. static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset)
  547. {
  548. BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
  549. BAIL_IF_MACRO(offset >= fhandle->filesize, ERR_PAST_EOF, 0);
  550. fhandle->currpos = offset;
  551. return 0;
  552. } /* iso_file_seek_mem */
  553. static int iso_file_close_mem(ISO9660FileHandle *fhandle)
  554. {
  555. allocator.Free(fhandle->cacheddata);
  556. allocator.Free(fhandle);
  557. return -1;
  558. } /* iso_file_seek_mem */
  559. static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle,
  560. void *buffer, PHYSFS_uint64 len)
  561. {
  562. /* check remaining bytes & max obj which can be fetched */
  563. const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
  564. if (bytesleft < len)
  565. len = bytesleft;
  566. PHYSFS_sint64 rc = __PHYSFS_platformRead(filehandle->filehandle, buffer,
  567. len);
  568. BAIL_IF_MACRO(rc == -1, NULL, -1);
  569. filehandle->currpos += rc; /* i trust my internal book keeping */
  570. BAIL_IF_MACRO(rc < len, ERR_CORRUPTED, -1);
  571. return rc;
  572. } /* iso_file_read_foreign */
  573. static int iso_file_seek_foreign(ISO9660FileHandle *fhandle,
  574. PHYSFS_sint64 offset)
  575. {
  576. BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
  577. BAIL_IF_MACRO(offset >= fhandle->filesize, ERR_PAST_EOF, 0);
  578. PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset;
  579. int rc = __PHYSFS_platformSeek(fhandle->filehandle, pos);
  580. BAIL_IF_MACRO(rc, NULL, -1);
  581. fhandle->currpos = offset;
  582. return 0;
  583. } /* iso_file_seek_foreign */
  584. static int iso_file_close_foreign(ISO9660FileHandle *fhandle)
  585. {
  586. void *filehandle = fhandle->filehandle;
  587. allocator.Free(fhandle);
  588. return __PHYSFS_platformClose(filehandle);
  589. } /* iso_file_close_foreign */
  590. static int iso_file_open_mem(ISO9660Handle *handle, ISO9660FileHandle *fhandle)
  591. {
  592. fhandle->cacheddata = allocator.Malloc(fhandle->filesize);
  593. BAIL_IF_MACRO(!fhandle->cacheddata, ERR_OUT_OF_MEMORY, -1);
  594. int rc = iso_readimage(handle, fhandle->startblock * 2048,
  595. fhandle->cacheddata, fhandle->filesize);
  596. GOTO_IF_MACRO(rc < 0, NULL, freemem);
  597. GOTO_IF_MACRO(rc == 0, ERR_CORRUPTED, freemem);
  598. fhandle->read = iso_file_read_mem;
  599. fhandle->seek = iso_file_seek_mem;
  600. fhandle->close = iso_file_close_mem;
  601. return 0;
  602. freemem:
  603. allocator.Free(fhandle->cacheddata);
  604. return -1;
  605. } /* iso_file_open_mem */
  606. static int iso_file_open_foreign(ISO9660Handle *handle,
  607. ISO9660FileHandle *fhandle)
  608. {
  609. fhandle->filehandle = __PHYSFS_platformOpenRead(handle->path);
  610. BAIL_IF_MACRO(!fhandle->filehandle, NULL, -1);
  611. int rc = __PHYSFS_platformSeek(fhandle->filehandle,
  612. fhandle->startblock * 2048);
  613. GOTO_IF_MACRO(!rc, NULL, closefile);
  614. fhandle->read = iso_file_read_foreign;
  615. fhandle->seek = iso_file_seek_foreign;
  616. fhandle->close = iso_file_close_foreign;
  617. return 0;
  618. closefile:
  619. __PHYSFS_platformClose(fhandle->filehandle);
  620. return -1;
  621. } /* iso_file_open_foreign */
  622. static fvoid *ISO9660_openRead(dvoid *opaque, const char *filename, int *exists)
  623. {
  624. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  625. ISO9660FileHandle *fhandle;
  626. ISO9660FileDescriptor descriptor;
  627. int rc;
  628. fhandle = allocator.Malloc(sizeof(ISO9660FileHandle));
  629. BAIL_IF_MACRO(fhandle == 0, ERR_OUT_OF_MEMORY, NULL);
  630. fhandle->cacheddata = 0;
  631. /* find file descriptor */
  632. rc = iso_find_dir_entry(handle, filename, &descriptor, exists);
  633. GOTO_IF_MACRO(rc, NULL, errorhandling);
  634. GOTO_IF_MACRO(!*exists, ERR_NO_SUCH_FILE, errorhandling);
  635. fhandle->startblock = descriptor.extentpos + descriptor.extattributelen;
  636. fhandle->filesize = descriptor.datalen;
  637. fhandle->currpos = 0;
  638. fhandle->isohandle = handle;
  639. fhandle->cacheddata = NULL;
  640. fhandle->filehandle = NULL;
  641. if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE)
  642. rc = iso_file_open_mem(handle, fhandle);
  643. else
  644. rc = iso_file_open_foreign(handle, fhandle);
  645. GOTO_IF_MACRO(rc, NULL, errorhandling);
  646. return fhandle;
  647. errorhandling:
  648. if (!fhandle)
  649. return NULL;
  650. allocator.Free(fhandle);
  651. return NULL;
  652. } /* ISO9660_openRead */
  653. static int ISO9660_fileClose(fvoid *opaque)
  654. {
  655. ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
  656. return fhandle->close(fhandle);
  657. } /* ISO9660_fileClose */
  658. static PHYSFS_sint64 ISO9660_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
  659. {
  660. ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
  661. return fhandle->read(fhandle, buf, len);
  662. } /* ISO9660_read */
  663. static PHYSFS_sint64 ISO9660_tell(fvoid *opaque)
  664. {
  665. return ((ISO9660FileHandle*) opaque)->currpos;
  666. } /* ISO9660_tell */
  667. static int ISO9660_seek(fvoid *opaque, PHYSFS_uint64 offset)
  668. {
  669. ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
  670. return fhandle->seek(fhandle, offset);
  671. } /* ISO9660_seek */
  672. static int ISO9660_eof(fvoid *opaque)
  673. {
  674. ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
  675. return fhandle->currpos >= fhandle->filesize;
  676. } /* ISO9660_eof */
  677. static PHYSFS_sint64 ISO9660_fileLength(fvoid *opaque)
  678. {
  679. return ((ISO9660FileHandle*) opaque)->filesize;
  680. } /* ISO9660_fileLength */
  681. /*******************************************************************************
  682. * Information gathering functions
  683. ******************************************************************************/
  684. static void ISO9660_enumerateFiles(dvoid *opaque, const char *dname,
  685. int omitSymLinks,
  686. PHYSFS_EnumFilesCallback cb,
  687. const char *origdir, void *callbackdata)
  688. {
  689. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  690. ISO9660FileDescriptor descriptor;
  691. PHYSFS_uint64 readpos;
  692. PHYSFS_uint64 end_of_dir;
  693. char filename[130]; /* ISO allows 31, Joliet 128 -> 128 + 2 eol bytes */
  694. int version = 0;
  695. if (*dname == '\0')
  696. {
  697. readpos = handle->rootdirstart;
  698. end_of_dir = readpos + handle->rootdirsize;
  699. } /* if */
  700. else
  701. {
  702. printf("pfad %s\n",dname);
  703. int exists = 0;
  704. BAIL_IF_MACRO(iso_find_dir_entry(handle,dname, &descriptor, &exists), NULL,);
  705. BAIL_IF_MACRO(exists == 0, NULL, );
  706. BAIL_IF_MACRO(!descriptor.flags.directory, NULL,);
  707. readpos = descriptor.extentpos * 2048;
  708. end_of_dir = readpos + descriptor.datalen;
  709. } /* else */
  710. while (1)
  711. {
  712. BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, &descriptor), NULL, );
  713. /* recordlen = 0 -> no more entries or fill entry */
  714. if (!descriptor.recordlen)
  715. {
  716. /* if we are in the last sector of the directory & it's 0 -> end */
  717. if ((end_of_dir - 2048) <= (readpos -1))
  718. break; /* finished */
  719. /* else skip to the next sector & continue; */
  720. readpos = (((readpos - 1) / 2048) + 1) * 2048;
  721. continue;
  722. } /* if */
  723. readpos += descriptor.recordlen;
  724. if (descriptor.filenamelen == 1 && (descriptor.filename[0] == 0
  725. || descriptor.filename[0] == 1))
  726. continue; /* special ones, ignore */
  727. strncpy(filename,descriptor.filename,descriptor.filenamelen);
  728. iso_extractfilename(handle, &descriptor, filename, &version);
  729. cb(callbackdata, origdir,filename);
  730. } /* while */
  731. } /* ISO9660_enumerateFiles */
  732. static int ISO9660_exists(dvoid *opaque, const char *name)
  733. {
  734. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  735. ISO9660FileDescriptor descriptor;
  736. int exists = 0;
  737. BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, &exists), NULL, -1);
  738. return exists;
  739. } /* ISO9660_exists */
  740. static int ISO9660_stat(dvoid *opaque, const char *name, int *exists,
  741. PHYSFS_Stat *stat)
  742. {
  743. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  744. ISO9660FileDescriptor descriptor;
  745. ISO9660ExtAttributeRec extattr;
  746. BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, exists), NULL, -1);
  747. if (!*exists)
  748. return 0;
  749. stat->readonly = 1;
  750. /* try to get extended info */
  751. if (descriptor.extattributelen)
  752. {
  753. BAIL_IF_MACRO(iso_read_ext_attributes(handle,
  754. descriptor.extentpos, &extattr), NULL, -1);
  755. stat->createtime = iso_volume_mktime(&extattr.create_time);
  756. stat->modtime = iso_volume_mktime(&extattr.mod_time);
  757. stat->accesstime = iso_volume_mktime(&extattr.mod_time);
  758. } /* if */
  759. else
  760. {
  761. stat->createtime = iso_mktime(&descriptor.recordtime);
  762. stat->modtime = iso_mktime(&descriptor.recordtime);
  763. stat->accesstime = iso_mktime(&descriptor.recordtime);
  764. } /* else */
  765. if (descriptor.flags.directory)
  766. {
  767. stat->filesize = 0;
  768. stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
  769. } /* if */
  770. else
  771. {
  772. stat->filesize = descriptor.datalen;
  773. stat->filetype = PHYSFS_FILETYPE_REGULAR;
  774. } /* else */
  775. return 1;
  776. } /* ISO9660_stat */
  777. static int ISO9660_isDirectory(dvoid *opaque, const char *name, int *fileExists)
  778. {
  779. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  780. ISO9660FileDescriptor descriptor;
  781. BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, fileExists), NULL, 0);
  782. return descriptor.flags.directory;
  783. } /* ISO9660_isDirectory */
  784. static int ISO9660_isSymLink(dvoid *opaque, const char *name, int *fileExists)
  785. {
  786. *fileExists = ISO9660_exists(opaque, name);
  787. return 0;
  788. } /* ISO9660_isSymLink */
  789. static PHYSFS_sint64 ISO9660_getLastModTime(dvoid *opaque, const char *name,
  790. int *fileExists)
  791. {
  792. ISO9660Handle *handle = (ISO9660Handle*) opaque;
  793. ISO9660FileDescriptor descriptor;
  794. BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, fileExists), NULL, -1);
  795. return iso_mktime(&descriptor.recordtime);
  796. } /* ISO9660_getLastModTime */
  797. /*******************************************************************************
  798. * Not supported functions
  799. ******************************************************************************/
  800. static fvoid* ISO9660_openWrite(dvoid *opaque, const char *name)
  801. {
  802. BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
  803. } /* ISO9660_openWrite */
  804. static fvoid* ISO9660_openAppend(dvoid *opaque, const char *name)
  805. {
  806. BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
  807. } /* ISO9660_openAppend */
  808. static int ISO9660_remove(dvoid *opaque, const char *name)
  809. {
  810. BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
  811. } /* ISO9660_remove */
  812. static int ISO9660_mkdir(dvoid *opaque, const char *name)
  813. {
  814. BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
  815. } /* ISO9660_mkdir */
  816. static PHYSFS_sint64 ISO9660_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
  817. {
  818. BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
  819. } /* ISO9660_write */
  820. const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ISO9660 =
  821. {
  822. "ISO",
  823. "ISO9660 image file",
  824. "Christoph Nelles <evilazrael@evilazrael.de>",
  825. "http://www.evilazrael.de",
  826. };
  827. const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
  828. {
  829. &__PHYSFS_ArchiveInfo_ISO9660,
  830. ISO9660_isArchive, /* isArchive() method */
  831. ISO9660_openArchive, /* openArchive() method */
  832. ISO9660_enumerateFiles, /* enumerateFiles() method */
  833. ISO9660_exists, /* exists() method */
  834. ISO9660_isDirectory, /* isDirectory() method */
  835. ISO9660_isSymLink, /* isSymLink() method */
  836. ISO9660_getLastModTime, /* getLastModTime() method */
  837. ISO9660_openRead, /* openRead() method */
  838. ISO9660_openWrite, /* openWrite() method */
  839. ISO9660_openAppend, /* openAppend() method */
  840. ISO9660_remove, /* remove() method */
  841. ISO9660_mkdir, /* mkdir() method */
  842. ISO9660_dirClose, /* dirClose() method */
  843. ISO9660_stat, /* stat() method */
  844. ISO9660_read, /* read() method */
  845. ISO9660_write, /* write() method */
  846. ISO9660_eof, /* eof() method */
  847. ISO9660_tell, /* tell() method */
  848. ISO9660_seek, /* seek() method */
  849. ISO9660_fileLength, /* fileLength() method */
  850. ISO9660_fileClose /* fileClose() method */
  851. };
  852. #endif /* defined PHYSFS_SUPPORTS_ISO9660 */
  853. /* end of archiver_iso9660.c ... */