PageRenderTime 107ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/netbsd/src/external/bsd/file/dist/src/compress.c

https://bitbucket.org/killerpenguinassassins/open_distrib_devel
C | 511 lines | 399 code | 46 blank | 66 comment | 106 complexity | 2a8223c9414dbb294a3df6a1ce679e92 MD5 | raw file
Possible License(s): CC0-1.0, MIT, LGPL-2.0, LGPL-3.0, WTFPL, GPL-2.0, BSD-2-Clause, AGPL-3.0, CC-BY-SA-3.0, MPL-2.0, JSON, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.1, CPL-1.0, AGPL-1.0, 0BSD, ISC, Apache-2.0, GPL-3.0, IPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* $NetBSD: compress.c,v 1.5 2012/02/22 17:53:51 christos Exp $ */
  2. /*
  3. * Copyright (c) Ian F. Darwin 1986-1995.
  4. * Software written by Ian F. Darwin and others;
  5. * maintained 1995-present by Christos Zoulas and others.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice immediately at the beginning of the file, without modification,
  12. * this list of conditions, and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  21. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * compress routines:
  31. * zmagic() - returns 0 if not recognized, uncompresses and prints
  32. * information if recognized
  33. * uncompress(method, old, n, newch) - uncompress old into new,
  34. * using method, return sizeof new
  35. */
  36. #include "file.h"
  37. #ifndef lint
  38. #if 0
  39. FILE_RCSID("@(#)$File: compress.c,v 1.68 2011/12/08 12:38:24 rrt Exp $")
  40. #else
  41. __RCSID("$NetBSD: compress.c,v 1.5 2012/02/22 17:53:51 christos Exp $");
  42. #endif
  43. #endif
  44. #include "magic.h"
  45. #include <stdlib.h>
  46. #ifdef HAVE_UNISTD_H
  47. #include <unistd.h>
  48. #endif
  49. #include <string.h>
  50. #include <errno.h>
  51. #ifndef __MINGW32__
  52. #include <sys/ioctl.h>
  53. #endif
  54. #ifdef HAVE_SYS_WAIT_H
  55. #include <sys/wait.h>
  56. #endif
  57. #if defined(HAVE_SYS_TIME_H)
  58. #include <sys/time.h>
  59. #endif
  60. #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
  61. #define BUILTIN_DECOMPRESS
  62. #include <zlib.h>
  63. #endif
  64. private const struct {
  65. const char magic[8];
  66. size_t maglen;
  67. const char *argv[3];
  68. int silent;
  69. } compr[] = {
  70. { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */
  71. /* Uncompress can get stuck; so use gzip first if we have it
  72. * Idea from Damien Clark, thanks! */
  73. { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */
  74. { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */
  75. { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */
  76. { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */
  77. /* the standard pack utilities do not accept standard input */
  78. { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */
  79. { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 }, /* pkzipped, */
  80. /* ...only first file examined */
  81. { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */
  82. { "LZIP", 4, { "lzip", "-cdq", NULL }, 1 },
  83. { "\3757zXZ\0",6,{ "xz", "-cd", NULL }, 1 }, /* XZ Utils */
  84. { "LRZI", 4, { "lrzip", "-dqo-", NULL }, 1 }, /* LRZIP */
  85. };
  86. #define NODATA ((size_t)~0)
  87. private ssize_t swrite(int, const void *, size_t);
  88. #if HAVE_FORK
  89. private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
  90. private size_t uncompressbuf(struct magic_set *, int, size_t,
  91. const unsigned char *, unsigned char **, size_t);
  92. #ifdef BUILTIN_DECOMPRESS
  93. private size_t uncompressgzipped(struct magic_set *, const unsigned char *,
  94. unsigned char **, size_t);
  95. #endif
  96. protected int
  97. file_zmagic(struct magic_set *ms, int fd, const char *name,
  98. const unsigned char *buf, size_t nbytes)
  99. {
  100. unsigned char *newbuf = NULL;
  101. size_t i, nsz;
  102. int rv = 0;
  103. int mime = ms->flags & MAGIC_MIME;
  104. if ((ms->flags & MAGIC_COMPRESS) == 0)
  105. return 0;
  106. for (i = 0; i < ncompr; i++) {
  107. if (nbytes < compr[i].maglen)
  108. continue;
  109. if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
  110. (nsz = uncompressbuf(ms, fd, i, buf, &newbuf,
  111. nbytes)) != NODATA) {
  112. ms->flags &= ~MAGIC_COMPRESS;
  113. rv = -1;
  114. if (file_buffer(ms, -1, name, newbuf, nsz) == -1)
  115. goto error;
  116. if (mime == MAGIC_MIME || mime == 0) {
  117. if (file_printf(ms, mime ?
  118. " compressed-encoding=" : " (") == -1)
  119. goto error;
  120. }
  121. if ((mime == 0 || mime & MAGIC_MIME_ENCODING) &&
  122. file_buffer(ms, -1, NULL, buf, nbytes) == -1)
  123. goto error;
  124. if (!mime && file_printf(ms, ")") == -1)
  125. goto error;
  126. rv = 1;
  127. break;
  128. }
  129. }
  130. error:
  131. free(newbuf);
  132. ms->flags |= MAGIC_COMPRESS;
  133. return rv;
  134. }
  135. #endif
  136. /*
  137. * `safe' write for sockets and pipes.
  138. */
  139. private ssize_t
  140. swrite(int fd, const void *buf, size_t n)
  141. {
  142. ssize_t rv;
  143. size_t rn = n;
  144. do
  145. switch (rv = write(fd, buf, n)) {
  146. case -1:
  147. if (errno == EINTR)
  148. continue;
  149. return -1;
  150. default:
  151. n -= rv;
  152. buf = CAST(const char *, buf) + rv;
  153. break;
  154. }
  155. while (n > 0);
  156. return rn;
  157. }
  158. /*
  159. * `safe' read for sockets and pipes.
  160. */
  161. protected ssize_t
  162. sread(int fd, void *buf, size_t n, int canbepipe __attribute__ ((unused)))
  163. {
  164. ssize_t rv;
  165. #ifdef FD_ZERO
  166. ssize_t cnt;
  167. #endif
  168. #ifdef FIONREAD
  169. int t = 0;
  170. #endif
  171. size_t rn = n;
  172. if (fd == STDIN_FILENO)
  173. goto nocheck;
  174. #ifdef FIONREAD
  175. if ((canbepipe && (ioctl(fd, FIONREAD, &t) == -1)) || (t == 0)) {
  176. #ifdef FD_ZERO
  177. for (cnt = 0;; cnt++) {
  178. fd_set check;
  179. struct timeval tout = {0, 100 * 1000};
  180. int selrv;
  181. FD_ZERO(&check);
  182. FD_SET(fd, &check);
  183. /*
  184. * Avoid soft deadlock: do not read if there
  185. * is nothing to read from sockets and pipes.
  186. */
  187. selrv = select(fd + 1, &check, NULL, NULL, &tout);
  188. if (selrv == -1) {
  189. if (errno == EINTR || errno == EAGAIN)
  190. continue;
  191. } else if (selrv == 0 && cnt >= 5) {
  192. return 0;
  193. } else
  194. break;
  195. }
  196. #endif
  197. (void)ioctl(fd, FIONREAD, &t);
  198. }
  199. if (t > 0 && (size_t)t < n) {
  200. n = t;
  201. rn = n;
  202. }
  203. #endif
  204. nocheck:
  205. do
  206. switch ((rv = read(fd, buf, n))) {
  207. case -1:
  208. if (errno == EINTR)
  209. continue;
  210. return -1;
  211. case 0:
  212. return rn - n;
  213. default:
  214. n -= rv;
  215. buf = ((char *)buf) + rv;
  216. break;
  217. }
  218. while (n > 0);
  219. return rn;
  220. }
  221. protected int
  222. file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
  223. size_t nbytes)
  224. {
  225. char buf[4096];
  226. ssize_t r;
  227. int tfd;
  228. #ifdef HAVE_MKSTEMP
  229. int te;
  230. #endif
  231. (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
  232. #ifndef HAVE_MKSTEMP
  233. {
  234. char *ptr = mktemp(buf);
  235. tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
  236. r = errno;
  237. (void)unlink(ptr);
  238. errno = r;
  239. }
  240. #else
  241. tfd = mkstemp(buf);
  242. te = errno;
  243. (void)unlink(buf);
  244. errno = te;
  245. #endif
  246. if (tfd == -1) {
  247. file_error(ms, errno,
  248. "cannot create temporary file for pipe copy");
  249. return -1;
  250. }
  251. if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
  252. r = 1;
  253. else {
  254. while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
  255. if (swrite(tfd, buf, (size_t)r) != r)
  256. break;
  257. }
  258. switch (r) {
  259. case -1:
  260. file_error(ms, errno, "error copying from pipe to temp file");
  261. return -1;
  262. case 0:
  263. break;
  264. default:
  265. file_error(ms, errno, "error while writing to temp file");
  266. return -1;
  267. }
  268. /*
  269. * We duplicate the file descriptor, because fclose on a
  270. * tmpfile will delete the file, but any open descriptors
  271. * can still access the phantom inode.
  272. */
  273. if ((fd = dup2(tfd, fd)) == -1) {
  274. file_error(ms, errno, "could not dup descriptor for temp file");
  275. return -1;
  276. }
  277. (void)close(tfd);
  278. if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
  279. file_badseek(ms);
  280. return -1;
  281. }
  282. return fd;
  283. }
  284. #if HAVE_FORK
  285. #ifdef BUILTIN_DECOMPRESS
  286. #define FHCRC (1 << 1)
  287. #define FEXTRA (1 << 2)
  288. #define FNAME (1 << 3)
  289. #define FCOMMENT (1 << 4)
  290. private size_t
  291. uncompressgzipped(struct magic_set *ms, const unsigned char *old,
  292. unsigned char **newch, size_t n)
  293. {
  294. unsigned char flg = old[3];
  295. size_t data_start = 10;
  296. z_stream z;
  297. int rc;
  298. if (flg & FEXTRA) {
  299. if (data_start+1 >= n)
  300. return 0;
  301. data_start += 2 + old[data_start] + old[data_start + 1] * 256;
  302. }
  303. if (flg & FNAME) {
  304. while(data_start < n && old[data_start])
  305. data_start++;
  306. data_start++;
  307. }
  308. if(flg & FCOMMENT) {
  309. while(data_start < n && old[data_start])
  310. data_start++;
  311. data_start++;
  312. }
  313. if(flg & FHCRC)
  314. data_start += 2;
  315. if (data_start >= n)
  316. return 0;
  317. if ((*newch = CAST(unsigned char *, malloc(HOWMANY + 1))) == NULL) {
  318. return 0;
  319. }
  320. /* XXX: const castaway, via strchr */
  321. z.next_in = (Bytef *)strchr((const char *)old + data_start,
  322. old[data_start]);
  323. z.avail_in = CAST(uint32_t, (n - data_start));
  324. z.next_out = *newch;
  325. z.avail_out = HOWMANY;
  326. z.zalloc = Z_NULL;
  327. z.zfree = Z_NULL;
  328. z.opaque = Z_NULL;
  329. /* LINTED bug in header macro */
  330. rc = inflateInit2(&z, -15);
  331. if (rc != Z_OK) {
  332. file_error(ms, 0, "zlib: %s", z.msg);
  333. return 0;
  334. }
  335. rc = inflate(&z, Z_SYNC_FLUSH);
  336. if (rc != Z_OK && rc != Z_STREAM_END) {
  337. file_error(ms, 0, "zlib: %s", z.msg);
  338. return 0;
  339. }
  340. n = (size_t)z.total_out;
  341. (void)inflateEnd(&z);
  342. /* let's keep the nul-terminate tradition */
  343. (*newch)[n] = '\0';
  344. return n;
  345. }
  346. #endif
  347. private size_t
  348. uncompressbuf(struct magic_set *ms, int fd, size_t method,
  349. const unsigned char *old, unsigned char **newch, size_t n)
  350. {
  351. int fdin[2], fdout[2];
  352. ssize_t r;
  353. pid_t pid;
  354. #ifdef BUILTIN_DECOMPRESS
  355. /* FIXME: This doesn't cope with bzip2 */
  356. if (method == 2)
  357. return uncompressgzipped(ms, old, newch, n);
  358. #endif
  359. (void)fflush(stdout);
  360. (void)fflush(stderr);
  361. if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) {
  362. file_error(ms, errno, "cannot create pipe");
  363. return NODATA;
  364. }
  365. switch (pid = fork()) {
  366. case 0: /* child */
  367. (void) close(0);
  368. if (fd != -1) {
  369. (void) dup(fd);
  370. (void) lseek(0, (off_t)0, SEEK_SET);
  371. } else {
  372. (void) dup(fdin[0]);
  373. (void) close(fdin[0]);
  374. (void) close(fdin[1]);
  375. }
  376. (void) close(1);
  377. (void) dup(fdout[1]);
  378. (void) close(fdout[0]);
  379. (void) close(fdout[1]);
  380. #ifndef DEBUG
  381. if (compr[method].silent)
  382. (void)close(2);
  383. #endif
  384. (void)execvp(compr[method].argv[0],
  385. (char *const *)(intptr_t)compr[method].argv);
  386. #ifdef DEBUG
  387. (void)fprintf(stderr, "exec `%s' failed (%s)\n",
  388. compr[method].argv[0], strerror(errno));
  389. #endif
  390. exit(1);
  391. /*NOTREACHED*/
  392. case -1:
  393. file_error(ms, errno, "could not fork");
  394. return NODATA;
  395. default: /* parent */
  396. (void) close(fdout[1]);
  397. if (fd == -1) {
  398. (void) close(fdin[0]);
  399. /*
  400. * fork again, to avoid blocking because both
  401. * pipes filled
  402. */
  403. switch (fork()) {
  404. case 0: /* child */
  405. (void)close(fdout[0]);
  406. if (swrite(fdin[1], old, n) != (ssize_t)n) {
  407. #ifdef DEBUG
  408. (void)fprintf(stderr,
  409. "Write failed (%s)\n",
  410. strerror(errno));
  411. #endif
  412. exit(1);
  413. }
  414. exit(0);
  415. /*NOTREACHED*/
  416. case -1:
  417. #ifdef DEBUG
  418. (void)fprintf(stderr, "Fork failed (%s)\n",
  419. strerror(errno));
  420. #endif
  421. exit(1);
  422. /*NOTREACHED*/
  423. default: /* parent */
  424. break;
  425. }
  426. (void) close(fdin[1]);
  427. fdin[1] = -1;
  428. }
  429. if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) {
  430. #ifdef DEBUG
  431. (void)fprintf(stderr, "Malloc failed (%s)\n",
  432. strerror(errno));
  433. #endif
  434. n = 0;
  435. goto err;
  436. }
  437. if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) {
  438. #ifdef DEBUG
  439. (void)fprintf(stderr, "Read failed (%s)\n",
  440. strerror(errno));
  441. #endif
  442. free(*newch);
  443. n = 0;
  444. newch[0] = '\0';
  445. goto err;
  446. } else {
  447. n = r;
  448. }
  449. /* NUL terminate, as every buffer is handled here. */
  450. (*newch)[n] = '\0';
  451. err:
  452. if (fdin[1] != -1)
  453. (void) close(fdin[1]);
  454. (void) close(fdout[0]);
  455. #ifdef WNOHANG
  456. while (waitpid(pid, NULL, WNOHANG) != -1)
  457. continue;
  458. #else
  459. (void)wait(NULL);
  460. #endif
  461. (void) close(fdin[0]);
  462. return n;
  463. }
  464. }
  465. #endif