/src/zziplib/zzip/memdisk.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 466 lines · 372 code · 34 blank · 60 comment · 42 complexity · 518ada4d50b8e7fb625377f0f80cd521 MD5 · raw file

  1. /*
  2. * NOTE: this is part of libzzipmmapped (i.e. it is not libzzip).
  3. * ==================
  4. *
  5. * The mem_disk cache will parse the central information of a zip archive
  6. * and store it internally. One the one hand it allows to find files
  7. * faster - no disk access is required and endian conversion is not
  8. * needed. If zzip is compiled with zip extensions then it is about
  9. * the only way to build maintainable code around the zip format.
  10. *
  11. * Note that 64bit support is almost entirely living in extension
  12. * blocks as well as different character encodings and file access
  13. * control bits that are mostly platform specific.
  14. *
  15. * Author:
  16. * Guido Draheim <guidod@gmx.de>
  17. *
  18. * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
  19. * All rights reserved,
  20. * use under the restrictions of the
  21. * Lesser GNU General Public License
  22. * or alternatively the restrictions
  23. * of the Mozilla Public License 1.1
  24. */
  25. #define _ZZIP_DISK_FILE_STRUCT 1
  26. #include <zzip/types.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <time.h>
  31. #include <zlib.h>
  32. #include <zzip/format.h>
  33. #include <zzip/fetch.h>
  34. #include <zzip/mmapped.h>
  35. #include <zzip/memdisk.h>
  36. #include <zzip/__fnmatch.h>
  37. #define ___ {
  38. #define ____ }
  39. static const char *error[] = {
  40. "Ok",
  41. # define _zzip_mem_disk_open_fail 1
  42. "zzip_mem_disk_open: zzip_disk_open did fail",
  43. # define _zzip_mem_disk_fdopen_fail 2
  44. "zzip_mem_disk_fdopen: zzip_disk_mmap did fail"
  45. # define _zzip_mem_disk_buffer_fail 3
  46. "zzip_mem_disk_buffer: zzip_disk_buffer did fail",
  47. 0
  48. };
  49. #define ZZIP_EXTRA_zip64 0x0001
  50. typedef struct _zzip_extra_zip64
  51. { /* ZIP64 extended information extra field */
  52. zzip_byte_t z_datatype[2]; /* Tag for this "extra" block type */
  53. zzip_byte_t z_datasize[2]; /* Size of this "extra" block */
  54. zzip_byte_t z_usize[8]; /* Original uncompressed file size */
  55. zzip_byte_t z_csize[8]; /* Size of compressed data */
  56. zzip_byte_t z_offset[8]; /* Offset of local header record */
  57. zzip_byte_t z_diskstart[4]; /* Number of the disk for file start */
  58. } zzip_extra_zip64;
  59. /*forward*/
  60. static zzip__new__ ZZIP_MEM_ENTRY *
  61. zzip_mem_entry_new(ZZIP_DISK * disk, ZZIP_DISK_ENTRY * entry);
  62. static void
  63. zzip_mem_entry_free(ZZIP_MEM_ENTRY * _zzip_restrict item);
  64. zzip__new__ ZZIP_MEM_DISK *
  65. zzip_mem_disk_new(void)
  66. {
  67. return calloc(1, sizeof(ZZIP_MEM_DISK));
  68. }
  69. /** create new diskdir handle.
  70. * wraps underlying zzip_disk_open. */
  71. zzip__new__ ZZIP_MEM_DISK *
  72. zzip_mem_disk_open(char *filename)
  73. {
  74. ZZIP_DISK *disk = zzip_disk_open(filename);
  75. if (! disk)
  76. { perror(error[_zzip_mem_disk_open_fail]); return 0; }
  77. ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
  78. zzip_mem_disk_load(dir, disk);
  79. return dir;
  80. ____;
  81. }
  82. /** create new diskdir handle.
  83. * wraps underlying zzip_disk_open. */
  84. zzip__new__ ZZIP_MEM_DISK *
  85. zzip_mem_disk_fdopen(int fd)
  86. {
  87. ZZIP_DISK *disk = zzip_disk_mmap(fd);
  88. if (! disk)
  89. { perror(error[_zzip_mem_disk_fdopen_fail]); return 0; }
  90. ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
  91. zzip_mem_disk_load(dir, disk);
  92. return dir;
  93. ____;
  94. }
  95. /** create new diskdir handle.
  96. * wraps underlying zzip_disk_buffer. */
  97. zzip__new__ ZZIP_MEM_DISK *
  98. zzip_mem_disk_buffer(char *buffer, size_t buflen)
  99. {
  100. ZZIP_DISK *disk = zzip_disk_buffer(buffer, buflen);
  101. if (! disk)
  102. { perror(error[_zzip_mem_disk_buffer_fail]); return 0; }
  103. ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
  104. zzip_mem_disk_load(dir, disk);
  105. return dir;
  106. ____;
  107. }
  108. /** parse central dir.
  109. * creates an internal copy of each entry converted to the local platform.
  110. * returns: number of entries, or -1 on error (setting errno)
  111. */
  112. long
  113. zzip_mem_disk_load(ZZIP_MEM_DISK * dir, ZZIP_DISK * disk)
  114. {
  115. if (! dir || ! disk)
  116. { errno=EINVAL; return -1; }
  117. if (dir->list)
  118. zzip_mem_disk_unload(dir);
  119. ___ long count = 0;
  120. ___ struct zzip_disk_entry *entry = zzip_disk_findfirst(disk);
  121. for (; entry; entry = zzip_disk_findnext(disk, entry))
  122. {
  123. ZZIP_MEM_ENTRY *item = zzip_mem_entry_new(disk, entry);
  124. if (! item)
  125. goto error;
  126. if (dir->last)
  127. {
  128. dir->last->zz_next = item; /* chain last */
  129. } else
  130. {
  131. dir->list = item;
  132. }
  133. dir->last = item; /* to earlier */
  134. count++;
  135. }
  136. ____;
  137. dir->disk = disk;
  138. return count;
  139. ____;
  140. error:
  141. zzip_mem_disk_unload(dir);
  142. return -1;
  143. }
  144. /** convert a zip disk entry to internal format.
  145. * creates a new item parsing the information out of the various places
  146. * in the zip archive. This is a good place to extend functionality if
  147. * you have a project with extra requirements as you can push more bits
  148. * right into the diskdir_entry for later usage in higher layers.
  149. * returns: new item, or null on error (setting errno)
  150. */
  151. zzip__new__ ZZIP_MEM_ENTRY *
  152. zzip_mem_entry_new(ZZIP_DISK * disk, ZZIP_DISK_ENTRY * entry)
  153. {
  154. if (! disk || ! entry)
  155. { errno=EINVAL; return 0; }
  156. ___ ZZIP_MEM_ENTRY *item = calloc(1, sizeof(*item));
  157. if (! item)
  158. return 0; /* errno=ENOMEM; */
  159. ___ struct zzip_file_header *header =
  160. zzip_disk_entry_to_file_header(disk, entry);
  161. /* there is a number of duplicated information in the file header
  162. * or the disk entry block. Theoretically some part may be missing
  163. * that exists in the other, ... but we will prefer the disk entry.
  164. */
  165. item->zz_comment = zzip_disk_entry_strdup_comment(disk, entry);
  166. item->zz_name = zzip_disk_entry_strdup_name(disk, entry);
  167. item->zz_data = zzip_file_header_to_data(header);
  168. item->zz_flags = zzip_disk_entry_get_flags(entry);
  169. item->zz_compr = zzip_disk_entry_get_compr(entry);
  170. item->zz_mktime = zzip_disk_entry_get_mktime(entry);
  171. item->zz_crc32 = zzip_disk_entry_get_crc32(entry);
  172. item->zz_csize = zzip_disk_entry_get_csize(entry);
  173. item->zz_usize = zzip_disk_entry_get_usize(entry);
  174. item->zz_diskstart = zzip_disk_entry_get_diskstart(entry);
  175. item->zz_filetype = zzip_disk_entry_get_filetype(entry);
  176. { /* copy the extra blocks to memory as well */
  177. int /* */ ext1 = zzip_disk_entry_get_extras(entry);
  178. char *_zzip_restrict ptr1 = zzip_disk_entry_to_extras(entry);
  179. int /* */ ext2 = zzip_file_header_get_extras(header);
  180. char *_zzip_restrict ptr2 = zzip_file_header_to_extras(header);
  181. if (ext1)
  182. {
  183. void *mem = malloc(ext1 + 2);
  184. item->zz_ext[1] = mem;
  185. memcpy(mem, ptr1, ext1);
  186. ((char *) (mem))[ext1 + 0] = 0;
  187. ((char *) (mem))[ext1 + 1] = 0;
  188. }
  189. if (ext2)
  190. {
  191. void *mem = malloc(ext2 + 2);
  192. item->zz_ext[2] = mem;
  193. memcpy(mem, ptr2, ext2);
  194. ((char *) (mem))[ext2 + 0] = 0;
  195. ((char *) (mem))[ext2 + 1] = 0;
  196. }
  197. }
  198. {
  199. /* override sizes/offsets with zip64 values for largefile support */
  200. zzip_extra_zip64 *block = (zzip_extra_zip64 *)
  201. zzip_mem_entry_extra_block(item, ZZIP_EXTRA_zip64);
  202. if (block)
  203. {
  204. item->zz_usize = __zzip_get64(block->z_usize);
  205. item->zz_csize = __zzip_get64(block->z_csize);
  206. item->zz_offset = __zzip_get64(block->z_offset);
  207. item->zz_diskstart = __zzip_get32(block->z_diskstart);
  208. }
  209. }
  210. /* NOTE:
  211. * All information from the central directory entry is now in memory.
  212. * Effectivly that allows us to modify it and write it back to disk.
  213. */
  214. return item;
  215. ____;
  216. ____;
  217. }
  218. /* find an extra block for the given datatype code.
  219. * We assume that the central directory has been preparsed to memory.
  220. */
  221. ZZIP_EXTRA_BLOCK *
  222. zzip_mem_entry_extra_block(ZZIP_MEM_ENTRY * entry, short datatype)
  223. {
  224. int i = 2;
  225. while (1)
  226. {
  227. ZZIP_EXTRA_BLOCK *ext = entry->zz_ext[i];
  228. if (ext)
  229. {
  230. while (*(short *) (ext->z_datatype))
  231. {
  232. if (datatype == zzip_extra_block_get_datatype(ext))
  233. {
  234. return ext;
  235. }
  236. ___ char *e = (char *) ext;
  237. e += zzip_extra_block_headerlength;
  238. e += zzip_extra_block_get_datasize(ext);
  239. ext = (void *) e;
  240. ____;
  241. }
  242. }
  243. if (! i)
  244. return 0;
  245. i--;
  246. }
  247. }
  248. void
  249. zzip_mem_entry_free(ZZIP_MEM_ENTRY * _zzip_restrict item)
  250. {
  251. if (item)
  252. {
  253. /* *INDENT-OFF* */
  254. if (item->zz_ext[0]) free (item->zz_ext[0]);
  255. if (item->zz_ext[1]) free (item->zz_ext[1]);
  256. if (item->zz_ext[2]) free (item->zz_ext[2]);
  257. if (item->zz_comment) free (item->zz_comment);
  258. if (item->zz_name) free (item->zz_name);
  259. free (item);
  260. /* *INDENT-ON* */
  261. }
  262. }
  263. void
  264. zzip_mem_disk_unload(ZZIP_MEM_DISK * dir)
  265. {
  266. ZZIP_MEM_ENTRY *item = dir->list;
  267. while (item)
  268. {
  269. ZZIP_MEM_ENTRY *next = item->zz_next;
  270. zzip_mem_entry_free(item);
  271. item = next;
  272. }
  273. dir->list = dir->last = 0;
  274. zzip_disk_close(dir->disk);
  275. dir->disk = 0;
  276. }
  277. void
  278. zzip_mem_disk_close(ZZIP_MEM_DISK * _zzip_restrict dir)
  279. {
  280. if (dir)
  281. {
  282. zzip_mem_disk_unload(dir);
  283. zzip_disk_close(dir->disk);
  284. free(dir);
  285. }
  286. }
  287. #if 0
  288. static void
  289. foo(short zz_datatype)
  290. {
  291. switch (zz_datatype)
  292. {
  293. /* *INDENT-OFF* */
  294. case 0x0001: /* ZIP64 extended information extra field */
  295. case 0x0007: /* AV Info */
  296. case 0x0008: /* Reserved for future Unicode file name data (PFS) */
  297. case 0x0009: /* OS/2 */
  298. case 0x000a: /* NTFS */
  299. case 0x000c: /* OpenVMS */
  300. case 0x000d: /* Unix */
  301. case 0x000e: /* Reserved for file stream and fork descriptors */
  302. case 0x000f: /* Patch Descriptor */
  303. case 0x0014: /* PKCS#7 Store for X.509 Certificates */
  304. case 0x0015: /* X.509 Certificate ID and Signature for file */
  305. case 0x0016: /* X.509 Certificate ID for Central Directory */
  306. case 0x0017: /* Strong Encryption Header */
  307. case 0x0018: /* Record Management Controls */
  308. case 0x0019: /* PKCS#7 Encryption Recipient Certificate List */
  309. case 0x0065: /* IBM S/390, AS/400 attributes - uncompressed */
  310. case 0x0066: /* Reserved for IBM S/390, AS/400 attr - compressed */
  311. case 0x07c8: /* Macintosh */
  312. case 0x2605: /* ZipIt Macintosh */
  313. case 0x2705: /* ZipIt Macintosh 1.3.5+ */
  314. case 0x2805: /* ZipIt Macintosh 1.3.5+ */
  315. case 0x334d: /* Info-ZIP Macintosh */
  316. case 0x4341: /* Acorn/SparkFS */
  317. case 0x4453: /* Windows NT security descriptor (binary ACL) */
  318. case 0x4704: /* VM/CMS */
  319. case 0x470f: /* MVS */
  320. case 0x4b46: /* FWKCS MD5 (see below) */
  321. case 0x4c41: /* OS/2 access control list (text ACL) */
  322. case 0x4d49: /* Info-ZIP OpenVMS */
  323. case 0x4f4c: /* Xceed original location extra field */
  324. case 0x5356: /* AOS/VS (ACL) */
  325. case 0x5455: /* extended timestamp */
  326. case 0x554e: /* Xceed unicode extra field */
  327. case 0x5855: /* Info-ZIP Unix (original, also OS/2, NT, etc) */
  328. case 0x6542: /* BeOS/BeBox */
  329. case 0x756e: /* ASi Unix */
  330. case 0x7855: /* Info-ZIP Unix (new) */
  331. case 0xfd4a: /* SMS/QDOS */
  332. /* *INDENT-ON* */
  333. }
  334. }
  335. #endif
  336. ZZIP_MEM_ENTRY *
  337. zzip_mem_disk_findfile(ZZIP_MEM_DISK * dir,
  338. char *filename, ZZIP_MEM_ENTRY * after,
  339. zzip_strcmp_fn_t compare)
  340. {
  341. ZZIP_MEM_ENTRY *entry = (! after ? dir->list : after->zz_next);
  342. if (! compare)
  343. compare = (zzip_strcmp_fn_t) (strcmp);
  344. for (; entry; entry = entry->zz_next)
  345. {
  346. if (! compare(filename, entry->zz_name))
  347. {
  348. return entry;
  349. }
  350. }
  351. return 0;
  352. }
  353. ZZIP_MEM_ENTRY *
  354. zzip_mem_disk_findmatch(ZZIP_MEM_DISK * dir,
  355. char *filespec, ZZIP_MEM_ENTRY * after,
  356. zzip_fnmatch_fn_t compare, int flags)
  357. {
  358. ZZIP_MEM_ENTRY *entry = (! after ? dir->list : after->zz_next);
  359. if (! compare)
  360. compare = (zzip_fnmatch_fn_t) _zzip_fnmatch;
  361. for (; entry; entry = entry->zz_next)
  362. {
  363. if (! compare(filespec, entry->zz_name, flags))
  364. {
  365. return entry;
  366. }
  367. }
  368. return 0;
  369. }
  370. zzip__new__ ZZIP_MEM_DISK_FILE *
  371. zzip_mem_entry_fopen(ZZIP_MEM_DISK * dir, ZZIP_MEM_ENTRY * entry)
  372. {
  373. /* keep this in sync with zzip_disk_entry_fopen */
  374. ZZIP_DISK_FILE *file = malloc(sizeof(ZZIP_MEM_DISK_FILE));
  375. if (! file)
  376. return file;
  377. file->buffer = dir->disk->buffer;
  378. file->endbuf = dir->disk->endbuf;
  379. file->avail = zzip_mem_entry_usize(entry);
  380. if (! file->avail || zzip_mem_entry_data_stored(entry))
  381. { file->stored = zzip_mem_entry_to_data (entry); return file; }
  382. file->stored = 0;
  383. file->zlib.opaque = 0;
  384. file->zlib.zalloc = Z_NULL;
  385. file->zlib.zfree = Z_NULL;
  386. file->zlib.avail_in = zzip_mem_entry_csize(entry);
  387. file->zlib.next_in = zzip_mem_entry_to_data(entry);
  388. if (! zzip_mem_entry_data_deflated(entry) ||
  389. inflateInit2(&file->zlib, -MAX_WBITS) != Z_OK)
  390. { free (file); return 0; }
  391. return file;
  392. }
  393. zzip__new__ ZZIP_MEM_DISK_FILE *
  394. zzip_mem_disk_fopen(ZZIP_MEM_DISK * dir, char *filename)
  395. {
  396. ZZIP_MEM_ENTRY *entry = zzip_mem_disk_findfile(dir, filename, 0, 0);
  397. if (! entry)
  398. return 0;
  399. else
  400. return zzip_mem_entry_fopen(dir, entry);
  401. }
  402. _zzip_size_t
  403. zzip_mem_disk_fread(void *ptr, _zzip_size_t size, _zzip_size_t nmemb,
  404. ZZIP_MEM_DISK_FILE * file)
  405. {
  406. return zzip_disk_fread(ptr, size, nmemb, file);
  407. }
  408. int
  409. zzip_mem_disk_fclose(ZZIP_MEM_DISK_FILE * file)
  410. {
  411. return zzip_disk_fclose(file);
  412. }
  413. int
  414. zzip_mem_disk_feof(ZZIP_MEM_DISK_FILE * file)
  415. {
  416. return zzip_disk_feof(file);
  417. }
  418. /* convert dostime of entry to unix time_t */
  419. long
  420. zzip_disk_entry_get_mktime(ZZIP_DISK_ENTRY * entry)
  421. {
  422. uint16_t dostime = ZZIP_GET16(entry->z_dostime.time);
  423. uint16_t dosdate = ZZIP_GET16(entry->z_dostime.date);
  424. struct tm date;
  425. date.tm_sec = (dostime) & 0x1F; /* bits 0..4 */
  426. date.tm_min = (dostime >> 5) & 0x3F; /* bits 5..10 */
  427. date.tm_hour = (dostime >> 11); /* bits 11..15 */
  428. date.tm_mday = (dosdate) & 0x1F; /* bits 16..20 */
  429. date.tm_mon = (dosdate >> 5) & 0xF; /* bits 21..24 */
  430. date.tm_year = (dosdate >> 9) + 80; /* bits 25..31 */
  431. return mktime(&date); /* well, unix has that function... */
  432. }