/src/zziplib/zzip/file.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 1180 lines · 727 code · 152 blank · 301 comment · 188 complexity · acbd1bb63248ef06b02808d59640be15 MD5 · raw file

  1. /*
  2. * Author:
  3. * Guido Draheim <guidod@gmx.de>
  4. * Tomi Ollila <Tomi.Ollila@iki.fi>
  5. *
  6. * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
  7. * All rights reserved,
  8. * use under the restrictions of the
  9. * Lesser GNU General Public License
  10. * or alternatively the restrictions
  11. * of the Mozilla Public License 1.1
  12. */
  13. #include <zzip/lib.h> /* exported... */
  14. #include <zzip/file.h>
  15. #include <string.h>
  16. #include <sys/stat.h>
  17. #include <errno.h>
  18. #include <stdlib.h>
  19. #include <ctype.h>
  20. #include <zzip/format.h>
  21. #include <zzip/fetch.h>
  22. #include <zzip/__debug.h>
  23. #if 0
  24. # if defined ZZIP_HAVE_IO_H
  25. # include <io.h> /* tell */
  26. # else
  27. # define tell(fd) lseek(fd,0,SEEK_CUR)
  28. # endif
  29. #else
  30. #define tells(fd) seeks(fd,0,SEEK_CUR)
  31. #endif
  32. /**
  33. * the direct function of => zzip_close(fp). it will cleanup the
  34. * inflate-portion of => zlib and free the structure given.
  35. *
  36. * it is called quite from the error-cleanup parts
  37. * of the various => _open functions.
  38. *
  39. * the .refcount is decreased and if zero the fp->dir is closed just as well.
  40. */
  41. int
  42. zzip_file_close(ZZIP_FILE * fp)
  43. {
  44. auto int self;
  45. ZZIP_DIR *dir = fp->dir;
  46. if (fp->method)
  47. inflateEnd(&fp->d_stream); /* inflateEnd() can be called many times */
  48. if (dir->cache.locked == NULL)
  49. dir->cache.locked = &self;
  50. if (fp->buf32k)
  51. {
  52. if (dir->cache.locked == &self && dir->cache.buf32k == NULL)
  53. dir->cache.buf32k = fp->buf32k;
  54. else
  55. free(fp->buf32k);
  56. }
  57. if (dir->currentfp == fp)
  58. dir->currentfp = NULL;
  59. dir->refcount--;
  60. /* ease to notice possible dangling reference errors */
  61. memset(fp, 0, sizeof(*fp));
  62. if (dir->cache.locked == &self && dir->cache.fp == NULL)
  63. dir->cache.fp = fp;
  64. else
  65. free(fp);
  66. if (dir->cache.locked == &self)
  67. dir->cache.locked = NULL;
  68. if (! dir->refcount)
  69. return zzip_dir_close(dir);
  70. else
  71. return 0;
  72. }
  73. static int
  74. zzip_file_saveoffset(ZZIP_FILE * fp)
  75. {
  76. if (fp)
  77. {
  78. int fd = fp->dir->fd;
  79. zzip_off_t off = fp->io->fd.seeks(fd, 0, SEEK_CUR);
  80. if (off < 0)
  81. return -1;
  82. fp->offset = off;
  83. }
  84. return 0;
  85. }
  86. /* user-definition */
  87. #ifndef ZZIP_BACKSLASH_DIRSEP
  88. #if defined HAVE_WINDOWS_H || defined ZZIP_HAVE_WINDOWS_H || defined _WIN32
  89. #define ZZIP_BACKSLASH_DIRSEP 1
  90. #elif defined ZZIP_CHECK_BACKSLASH_DIRSEPARATOR
  91. #define ZZIP_BACKSLASH_DIRSEP 1
  92. #else
  93. #define ZZIP_BACKSLASH_DIRSEP 0
  94. #endif
  95. #endif
  96. static zzip_char_t*
  97. strrchr_basename(zzip_char_t* name)
  98. {
  99. register zzip_char_t *n = strrchr(name, '/');
  100. if (n) return n + 1;
  101. return name;
  102. }
  103. static zzip_char_t*
  104. dirsep_basename(zzip_char_t* name)
  105. {
  106. register zzip_char_t *n = strrchr(name, '/');
  107. if (ZZIP_BACKSLASH_DIRSEP)
  108. {
  109. register zzip_char_t *m = strrchr(name, '\\');
  110. if (!n || (m && n < m))
  111. n = m;
  112. }
  113. if (n) return n + 1;
  114. return name;
  115. }
  116. #if defined strcasecmp
  117. #define dirsep_strcasecmp strcasecmp
  118. #else
  119. static int
  120. dirsep_strcasecmp(zzip_char_t * s1, zzip_char_t * s2)
  121. {
  122. /* ASCII tolower - including mapping of backslash in normal slash */
  123. static const char mapping[] = "@abcdefghijklmnopqrstuvwxyz[/]^_";
  124. int c1, c2;
  125. while (*s1 && *s2)
  126. {
  127. c1 = (int) (unsigned char) *s1;
  128. c2 = (int) (unsigned char) *s2;
  129. if ((c1 & 0xE0) == 0x40)
  130. c1 = mapping[c1 & 0x1f];
  131. if ((c2 & 0xE0) == 0x40)
  132. c2 = mapping[c2 & 0x1f];
  133. if (c1 != c2)
  134. return (c1 - c2);
  135. s1++;
  136. s2++;
  137. }
  138. return (((int) (unsigned char) *s1) - ((int) (unsigned char) *s2));
  139. }
  140. #endif
  141. static int zzip_inflate_init(ZZIP_FILE *, struct zzip_dir_hdr *);
  142. /**
  143. * open an => ZZIP_FILE from an already open => ZZIP_DIR handle. Since
  144. * we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk
  145. * this is the best choice to unpack multiple files.
  146. *
  147. * Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k
  148. * memchunk here... just to be safe.
  149. *
  150. * On error it returns null and sets errcode in the ZZIP_DIR.
  151. */
  152. ZZIP_FILE *
  153. zzip_file_open(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
  154. {
  155. auto int self;
  156. zzip_error_t err = 0;
  157. struct zzip_file *fp = 0;
  158. struct zzip_dir_hdr *hdr = dir->hdr0;
  159. int (*filename_strcmp) (zzip_char_t *, zzip_char_t *);
  160. zzip_char_t* (*filename_basename)(zzip_char_t*);
  161. filename_strcmp = (o_mode & ZZIP_CASELESS) ? dirsep_strcasecmp : strcmp;
  162. filename_basename = (o_mode & ZZIP_CASELESS) ? dirsep_basename : strrchr_basename;
  163. if (! dir)
  164. return NULL;
  165. if (! dir->fd || dir->fd == -1)
  166. { dir->errcode = EBADF; return NULL; }
  167. if (! hdr)
  168. { dir->errcode = ENOENT; return NULL; }
  169. if (o_mode & ZZIP_NOPATHS)
  170. name = filename_basename(name);
  171. while (1)
  172. {
  173. register zzip_char_t *hdr_name = hdr->d_name;
  174. if (o_mode & ZZIP_NOPATHS)
  175. hdr_name = filename_basename(hdr_name);
  176. HINT4("name='%s', compr=%d, size=%d\n",
  177. hdr->d_name, hdr->d_compr, hdr->d_usize);
  178. if (! filename_strcmp(hdr_name, name))
  179. {
  180. switch (hdr->d_compr)
  181. {
  182. case 0: /* store */
  183. case 8: /* inflate */
  184. break;
  185. default:
  186. { err = ZZIP_UNSUPP_COMPR; goto error; }
  187. }
  188. if (dir->cache.locked == NULL)
  189. dir->cache.locked = &self;
  190. if (dir->cache.locked == &self && dir->cache.fp)
  191. {
  192. fp = dir->cache.fp;
  193. dir->cache.fp = NULL;
  194. /* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */
  195. } else
  196. {
  197. if (! (fp = (ZZIP_FILE *) calloc(1, sizeof(*fp))))
  198. { err = ZZIP_OUTOFMEM; goto error; }
  199. }
  200. fp->dir = dir;
  201. fp->io = dir->io;
  202. dir->refcount++;
  203. if (dir->cache.locked == &self && dir->cache.buf32k)
  204. {
  205. fp->buf32k = dir->cache.buf32k;
  206. dir->cache.buf32k = NULL;
  207. } else
  208. {
  209. if (! (fp->buf32k = (char *) malloc(ZZIP_32K)))
  210. { err = ZZIP_OUTOFMEM; goto error; }
  211. }
  212. if (dir->cache.locked == &self)
  213. dir->cache.locked = NULL;
  214. /*
  215. * In order to support simultaneous open files in one zip archive
  216. * we'll fix the fd offset when opening new file/changing which
  217. * file to read...
  218. */
  219. if (zzip_file_saveoffset(dir->currentfp) < 0)
  220. { err = ZZIP_DIR_SEEK; goto error; }
  221. fp->offset = hdr->d_off;
  222. dir->currentfp = fp;
  223. if (dir->io->fd.seeks(dir->fd, hdr->d_off, SEEK_SET) < 0)
  224. { err = ZZIP_DIR_SEEK; goto error; }
  225. {
  226. /* skip local header - should test tons of other info,
  227. * but trust that those are correct */
  228. zzip_ssize_t dataoff;
  229. struct zzip_file_header *p = (void *) fp->buf32k;
  230. dataoff = dir->io->fd.read(dir->fd, (void *) p, sizeof(*p));
  231. if (dataoff < (zzip_ssize_t) sizeof(*p))
  232. { err = ZZIP_DIR_READ; goto error; }
  233. if (! zzip_file_header_check_magic(p)) /* PK\3\4 */
  234. { err = ZZIP_CORRUPTED; goto error; }
  235. dataoff = zzip_file_header_sizeof_tail(p);
  236. if (dir->io->fd.seeks(dir->fd, dataoff, SEEK_CUR) < 0)
  237. { err = ZZIP_DIR_SEEK; goto error; }
  238. fp->dataoffset = dir->io->fd.tells(dir->fd);
  239. fp->usize = hdr->d_usize;
  240. fp->csize = hdr->d_csize;
  241. }
  242. err = zzip_inflate_init(fp, hdr);
  243. if (err)
  244. goto error;
  245. return fp;
  246. } else
  247. {
  248. if (hdr->d_reclen == 0)
  249. break;
  250. hdr = (struct zzip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
  251. } /*filename_strcmp */
  252. } /*forever */
  253. dir->errcode = ZZIP_ENOENT;
  254. return NULL;
  255. error:
  256. if (fp)
  257. zzip_file_close(fp);
  258. dir->errcode = err;
  259. return NULL;
  260. }
  261. /**
  262. * call => inflateInit and setup fp's iterator variables,
  263. * used by lowlevel => _open functions.
  264. */
  265. static int
  266. zzip_inflate_init(ZZIP_FILE * fp, struct zzip_dir_hdr *hdr)
  267. {
  268. int err;
  269. fp->method = hdr->d_compr;
  270. fp->restlen = hdr->d_usize;
  271. if (fp->method)
  272. {
  273. memset(&fp->d_stream, 0, sizeof(fp->d_stream));
  274. err = inflateInit2(&fp->d_stream, -MAX_WBITS);
  275. if (err != Z_OK)
  276. goto error;
  277. fp->crestlen = hdr->d_csize;
  278. }
  279. return 0;
  280. error:
  281. if (fp)
  282. zzip_file_close(fp);
  283. return err;
  284. }
  285. /**
  286. * This function closes the given ZZIP_FILE handle.
  287. *
  288. * If the ZZIP_FILE wraps a normal stat'fd then it is just that int'fd
  289. * that is being closed and the otherwise empty ZZIP_FILE gets freed.
  290. */
  291. int
  292. zzip_fclose(ZZIP_FILE * fp)
  293. {
  294. if (! fp)
  295. return 0;
  296. if (! fp->dir) /* stat fd */
  297. { int r = fp->io->fd.close(fp->fd); free(fp); return r; }
  298. else
  299. return zzip_file_close(fp);
  300. }
  301. /** => zzip_fclose
  302. */
  303. int
  304. zzip_close(ZZIP_FILE * fp)
  305. {
  306. return zzip_fclose(fp);
  307. }
  308. /**
  309. * This functions read data from zip-contained file.
  310. *
  311. * It works like => read(2) and will fill the given buffer with bytes from
  312. * the opened file. It will return the number of bytes read, so if the => EOF
  313. * is encountered you will be prompted with the number of bytes actually read.
  314. *
  315. * This is the routines that needs the => buf32k buffer, and it would have
  316. * need for much more polishing but it does already work quite well.
  317. *
  318. * Note: the 32K buffer is rather big. The original inflate-algorithm
  319. * required just that but the latest zlib would work just fine with
  320. * a smaller buffer.
  321. */
  322. zzip_ssize_t
  323. zzip_file_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
  324. {
  325. ZZIP_DIR *dir;
  326. zzip_size_t l;
  327. zzip_ssize_t rv;
  328. if (! fp || ! fp->dir)
  329. return 0;
  330. dir = fp->dir;
  331. l = fp->restlen > len ? len : fp->restlen;
  332. if (fp->restlen == 0)
  333. return 0;
  334. /*
  335. * If this is other handle than previous, save current seek pointer
  336. * and read the file position of `this' handle.
  337. */
  338. if (dir->currentfp != fp)
  339. {
  340. if (zzip_file_saveoffset(dir->currentfp) < 0
  341. || fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
  342. { dir->errcode = ZZIP_DIR_SEEK; return -1; }
  343. else
  344. { dir->currentfp = fp; }
  345. }
  346. /* if more methods is to be supported, change this to `switch ()' */
  347. if (fp->method) /* method != 0 == 8, inflate */
  348. {
  349. fp->d_stream.avail_out = l;
  350. fp->d_stream.next_out = (unsigned char *) buf;
  351. do
  352. {
  353. int err;
  354. zzip_size_t startlen;
  355. if (fp->crestlen > 0 && fp->d_stream.avail_in == 0)
  356. {
  357. zzip_size_t cl = (fp->crestlen < ZZIP_32K ?
  358. fp->crestlen : ZZIP_32K);
  359. /* zzip_size_t cl =
  360. * fp->crestlen > 128 ? 128 : fp->crestlen;
  361. */
  362. zzip_ssize_t i = fp->io->fd.read(dir->fd, fp->buf32k, cl);
  363. if (i <= 0)
  364. {
  365. dir->errcode = ZZIP_DIR_READ;
  366. /* or ZZIP_DIR_READ_EOF ? */
  367. return -1;
  368. }
  369. fp->crestlen -= i;
  370. fp->d_stream.avail_in = i;
  371. fp->d_stream.next_in = (unsigned char *) fp->buf32k;
  372. }
  373. startlen = fp->d_stream.total_out;
  374. err = inflate(&fp->d_stream, Z_NO_FLUSH);
  375. if (err == Z_STREAM_END)
  376. { fp->restlen = 0; }
  377. else if (err == Z_OK)
  378. { fp->restlen -= (fp->d_stream.total_out - startlen); }
  379. else
  380. { dir->errcode = err; return -1; }
  381. }
  382. while (fp->restlen && fp->d_stream.avail_out);
  383. return l - fp->d_stream.avail_out;
  384. } else
  385. { /* method == 0 -- unstore */
  386. rv = fp->io->fd.read(dir->fd, buf, l);
  387. if (rv > 0)
  388. { fp->restlen-= rv; }
  389. else if (rv < 0)
  390. { dir->errcode = ZZIP_DIR_READ; }
  391. return rv;
  392. }
  393. }
  394. /**
  395. * This function will read(2) data from a real/zipped file.
  396. *
  397. * the replacement for => read(2) will fill the given buffer with bytes from
  398. * the opened file. It will return the number of bytes read, so if the EOF
  399. * is encountered you will be prompted with the number of bytes actually read.
  400. *
  401. * If the file-handle is wrapping a stat'able file then it will actually just
  402. * perform a normal => read(2)-call, otherwise => zzip_file_read is called
  403. * to decompress the data stream and any error is mapped to => errno(3).
  404. */
  405. zzip_ssize_t
  406. zzip_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
  407. {
  408. if (! fp)
  409. return 0;
  410. if (! fp->dir)
  411. { return fp->io->fd.read(fp->fd, buf, len); } /* stat fd */
  412. else
  413. {
  414. register zzip_ssize_t v;
  415. v = zzip_file_read(fp, buf, len);
  416. if (v == -1)
  417. { errno = zzip_errno(fp->dir->errcode); }
  418. return v;
  419. }
  420. }
  421. /** => zzip_read
  422. */
  423. zzip_size_t
  424. zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, ZZIP_FILE * file)
  425. {
  426. if (! size)
  427. size = 1;
  428. return zzip_read(file, ptr, size * nmemb) / size;
  429. }
  430. #define ZZIP_WRONLY O_WRONLY
  431. #define ZZIP_EXCL O_EXCL
  432. #if defined O_SYNC
  433. #define ZZIP_SYNC O_SYNC
  434. #else
  435. #define ZZIP_SYNC 0
  436. #endif
  437. #if defined O_NONBLOCK
  438. #define ZZIP_NONBLOCK O_NONBLOCK
  439. #elif defined O_NDELAY
  440. #define ZZIP_NOCTTY O_NDELAY
  441. #else
  442. #define ZZIP_NOCTTY 0
  443. #endif
  444. /* ------------------------------------------------------------------- */
  445. /** also: fopen(2)
  446. * This function will => fopen(3) a real/zipped file.
  447. *
  448. * It has some magic functionality builtin - it will first try to open
  449. * the given <em>filename</em> as a normal file. If it does not
  450. * exist, the given path to the filename (if any) is split into
  451. * its directory-part and the file-part. A ".zip" extension is
  452. * then added to the directory-part to create the name of a
  453. * zip-archive. That zip-archive (if it exists) is being searched
  454. * for the file-part, and if found a zzip-handle is returned.
  455. *
  456. * Note that if the file is found in the normal fs-directory the
  457. * returned structure is mostly empty and the => zzip_read call will
  458. * use the libc => read(2) to obtain data. Otherwise a => zzip_file_open
  459. * is performed and any error mapped to => errno(3).
  460. *
  461. * unlike the posix-wrapper => zzip_open the mode-argument is
  462. * a string which allows for more freedom to support the extra
  463. * zzip modes called ZZIP_CASEINSENSITIVE and ZZIP_IGNOREPATH.
  464. * Currently, this => zzip_fopen call will convert the following
  465. * characters in the mode-string into their corrsponding mode-bits:
  466. * * <code> "r" : O_RDONLY : </code> read-only
  467. * * <code> "b" : O_BINARY : </code> binary (win32 specific)
  468. * * <code> "f" : O_NOCTTY : </code> no char device (unix)
  469. * * <code> "i" : ZZIP_CASELESS : </code> inside zip file
  470. * * <code> "*" : ZZIP_NOPATHS : </code> inside zip file only
  471. * all other modes will be ignored for zip-contained entries
  472. * but they are transferred for compatibility and portability,
  473. * including these extra sugar bits:
  474. * * <code> "x" : O_EXCL :</code> fail if file did exist
  475. * * <code> "s" : O_SYNC :</code> synchronized access
  476. * * <code> "n" : O_NONBLOCK :</code> nonblocking access
  477. * * <code> "z#" : compression level :</code> for zlib
  478. * * <code> "g#" : group access :</code> unix access bits
  479. * * <code> "u#" : owner access :</code> unix access bits
  480. * * <code> "o#" : world access :</code> unix access bits
  481. * ... the access bits are in traditional unix bit format
  482. * with 7 = read/write/execute, 6 = read/write, 4 = read-only.
  483. *
  484. * The default access mode is 0664, and the compression level
  485. * is ignored since the lib can not yet write zip files, otherwise
  486. * it would be the initialisation value for the zlib deflateInit
  487. * where 0 = no-compression, 1 = best-speed, 9 = best-compression.
  488. *
  489. * This function returns a new zzip-handle (use => zzip_close to return
  490. * it). On error this function will return null setting => errno(3).
  491. */
  492. ZZIP_FILE *
  493. zzip_fopen(zzip_char_t * filename, zzip_char_t * mode)
  494. {
  495. return zzip_freopen(filename, mode, 0);
  496. }
  497. /** => zzip_fopen
  498. *
  499. * This function receives an additional argument pointing to
  500. * a ZZIP_FILE* being already in use. If this extra argument is
  501. * null then this function is identical with calling => zzip_fopen
  502. *
  503. * Per default, the old file stream is closed and only the internal
  504. * structures associated with it are kept. These internal structures
  505. * may be reused for the return value, and this is a lot quicker when
  506. * the filename matches a zipped file that is incidently in the very
  507. * same zip arch as the old filename wrapped in the stream struct.
  508. *
  509. * That's simply because the zip arch's central directory does not
  510. * need to be read again. As an extension for this function, if the
  511. * mode-string contains a "q" then the old stream is not closed but
  512. * left untouched, instead it is only given as a hint that a new
  513. * file handle may share/copy the zip arch structures of the old file
  514. * handle if that is possible, i.e when they are in the same zip arch.
  515. *
  516. * This function returns a new zzip-handle (use => zzip_close to return
  517. * it). On error this function will return null setting => errno(3).
  518. */
  519. ZZIP_FILE *
  520. zzip_freopen(zzip_char_t * filename, zzip_char_t * mode, ZZIP_FILE * stream)
  521. {
  522. int o_flags = 0;
  523. int o_modes = 0664;
  524. if (! mode)
  525. mode = "rb";
  526. # ifndef O_BINARY
  527. # define O_BINARY 0
  528. # endif
  529. # ifndef O_NOCTTY
  530. # define O_NOCTTY 0
  531. # endif
  532. # ifndef O_SYNC
  533. # define O_SYNC 0
  534. # endif
  535. # ifndef O_NONBLOCK
  536. # define O_NONBLOCK 0
  537. # endif
  538. for (; *mode; mode++)
  539. {
  540. switch (*mode)
  541. {
  542. /* *INDENT-OFF* */
  543. case '0': case '1': case '2': case '3': case '4':
  544. case '5': case '6': case '7': case '8': case '9':
  545. continue; /* ignore if not attached to other info */
  546. case 'r': o_flags |= mode[1] == '+' ? O_RDWR : O_RDONLY; break;
  547. case 'w': o_flags |= mode[1] == '+' ? O_RDWR : O_WRONLY;
  548. o_flags |= O_TRUNC; break;
  549. case 'b': o_flags |= O_BINARY; break;
  550. case 'f': o_flags |= O_NOCTTY; break;
  551. case 'i': o_modes |= ZZIP_CASELESS; break;
  552. case '*': o_modes |= ZZIP_NOPATHS; break;
  553. case 'x': o_flags |= O_EXCL; break;
  554. case 's': o_flags |= O_SYNC; break;
  555. case 'n': o_flags |= O_NONBLOCK; break;
  556. case 'o': o_modes &=~ 07;
  557. o_modes |= ((mode[1] - '0')) & 07; continue;
  558. case 'g': o_modes &=~ 070;
  559. o_modes |= ((mode[1] - '0') << 3) & 070; continue;
  560. case 'u': o_modes &=~ 0700;
  561. o_modes |= ((mode[1] - '0') << 6) & 0700; continue;
  562. case 'q': o_modes |= ZZIP_FACTORY; break;
  563. case 'z': /* compression level */
  564. continue; /* currently ignored, just for write mode */
  565. /* *INDENT-ON* */
  566. }
  567. }
  568. {
  569. ZZIP_FILE *fp =
  570. zzip_open_shared_io(stream, filename, o_flags, o_modes, 0, 0);
  571. if (! (o_modes & ZZIP_FACTORY) && stream)
  572. zzip_file_close(stream);
  573. return fp;
  574. }
  575. }
  576. /**
  577. * This function will => open(2) a real/zipped file
  578. *
  579. * It has some magic functionality builtin - it will first try to open
  580. * the given <em>filename</em> as a normal file. If it does not
  581. * exist, the given path to the filename (if any) is split into
  582. * its directory-part and the file-part. A ".zip" extension is
  583. * then added to the directory-part to create the name of a
  584. * zip-archive. That zip-archive (if it exists) is being searched
  585. * for the file-part, and if found a zzip-handle is returned.
  586. *
  587. * Note that if the file is found in the normal fs-directory the
  588. * returned structure is mostly empty and the => zzip_read call will
  589. * use the libc => read(2) to obtain data. Otherwise a => zzip_file_open
  590. * is performed and any error mapped to => errno(3).
  591. *
  592. * There was a possibility to transfer zziplib-specific openmodes
  593. * through o_flags but you should please not use them anymore and
  594. * look into => zzip_open_ext_io to submit them down. This function
  595. * is shallow in that it just extracts the zzipflags and calls
  596. * * <code>zzip_open_ext_io(filename, o_flags, zzipflags|0664, 0, 0) </code>
  597. * you must stop using this extra functionality (not well known anyway)
  598. * since zzip_open might be later usable to open files for writing
  599. * in which case the _EXTRAFLAGS will get in conflict.
  600. *
  601. * compare with => open(2) and => zzip_fopen
  602. */
  603. ZZIP_FILE *
  604. zzip_open(zzip_char_t * filename, int o_flags)
  605. {
  606. /* backward compatibility */
  607. int o_modes = 0664;
  608. if (o_flags & ZZIP_CASEINSENSITIVE)
  609. { o_flags ^= ZZIP_CASEINSENSITIVE; o_modes |= ZZIP_CASELESS; }
  610. if (o_flags & ZZIP_IGNOREPATH)
  611. { o_flags ^= ZZIP_IGNOREPATH; o_modes |= ZZIP_NOPATHS; }
  612. return zzip_open_ext_io(filename, o_flags, o_modes, 0, 0);
  613. }
  614. /* ZZIP_ONLYZIP won't work on platforms with sizeof(int) == 16bit */
  615. #if ZZIP_SIZEOF_INT+0 == 2
  616. #undef ZZIP_ONLYZIP
  617. #endif
  618. /** => zzip_open
  619. *
  620. * This function uses explicit ext and io instead of the internal
  621. * defaults, setting them to zero is equivalent to => zzip_open
  622. *
  623. * note that the two flag types have been split into an o_flags
  624. * (for fcntl-like openflags) and o_modes where the latter shall
  625. * carry the zzip_flags and possibly accessmodes for unix filesystems.
  626. * Since this version of zziplib can not write zipfiles, it is not
  627. * yet used for anything else than zzip-specific modeflags.
  628. *
  629. * This function returns a new zzip-handle (use => zzip_close to return
  630. * it). On error this function will return null setting => errno(3).
  631. *
  632. * If any ext_io handlers were used then the referenced structure
  633. * should be static as the allocated ZZIP_FILE does not copy them.
  634. */
  635. ZZIP_FILE *
  636. zzip_open_ext_io(zzip_char_t * filename, int o_flags, int o_modes,
  637. zzip_strings_t * ext, zzip_plugin_io_t io)
  638. {
  639. return zzip_open_shared_io(0, filename, o_flags, o_modes, ext, io);
  640. }
  641. /** => zzip_open
  642. *
  643. * This function takes an extra stream argument - if a handle has been
  644. * then ext/io can be left null and the new stream handle will pick up
  645. * the ext/io. This should be used only in specific environment however
  646. * since => zzip_file_real does not store any ext-sequence.
  647. *
  648. * The benefit for this function comes in when the old file handle
  649. * was openened from a file within a zip archive. When the new file
  650. * is in the same zip archive then the internal zzip_dir structures
  651. * will be shared. It is even quicker, as no check needs to be done
  652. * anymore trying to guess the zip archive place in the filesystem,
  653. * here we just check whether the zip archive's filepath is a prefix
  654. * part of the filename to be opened.
  655. *
  656. * Note that this function is also used by => zzip_freopen that
  657. * will unshare the old handle, thereby possibly closing the handle.
  658. *
  659. * This function returns a new zzip-handle (use => zzip_close to return
  660. * it). On error this function will return null setting => errno(3).
  661. */
  662. ZZIP_FILE *
  663. zzip_open_shared_io(ZZIP_FILE * stream,
  664. zzip_char_t * filename, int o_flags, int o_modes,
  665. zzip_strings_t * ext, zzip_plugin_io_t io)
  666. {
  667. if (stream && stream->dir)
  668. {
  669. if (! ext)
  670. ext = stream->dir->fileext;
  671. if (! io)
  672. io = stream->dir->io;
  673. }
  674. if (! io)
  675. io = zzip_get_default_io();
  676. if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
  677. goto try_zzip;
  678. try_real:
  679. /* prefer an existing real file */
  680. {
  681. zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL)
  682. ? zzip_get_default_io() : io;
  683. int fd = (os->fd.open)(filename, o_flags); /* io->fd.open */
  684. if (fd != -1)
  685. {
  686. ZZIP_FILE *fp = calloc(1, sizeof(ZZIP_FILE));
  687. if (! fp)
  688. { os->fd.close(fd); return 0; } /* io->fd.close */
  689. fp->fd = fd;
  690. fp->io = os;
  691. return fp;
  692. }
  693. if (o_modes & ZZIP_PREFERZIP)
  694. return 0;
  695. }
  696. try_zzip:
  697. /* if the user had it in place of a normal xopen, then
  698. * we better defend this lib against illegal usage */
  699. if (o_flags & (O_CREAT | O_WRONLY))
  700. { errno = EINVAL; return 0; }
  701. if (o_flags & (O_RDWR))
  702. { o_flags ^= O_RDWR; o_flags |= O_RDONLY; }
  703. /* this is just for backward compatibility -and strictly needed to
  704. * prepare ourselves for more options and more options later on... */
  705. /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */
  706. /*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */
  707. /* see if we can open a file that is a zip file */
  708. {
  709. char basename[PATH_MAX];
  710. char *p;
  711. int filename_len = strlen(filename);
  712. if (filename_len >= PATH_MAX)
  713. { errno = ENAMETOOLONG; return 0; }
  714. memcpy(basename, filename, filename_len + 1);
  715. /* see if we can share the same zip directory */
  716. if (stream && stream->dir && stream->dir->realname)
  717. {
  718. zzip_size_t len = strlen(stream->dir->realname);
  719. if (! memcmp(filename, stream->dir->realname, len) &&
  720. filename[len] == '/' && filename[len + 1])
  721. {
  722. ZZIP_FILE *fp =
  723. zzip_file_open(stream->dir, filename + len + 1, o_modes);
  724. if (! fp)
  725. { errno = zzip_errno (stream->dir->errcode); }
  726. return fp;
  727. }
  728. }
  729. /* per each slash in filename, check if it there is a zzip around */
  730. while ((p = strrchr(basename, '/')))
  731. {
  732. zzip_error_t e = 0;
  733. ZZIP_DIR *dir;
  734. ZZIP_FILE *fp;
  735. int fd;
  736. *p = '\0';
  737. /* i.e. cut at path separator == possible zipfile basename */
  738. fd = __zzip_try_open(basename, o_flags | O_RDONLY | O_BINARY,
  739. ext, io);
  740. if (fd == -1)
  741. { continue; }
  742. /* found zip-file .... now try to parse it */
  743. dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io);
  744. if (e)
  745. { errno = zzip_errno(e); io->fd.close(fd); return 0; }
  746. /* (p - basename) is the lenghtof zzip_dir part of the filename */
  747. fp = zzip_file_open(dir, filename + (p - basename) + 1, o_modes);
  748. if (! fp)
  749. { errno = zzip_errno(dir->errcode); }
  750. else
  751. { if (! dir->realname) dir->realname = strdup (basename); }
  752. zzip_dir_close(dir);
  753. /* note: since (fp) is attached that (dir) will survive */
  754. /* but (dir) is implicitly closed on next zzip_close(fp) */
  755. return fp;
  756. }
  757. if (o_modes & ZZIP_PREFERZIP)
  758. goto try_real;
  759. else
  760. { errno = ENOENT; return 0; }
  761. }
  762. }
  763. #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
  764. #undef zzip_open_shared_io /* zzip_open_shared_io64 */
  765. #undef zzip_open_ext_io /* zzip_open_ext_io64 */
  766. #undef zzip_opendir_ext_io /* zzip_opendir_ext_io64 */
  767. ZZIP_FILE *zzip_open_shared_io(ZZIP_FILE * stream,
  768. zzip_char_t * name, int o_flags,
  769. int o_modes, zzip_strings_t * ext,
  770. zzip_plugin_io_t io);
  771. ZZIP_FILE *zzip_open_ext_io(zzip_char_t * name, int o_flags,
  772. int o_modes, zzip_strings_t * ext,
  773. zzip_plugin_io_t io);
  774. ZZIP_DIR *zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
  775. zzip_strings_t * ext, zzip_plugin_io_t io);
  776. /* DLL compatibility layer - so that 32bit code can link with this lib too */
  777. ZZIP_FILE *
  778. zzip_open_shared_io(ZZIP_FILE * stream,
  779. zzip_char_t * name, int o_flags,
  780. int o_modes, zzip_strings_t * ext, zzip_plugin_io_t io)
  781. {
  782. if (! io)
  783. return zzip_open_shared_io64(stream, name, o_flags, o_modes, ext, io);
  784. errno = EOVERFLOW;
  785. return NULL;
  786. }
  787. ZZIP_FILE *
  788. zzip_open_ext_io(zzip_char_t * name, int o_flags, int o_modes,
  789. zzip_strings_t * ext, zzip_plugin_io_t io)
  790. {
  791. if (! io)
  792. return zzip_open_ext_io64(name, o_flags, o_modes, ext, io);
  793. errno = EOVERFLOW;
  794. return NULL;
  795. }
  796. ZZIP_DIR *
  797. zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
  798. zzip_strings_t * ext, zzip_plugin_io_t io)
  799. {
  800. if (! io)
  801. return zzip_opendir_ext_io64(name, o_modes, ext, io);
  802. else
  803. { errno = EOVERFLOW; return NULL; }
  804. }
  805. #endif /* ZZIP_LARGEFILE_RENAME && EOVERFLOW && PIC */
  806. /* ------------------------------------------------------------------- */
  807. /**
  808. * This function will rewind a real/zipped file.
  809. *
  810. * It seeks to the beginning of this file's data in the zip,
  811. * or the beginning of the file for a stat'fd.
  812. */
  813. int
  814. zzip_rewind(ZZIP_FILE * fp)
  815. {
  816. ZZIP_DIR *dir;
  817. int err;
  818. if (! fp)
  819. return -1;
  820. if (! fp->dir)
  821. { /* stat fd */
  822. fp->io->fd.seeks(fp->fd, 0, SEEK_SET);
  823. return 0;
  824. }
  825. dir = fp->dir;
  826. /*
  827. * If this is other handle than previous, save current seek pointer
  828. */
  829. if (dir->currentfp != fp)
  830. {
  831. if (zzip_file_saveoffset(dir->currentfp) < 0)
  832. { dir->errcode = ZZIP_DIR_SEEK; return -1; }
  833. else
  834. { dir->currentfp = fp; }
  835. }
  836. /* seek to beginning of this file */
  837. if (fp->io->fd.seeks(dir->fd, fp->dataoffset, SEEK_SET) < 0)
  838. return -1;
  839. /* reset the inflate init stuff */
  840. fp->restlen = fp->usize;
  841. fp->offset = fp->dataoffset;
  842. if (fp->method)
  843. { /* method == 8, deflate */
  844. err = inflateReset(&fp->d_stream);
  845. if (err != Z_OK)
  846. goto error;
  847. /* start over at next inflate with a fresh read() */
  848. fp->d_stream.avail_in = 0;
  849. fp->crestlen = fp->csize;
  850. }
  851. return 0;
  852. error:
  853. if (fp)
  854. zzip_file_close(fp);
  855. return err;
  856. }
  857. /**
  858. * This function will perform a => lseek(2) operation on a real/zipped file
  859. *
  860. * It will try to seek to the offset specified by offset, relative to whence,
  861. * which is one of SEEK_SET, SEEK_CUR or SEEK_END.
  862. *
  863. * If the file-handle is wrapping a stat'able file then it will actually just
  864. * perform a normal => lseek(2)-call. Otherwise the relative offset
  865. * is calculated, negative offsets are transformed into positive ones
  866. * by rewinding the file, and then data is read until the offset is
  867. * reached. This can make the function terribly slow, but this is
  868. * how gzio implements it, so I'm not sure there is a better way
  869. * without using the internals of the algorithm.
  870. */
  871. zzip_off_t
  872. zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence)
  873. {
  874. zzip_off_t cur_pos, rel_ofs, read_size, ofs;
  875. ZZIP_DIR *dir;
  876. if (! fp)
  877. return -1;
  878. if (! fp->dir)
  879. { /* stat fd */
  880. return fp->io->fd.seeks(fp->fd, offset, whence);
  881. }
  882. cur_pos = zzip_tell(fp);
  883. /* calculate relative offset */
  884. switch (whence)
  885. {
  886. case SEEK_SET: /* from beginning */
  887. rel_ofs = offset - cur_pos;
  888. break;
  889. case SEEK_CUR: /* from current */
  890. rel_ofs = offset;
  891. break;
  892. case SEEK_END: /* from end */
  893. rel_ofs = fp->usize + offset - cur_pos;
  894. break;
  895. default: /* something wrong */
  896. return -1;
  897. }
  898. if (rel_ofs == 0)
  899. return cur_pos; /* don't have to move */
  900. if (rel_ofs < 0)
  901. { /* convert backward into forward */
  902. if (zzip_rewind(fp) == -1)
  903. return -1;
  904. read_size = cur_pos + rel_ofs;
  905. cur_pos = 0;
  906. } else
  907. { /* amount to read is positive relative offset */
  908. read_size = rel_ofs;
  909. }
  910. if (read_size < 0) /* bad offset, before beginning of file */
  911. return -1;
  912. if (read_size + cur_pos > (zzip_off_t) fp->usize) /* bad offset, past EOF */
  913. return -1;
  914. if (read_size == 0) /* nothing to read */
  915. return cur_pos;
  916. dir = fp->dir;
  917. /*
  918. * If this is other handle than previous, save current seek pointer
  919. * and read the file position of `this' handle.
  920. */
  921. if (dir->currentfp != fp)
  922. {
  923. if (zzip_file_saveoffset(dir->currentfp) < 0
  924. || fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
  925. { dir->errcode = ZZIP_DIR_SEEK; return -1; }
  926. else
  927. { dir->currentfp = fp; }
  928. }
  929. if (fp->method == 0)
  930. { /* unstore, just lseek relatively */
  931. ofs = fp->io->fd.tells(dir->fd);
  932. ofs = fp->io->fd.seeks(dir->fd, read_size, SEEK_CUR);
  933. if (ofs > 0)
  934. { /* readjust from beginning of file */
  935. ofs -= fp->dataoffset;
  936. fp->restlen = fp->usize - ofs;
  937. }
  938. return ofs;
  939. } else
  940. { /* method == 8, inflate */
  941. char *buf;
  942. /*FIXME: use a static buffer! */
  943. buf = (char *) malloc(ZZIP_32K);
  944. if (! buf)
  945. return -1;
  946. while (read_size > 0)
  947. {
  948. zzip_off_t size = ZZIP_32K;
  949. if (read_size < size /*32K */ )
  950. size = read_size;
  951. size = zzip_file_read(fp, buf, (zzip_size_t) size);
  952. if (size <= 0)
  953. { free(buf); return -1; }
  954. read_size -= size;
  955. }
  956. free(buf);
  957. }
  958. return zzip_tell(fp);
  959. }
  960. /**
  961. * This function will => tell(2) the current position in a real/zipped file
  962. *
  963. * It will return the current offset within the real/zipped file,
  964. * measured in uncompressed bytes for the zipped-file case.
  965. *
  966. * If the file-handle is wrapping a stat'able file then it will actually just
  967. * perform a normal => tell(2)-call, otherwise the offset is
  968. * calculated from the amount of data left and the total uncompressed
  969. * size;
  970. */
  971. zzip_off_t
  972. zzip_tell(ZZIP_FILE * fp)
  973. {
  974. if (! fp)
  975. return -1;
  976. if (! fp->dir) /* stat fd */
  977. return fp->io->fd.tells(fp->fd);
  978. /* current uncompressed offset is uncompressed size - data left */
  979. return (fp->usize - fp->restlen);
  980. }
  981. #ifndef EOVERFLOW
  982. #define EOVERFLOW EFBIG
  983. #endif
  984. /** => zzip_tell
  985. * This function is provided for users who can not use any largefile-mode.
  986. */
  987. long
  988. zzip_tell32(ZZIP_FILE * fp)
  989. {
  990. if (sizeof(zzip_off_t) == sizeof(long))
  991. {
  992. return zzip_tell(fp);
  993. } else
  994. {
  995. off_t off = zzip_tell(fp);
  996. if (off >= 0) {
  997. register long off32 = off;
  998. if (off32 == off) return off32;
  999. errno = EOVERFLOW;
  1000. }
  1001. return -1;
  1002. }
  1003. }
  1004. /** => zzip_seek
  1005. * This function is provided for users who can not use any largefile-mode.
  1006. */
  1007. long
  1008. zzip_seek32(ZZIP_FILE * fp, long offset, int whence)
  1009. {
  1010. if (sizeof(zzip_off_t) == sizeof(long))
  1011. {
  1012. return zzip_seek(fp, offset, whence);
  1013. } else
  1014. {
  1015. off_t off = zzip_seek(fp, offset, whence);
  1016. if (off >= 0) {
  1017. register long off32 = off;
  1018. if (off32 == off) return off32;
  1019. errno = EOVERFLOW;
  1020. }
  1021. return -1;
  1022. }
  1023. }
  1024. /*
  1025. * Local variables:
  1026. * c-file-style: "stroustrup"
  1027. * End:
  1028. */