070-use_external_gzip.patch 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. --- a/libbb/unarchive.c
  2. +++ b/libbb/unarchive.c
  3. @@ -28,6 +28,7 @@
  4. #include <libgen.h>
  5. #include "libbb.h"
  6. +#include "gzip.h"
  7. #define CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY 1
  8. #define CONFIG_FEATURE_TAR_GNU_EXTENSIONS
  9. @@ -39,38 +40,15 @@ static char *linkname = NULL;
  10. off_t archive_offset;
  11. -#define SEEK_BUF 4096
  12. static ssize_t
  13. -seek_by_read(FILE* fd, size_t len)
  14. -{
  15. - ssize_t cc, total = 0;
  16. - char buf[SEEK_BUF];
  17. -
  18. - while (len) {
  19. - cc = fread(buf, sizeof(buf[0]),
  20. - len > SEEK_BUF ? SEEK_BUF : len,
  21. - fd);
  22. -
  23. - total += cc;
  24. - len -= cc;
  25. -
  26. - if(feof(fd) || ferror(fd))
  27. - break;
  28. - }
  29. - return total;
  30. -}
  31. -
  32. -static void
  33. -seek_sub_file(FILE *fd, const int count)
  34. +seek_forward(struct gzip_handle *zh, ssize_t len)
  35. {
  36. - archive_offset += count;
  37. + ssize_t slen = gzip_seek(zh, len);
  38. - /* Do not use fseek() on a pipe. It may fail with ESPIPE, leaving the
  39. - * stream at an undefined location.
  40. - */
  41. - seek_by_read(fd, count);
  42. + if (slen == len)
  43. + archive_offset += len;
  44. - return;
  45. + return slen;
  46. }
  47. @@ -87,7 +65,7 @@ seek_sub_file(FILE *fd, const int count)
  48. * trailing '/' or else the last dir will be assumed to be the file prefix
  49. */
  50. static char *
  51. -extract_archive(FILE *src_stream, FILE *out_stream,
  52. +extract_archive(struct gzip_handle *src_stream, FILE *out_stream,
  53. const file_header_t *file_entry, const int function,
  54. const char *prefix,
  55. int *err)
  56. @@ -129,14 +107,14 @@ extract_archive(FILE *src_stream, FILE *
  57. if (function & extract_to_stream) {
  58. if (S_ISREG(file_entry->mode)) {
  59. - *err = copy_file_chunk(src_stream, out_stream, file_entry->size);
  60. + *err = gzip_copy(src_stream, out_stream, file_entry->size);
  61. archive_offset += file_entry->size;
  62. }
  63. }
  64. else if (function & extract_one_to_buffer) {
  65. if (S_ISREG(file_entry->mode)) {
  66. buffer = (char *) xmalloc(file_entry->size + 1);
  67. - fread(buffer, 1, file_entry->size, src_stream);
  68. + gzip_read(src_stream, buffer, file_entry->size);
  69. buffer[file_entry->size] = '\0';
  70. archive_offset += file_entry->size;
  71. goto cleanup;
  72. @@ -156,7 +134,7 @@ extract_archive(FILE *src_stream, FILE *
  73. *err = -1;
  74. error_msg("%s not created: newer or same age file exists", file_entry->name);
  75. }
  76. - seek_sub_file(src_stream, file_entry->size);
  77. + seek_forward(src_stream, file_entry->size);
  78. goto cleanup;
  79. }
  80. }
  81. @@ -185,11 +163,11 @@ extract_archive(FILE *src_stream, FILE *
  82. } else {
  83. if ((dst_stream = wfopen(full_name, "w")) == NULL) {
  84. *err = -1;
  85. - seek_sub_file(src_stream, file_entry->size);
  86. + seek_forward(src_stream, file_entry->size);
  87. goto cleanup;
  88. }
  89. archive_offset += file_entry->size;
  90. - *err = copy_file_chunk(src_stream, dst_stream, file_entry->size);
  91. + *err = gzip_copy(src_stream, dst_stream, file_entry->size);
  92. fclose(dst_stream);
  93. }
  94. break;
  95. @@ -250,7 +228,7 @@ extract_archive(FILE *src_stream, FILE *
  96. /* If we arent extracting data we have to skip it,
  97. * if data size is 0 then then just do it anyway
  98. * (saves testing for it) */
  99. - seek_sub_file(src_stream, file_entry->size);
  100. + seek_forward(src_stream, file_entry->size);
  101. }
  102. /* extract_list and extract_verbose_list can be used in conjunction
  103. @@ -274,8 +252,8 @@ cleanup:
  104. }
  105. static char *
  106. -unarchive(FILE *src_stream, FILE *out_stream,
  107. - file_header_t *(*get_headers)(FILE *),
  108. +unarchive(struct gzip_handle *src_stream, FILE *out_stream,
  109. + file_header_t *(*get_headers)(struct gzip_handle *),
  110. void (*free_headers)(file_header_t *),
  111. const int extract_function,
  112. const char *prefix,
  113. @@ -329,7 +307,7 @@ unarchive(FILE *src_stream, FILE *out_st
  114. }
  115. } else {
  116. /* seek past the data entry */
  117. - seek_sub_file(src_stream, file_entry->size);
  118. + seek_forward(src_stream, file_entry->size);
  119. }
  120. free_headers(file_entry);
  121. }
  122. @@ -337,108 +315,9 @@ unarchive(FILE *src_stream, FILE *out_st
  123. return buffer;
  124. }
  125. -static file_header_t *
  126. -get_header_ar(FILE *src_stream)
  127. -{
  128. - file_header_t *typed;
  129. - union {
  130. - char raw[60];
  131. - struct {
  132. - char name[16];
  133. - char date[12];
  134. - char uid[6];
  135. - char gid[6];
  136. - char mode[8];
  137. - char size[10];
  138. - char magic[2];
  139. - } formated;
  140. - } ar;
  141. - static char *ar_long_names;
  142. -
  143. - if (fread(ar.raw, 1, 60, src_stream) != 60) {
  144. - return(NULL);
  145. - }
  146. - archive_offset += 60;
  147. - /* align the headers based on the header magic */
  148. - if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
  149. - /* some version of ar, have an extra '\n' after each data entry,
  150. - * this puts the next header out by 1 */
  151. - if (ar.formated.magic[1] != '`') {
  152. - error_msg("Invalid magic");
  153. - return(NULL);
  154. - }
  155. - /* read the next char out of what would be the data section,
  156. - * if its a '\n' then it is a valid header offset by 1*/
  157. - archive_offset++;
  158. - if (fgetc(src_stream) != '\n') {
  159. - error_msg("Invalid magic");
  160. - return(NULL);
  161. - }
  162. - /* fix up the header, we started reading 1 byte too early */
  163. - /* raw_header[60] wont be '\n' as it should, but it doesnt matter */
  164. - memmove(ar.raw, &ar.raw[1], 59);
  165. - }
  166. -
  167. - typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
  168. -
  169. - typed->size = (size_t) atoi(ar.formated.size);
  170. - /* long filenames have '/' as the first character */
  171. - if (ar.formated.name[0] == '/') {
  172. - if (ar.formated.name[1] == '/') {
  173. - /* If the second char is a '/' then this entries data section
  174. - * stores long filename for multiple entries, they are stored
  175. - * in static variable long_names for use in future entries */
  176. - ar_long_names = (char *) xrealloc(ar_long_names, typed->size);
  177. - fread(ar_long_names, 1, typed->size, src_stream);
  178. - archive_offset += typed->size;
  179. - /* This ar entries data section only contained filenames for other records
  180. - * they are stored in the static ar_long_names for future reference */
  181. - return (get_header_ar(src_stream)); /* Return next header */
  182. - } else if (ar.formated.name[1] == ' ') {
  183. - /* This is the index of symbols in the file for compilers */
  184. - seek_sub_file(src_stream, typed->size);
  185. - return (get_header_ar(src_stream)); /* Return next header */
  186. - } else {
  187. - /* The number after the '/' indicates the offset in the ar data section
  188. - (saved in variable long_name) that conatains the real filename */
  189. - if (!ar_long_names) {
  190. - error_msg("Cannot resolve long file name");
  191. - return (NULL);
  192. - }
  193. - typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1]));
  194. - }
  195. - } else {
  196. - /* short filenames */
  197. - typed->name = xcalloc(1, 16);
  198. - strncpy(typed->name, ar.formated.name, 16);
  199. - }
  200. - typed->name[strcspn(typed->name, " /")]='\0';
  201. -
  202. - /* convert the rest of the now valid char header to its typed struct */
  203. - parse_mode(ar.formated.mode, &typed->mode);
  204. - typed->mtime = atoi(ar.formated.date);
  205. - typed->uid = atoi(ar.formated.uid);
  206. - typed->gid = atoi(ar.formated.gid);
  207. -
  208. - return(typed);
  209. -}
  210. -
  211. -static void
  212. -free_header_ar(file_header_t *ar_entry)
  213. -{
  214. - if (ar_entry == NULL)
  215. - return;
  216. -
  217. - free(ar_entry->name);
  218. - if (ar_entry->link_name)
  219. - free(ar_entry->link_name);
  220. -
  221. - free(ar_entry);
  222. -}
  223. -
  224. static file_header_t *
  225. -get_header_tar(FILE *tar_stream)
  226. +get_header_tar(struct gzip_handle *tar_stream)
  227. {
  228. union {
  229. unsigned char raw[512];
  230. @@ -467,10 +346,10 @@ get_header_tar(FILE *tar_stream)
  231. long sum = 0;
  232. if (archive_offset % 512 != 0) {
  233. - seek_sub_file(tar_stream, 512 - (archive_offset % 512));
  234. + seek_forward(tar_stream, 512 - (archive_offset % 512));
  235. }
  236. - if (fread(tar.raw, 1, 512, tar_stream) != 512) {
  237. + if (gzip_read(tar_stream, tar.raw, 512) != 512) {
  238. /* Unfortunately its common for tar files to have all sorts of
  239. * trailing garbage, fail silently */
  240. // error_msg("Couldnt read header");
  241. @@ -557,7 +436,7 @@ get_header_tar(FILE *tar_stream)
  242. # ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
  243. case 'L': {
  244. longname = xmalloc(tar_entry->size + 1);
  245. - if(fread(longname, tar_entry->size, 1, tar_stream) != 1)
  246. + if(gzip_read(tar_stream, longname, tar_entry->size) != tar_entry->size)
  247. return NULL;
  248. longname[tar_entry->size] = '\0';
  249. archive_offset += tar_entry->size;
  250. @@ -566,7 +445,7 @@ get_header_tar(FILE *tar_stream)
  251. }
  252. case 'K': {
  253. linkname = xmalloc(tar_entry->size + 1);
  254. - if(fread(linkname, tar_entry->size, 1, tar_stream) != 1)
  255. + if(gzip_read(tar_stream, linkname, tar_entry->size) != tar_entry->size)
  256. return NULL;
  257. linkname[tar_entry->size] = '\0';
  258. archive_offset += tar_entry->size;
  259. @@ -642,6 +521,9 @@ deb_extract(const char *package_filename
  260. char *ared_file = NULL;
  261. char ar_magic[8];
  262. int gz_err;
  263. + struct gzip_handle tar_outer, tar_inner;
  264. + file_header_t *tar_header;
  265. + ssize_t len;
  266. *err = 0;
  267. @@ -672,111 +554,44 @@ deb_extract(const char *package_filename
  268. /* set the buffer size */
  269. setvbuf(deb_stream, NULL, _IOFBF, 0x8000);
  270. - /* check ar magic */
  271. - fread(ar_magic, 1, 8, deb_stream);
  272. -
  273. - if (strncmp(ar_magic,"!<arch>",7) == 0) {
  274. - archive_offset = 8;
  275. + memset(&tar_outer, 0, sizeof(tar_outer));
  276. + tar_outer.file = deb_stream;
  277. + gzip_exec(&tar_outer, NULL);
  278. - while ((ar_header = get_header_ar(deb_stream)) != NULL) {
  279. - if (strcmp(ared_file, ar_header->name) == 0) {
  280. - int gunzip_pid = 0;
  281. - FILE *uncompressed_stream;
  282. - /* open a stream of decompressed data */
  283. - uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
  284. - if (uncompressed_stream == NULL) {
  285. - *err = -1;
  286. - goto cleanup;
  287. - }
  288. + /* walk through outer tar file to find ared_file */
  289. + while ((tar_header = get_header_tar(&tar_outer)) != NULL) {
  290. + int name_offset = 0;
  291. + if (strncmp(tar_header->name, "./", 2) == 0)
  292. + name_offset = 2;
  293. - archive_offset = 0;
  294. - output_buffer = unarchive(uncompressed_stream,
  295. - out_stream, get_header_tar,
  296. - free_header_tar,
  297. - extract_function, prefix,
  298. - file_list, err);
  299. - fclose(uncompressed_stream);
  300. - gz_err = gz_close(gunzip_pid);
  301. - if (gz_err)
  302. - *err = -1;
  303. - free_header_ar(ar_header);
  304. - break;
  305. - }
  306. - if (fseek(deb_stream, ar_header->size, SEEK_CUR) == -1) {
  307. - opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
  308. - *err = -1;
  309. - free_header_ar(ar_header);
  310. - goto cleanup;
  311. - }
  312. - free_header_ar(ar_header);
  313. - }
  314. - goto cleanup;
  315. - } else if (strncmp(ar_magic, "\037\213", 2) == 0) {
  316. - /* it's a gz file, let's assume it's an opkg */
  317. - int unzipped_opkg_pid;
  318. - FILE *unzipped_opkg_stream;
  319. - file_header_t *tar_header;
  320. - archive_offset = 0;
  321. - if (fseek(deb_stream, 0, SEEK_SET) == -1) {
  322. - opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
  323. - *err = -1;
  324. - goto cleanup;
  325. - }
  326. - unzipped_opkg_stream = gz_open(deb_stream, &unzipped_opkg_pid);
  327. - if (unzipped_opkg_stream == NULL) {
  328. - *err = -1;
  329. - goto cleanup;
  330. - }
  331. + if (strcmp(ared_file, tar_header->name+name_offset) == 0) {
  332. + memset(&tar_inner, 0, sizeof(tar_inner));
  333. + tar_inner.gzip = &tar_outer;
  334. + gzip_exec(&tar_inner, NULL);
  335. - /* walk through outer tar file to find ared_file */
  336. - while ((tar_header = get_header_tar(unzipped_opkg_stream)) != NULL) {
  337. - int name_offset = 0;
  338. - if (strncmp(tar_header->name, "./", 2) == 0)
  339. - name_offset = 2;
  340. - if (strcmp(ared_file, tar_header->name+name_offset) == 0) {
  341. - int gunzip_pid = 0;
  342. - FILE *uncompressed_stream;
  343. - /* open a stream of decompressed data */
  344. - uncompressed_stream = gz_open(unzipped_opkg_stream, &gunzip_pid);
  345. - if (uncompressed_stream == NULL) {
  346. - *err = -1;
  347. - goto cleanup;
  348. - }
  349. - archive_offset = 0;
  350. + archive_offset = 0;
  351. - output_buffer = unarchive(uncompressed_stream,
  352. - out_stream,
  353. - get_header_tar,
  354. - free_header_tar,
  355. - extract_function,
  356. - prefix,
  357. - file_list,
  358. - err);
  359. + output_buffer = unarchive(&tar_inner,
  360. + out_stream,
  361. + get_header_tar,
  362. + free_header_tar,
  363. + extract_function,
  364. + prefix,
  365. + file_list,
  366. + err);
  367. - free_header_tar(tar_header);
  368. - fclose(uncompressed_stream);
  369. - gz_err = gz_close(gunzip_pid);
  370. - if (gz_err)
  371. - *err = -1;
  372. - break;
  373. - }
  374. - seek_sub_file(unzipped_opkg_stream, tar_header->size);
  375. free_header_tar(tar_header);
  376. + gzip_close(&tar_inner);
  377. + break;
  378. }
  379. - fclose(unzipped_opkg_stream);
  380. - gz_err = gz_close(unzipped_opkg_pid);
  381. - if (gz_err)
  382. - *err = -1;
  383. - goto cleanup;
  384. - } else {
  385. - *err = -1;
  386. - error_msg("%s: invalid magic", package_filename);
  387. + seek_forward(&tar_outer, tar_header->size);
  388. + free_header_tar(tar_header);
  389. }
  390. cleanup:
  391. - if (deb_stream)
  392. - fclose(deb_stream);
  393. + gzip_close(&tar_outer);
  394. +
  395. if (file_list)
  396. free(file_list);
  397. --- /dev/null
  398. +++ b/libbb/gzip.h
  399. @@ -0,0 +1,41 @@
  400. +/*
  401. + * Copyright (C) 2016 Jo-Philipp Wich <jo@mein.io>
  402. + *
  403. + * Zlib decrompression utility routines.
  404. + *
  405. + * This program is free software; you can redistribute it and/or modify
  406. + * it under the terms of the GNU General Public License as published by
  407. + * the Free Software Foundation; either version 2 of the License, or
  408. + * (at your option) any later version.
  409. + *
  410. + * This program is distributed in the hope that it will be useful,
  411. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  412. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  413. + * GNU Library General Public License for more details.
  414. + *
  415. + * You should have received a copy of the GNU General Public License
  416. + * along with this program; if not, write to the Free Software
  417. + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  418. + */
  419. +
  420. +#include <stdio.h>
  421. +#include <signal.h>
  422. +#include <pthread.h>
  423. +
  424. +struct gzip_handle {
  425. + FILE *file;
  426. + struct gzip_handle *gzip;
  427. +
  428. + pid_t pid;
  429. + int rfd, wfd;
  430. + struct sigaction pipe_sa;
  431. + pthread_t thread;
  432. +};
  433. +
  434. +int gzip_exec(struct gzip_handle *zh, const char *filename);
  435. +ssize_t gzip_read(struct gzip_handle *zh, char *buf, ssize_t len);
  436. +ssize_t gzip_copy(struct gzip_handle *zh, FILE *out, ssize_t len);
  437. +int gzip_close(struct gzip_handle *zh);
  438. +FILE *gzip_fdopen(struct gzip_handle *zh, const char *filename);
  439. +
  440. +#define gzip_seek(zh, len) gzip_copy(zh, NULL, len)
  441. --- a/libbb/Makefile.am
  442. +++ b/libbb/Makefile.am
  443. @@ -4,9 +4,8 @@ ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"
  444. noinst_LIBRARIES = libbb.a
  445. -libbb_a_SOURCES = gz_open.c \
  446. +libbb_a_SOURCES = \
  447. libbb.h \
  448. - unzip.c \
  449. wfopen.c \
  450. unarchive.c \
  451. copy_file.c \
  452. @@ -20,7 +19,8 @@ libbb_a_SOURCES = gz_open.c \
  453. parse_mode.c \
  454. time_string.c \
  455. all_read.c \
  456. - mode_string.c
  457. + mode_string.c \
  458. + gzip.c
  459. libbb_la_CFLAGS = $(ALL_CFLAGS)
  460. #libbb_la_LDFLAGS = -static
  461. --- /dev/null
  462. +++ b/libbb/gzip.c
  463. @@ -0,0 +1,208 @@
  464. +/*
  465. + * Copyright (C) 2016 Jo-Philipp Wich <jo@mein.io>
  466. + * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
  467. + *
  468. + * Zlib decrompression utility routines.
  469. + *
  470. + * This program is free software; you can redistribute it and/or modify
  471. + * it under the terms of the GNU General Public License as published by
  472. + * the Free Software Foundation; either version 2 of the License, or
  473. + * (at your option) any later version.
  474. + *
  475. + * This program is distributed in the hope that it will be useful,
  476. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  477. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  478. + * GNU Library General Public License for more details.
  479. + *
  480. + * You should have received a copy of the GNU General Public License
  481. + * along with this program; if not, write to the Free Software
  482. + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  483. + */
  484. +
  485. +#include <string.h>
  486. +#include <errno.h>
  487. +#include <fcntl.h>
  488. +#include <unistd.h>
  489. +#include <poll.h>
  490. +#include <stdlib.h>
  491. +#include <sys/stat.h>
  492. +#include <sys/wait.h>
  493. +
  494. +#include "gzip.h"
  495. +
  496. +static void
  497. +to_devnull(int fd)
  498. +{
  499. + int devnull = open("/dev/null", fd ? O_WRONLY : O_RDONLY);
  500. +
  501. + if (devnull >= 0)
  502. + dup2(devnull, fd);
  503. +
  504. + if (devnull > STDERR_FILENO)
  505. + close(devnull);
  506. +}
  507. +
  508. +void *
  509. +gzip_thread(void *ptr)
  510. +{
  511. + struct gzip_handle *zh = ptr;
  512. + char buf[4096];
  513. + int len, ret;
  514. +
  515. + while (1) {
  516. + if (zh->file)
  517. + len = fread(buf, 1, sizeof(buf), zh->file);
  518. + else if (zh->gzip)
  519. + len = gzip_read(zh->gzip, buf, sizeof(buf));
  520. +
  521. + if (len <= 0)
  522. + break;
  523. +
  524. + do {
  525. + ret = write(zh->wfd, buf, len);
  526. + } while (ret == -1 && errno == EINTR);
  527. + }
  528. +
  529. + close(zh->wfd);
  530. + zh->wfd = -1;
  531. +}
  532. +
  533. +int
  534. +gzip_exec(struct gzip_handle *zh, const char *filename)
  535. +{
  536. + int rpipe[2] = { -1, -1 }, wpipe[2] = { -1, -1 };
  537. + struct sigaction pipe_sa = { .sa_handler = SIG_IGN };
  538. +
  539. + zh->rfd = -1;
  540. + zh->wfd = -1;
  541. +
  542. + if (sigaction(SIGPIPE, &pipe_sa, &zh->pipe_sa) < 0)
  543. + return -1;
  544. +
  545. + if (pipe(rpipe) < 0)
  546. + return -1;
  547. +
  548. + if (!filename && pipe(wpipe) < 0) {
  549. + close(rpipe[0]);
  550. + close(rpipe[1]);
  551. + return -1;
  552. + }
  553. +
  554. + zh->pid = vfork();
  555. +
  556. + switch (zh->pid) {
  557. + case -1:
  558. + return -1;
  559. +
  560. + case 0:
  561. + to_devnull(STDERR_FILENO);
  562. +
  563. + if (filename) {
  564. + to_devnull(STDIN_FILENO);
  565. + }
  566. + else {
  567. + dup2(wpipe[0], STDIN_FILENO);
  568. + close(wpipe[0]);
  569. + close(wpipe[1]);
  570. + }
  571. +
  572. + dup2(rpipe[1], STDOUT_FILENO);
  573. + close(rpipe[0]);
  574. + close(rpipe[1]);
  575. +
  576. + execlp("gzip", "gzip", "-d", "-c", filename, NULL);
  577. + exit(-1);
  578. +
  579. + default:
  580. + zh->rfd = rpipe[0];
  581. + zh->wfd = wpipe[1];
  582. +
  583. + fcntl(zh->rfd, F_SETFD, fcntl(zh->rfd, F_GETFD) | FD_CLOEXEC);
  584. + close(rpipe[1]);
  585. +
  586. + if (zh->wfd >= 0) {
  587. + fcntl(zh->wfd, F_SETFD, fcntl(zh->wfd, F_GETFD) | FD_CLOEXEC);
  588. + close(wpipe[0]);
  589. + pthread_create(&zh->thread, NULL, gzip_thread, zh);
  590. + }
  591. + }
  592. +
  593. + return 0;
  594. +}
  595. +
  596. +ssize_t
  597. +gzip_read(struct gzip_handle *zh, char *buf, ssize_t len)
  598. +{
  599. + ssize_t ret;
  600. +
  601. + do {
  602. + ret = read(zh->rfd, buf, len);
  603. + } while (ret == -1 && errno != EINTR);
  604. +
  605. + return ret;
  606. +}
  607. +
  608. +ssize_t
  609. +gzip_copy(struct gzip_handle *zh, FILE *out, ssize_t len)
  610. +{
  611. + char buf[4096];
  612. + ssize_t rlen, total = 0;
  613. +
  614. + while (len > 0) {
  615. + rlen = gzip_read(zh, buf,
  616. + (len > sizeof(buf)) ? sizeof(buf) : len);
  617. +
  618. + if (rlen <= 0)
  619. + break;
  620. +
  621. + if (out != NULL) {
  622. + if (fwrite(buf, 1, rlen, out) != rlen)
  623. + break;
  624. + }
  625. +
  626. + len -= rlen;
  627. + total += rlen;
  628. + }
  629. +
  630. + return total;
  631. +}
  632. +
  633. +FILE *
  634. +gzip_fdopen(struct gzip_handle *zh, const char *filename)
  635. +{
  636. + memset(zh, 0, sizeof(*zh));
  637. +
  638. + if (!filename || gzip_exec(zh, filename) < 0)
  639. + return NULL;
  640. +
  641. + fcntl(zh->rfd, F_SETFL, fcntl(zh->rfd, F_GETFL) & ~O_NONBLOCK);
  642. +
  643. + return fdopen(zh->rfd, "r");
  644. +}
  645. +
  646. +int
  647. +gzip_close(struct gzip_handle *zh)
  648. +{
  649. + int code = -1;
  650. +
  651. + if (zh->rfd >= 0)
  652. + close(zh->rfd);
  653. +
  654. + if (zh->wfd >= 0)
  655. + close(zh->wfd);
  656. +
  657. + if (zh->pid > 0) {
  658. + kill(zh->pid, SIGKILL);
  659. + waitpid(zh->pid, &code, 0);
  660. + }
  661. +
  662. + if (zh->file)
  663. + fclose(zh->file);
  664. +
  665. + if (zh->thread)
  666. + pthread_join(zh->thread, NULL);
  667. +
  668. + sigaction(SIGPIPE, &zh->pipe_sa, NULL);
  669. +
  670. + return WIFEXITED(code) ? WEXITSTATUS(code) : -1;
  671. +}
  672. --- a/src/Makefile.am
  673. +++ b/src/Makefile.am
  674. @@ -3,4 +3,4 @@ bin_PROGRAMS = opkg-cl
  675. opkg_cl_SOURCES = opkg-cl.c
  676. opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.a \
  677. - $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
  678. + $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) -lpthread
  679. --- a/tests/Makefile.am
  680. +++ b/tests/Makefile.am
  681. @@ -16,7 +16,7 @@ noinst_PROGRAMS = libopkg_test
  682. #opkg_active_list_test_SOURCES = opkg_active_list_test.c
  683. #opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
  684. -libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.a $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
  685. +libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.a $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) -lpthread
  686. libopkg_test_SOURCE = libopkg_test.c
  687. libopkg_test_LDFLAGS = -static