blob: 743ffee0207e97f0639fc8299cc89f13d1791634 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath5699b852003-11-15 23:19:05 +00002/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02003 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath5699b852003-11-15 23:19:05 +00004 */
5
Glenn L McGrath5699b852003-11-15 23:19:05 +00006#include "libbb.h"
Denys Vlasenkod184a722011-09-22 12:45:14 +02007#include "bb_archive.h"
Bernhard Reutner-Fischercfb53df2006-04-02 21:50:01 +00008
Denys Vlasenko59655072012-03-06 16:23:50 +01009#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \
10 || ENABLE_FEATURE_SEAMLESS_BZ2 \
11 || ENABLE_FEATURE_SEAMLESS_GZ \
12 /* || ENABLE_FEATURE_SEAMLESS_Z */ \
13)
14
15#if ZIPPED
16# include "bb_archive.h"
17#endif
18
Glenn L McGrath5699b852003-11-15 23:19:05 +000019/* transformer(), more than meets the eye */
Denis Vlasenko211f7f82007-09-05 11:48:32 +000020/*
Denis Vlasenko059c9172007-11-12 02:13:12 +000021 * On MMU machine, the transform_prog is removed by macro magic
Denys Vlasenko833d4e72010-11-03 02:38:31 +010022 * in include/archive.h. On NOMMU, transformer is removed.
Denis Vlasenko211f7f82007-09-05 11:48:32 +000023 */
Denis Vlasenkob6052722008-07-10 17:43:01 +000024void FAST_FUNC open_transformer(int fd,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000025 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd),
Denis Vlasenko059c9172007-11-12 02:13:12 +000026 const char *transform_prog)
Glenn L McGrath5699b852003-11-15 23:19:05 +000027{
Denis Vlasenko37188322008-02-16 13:20:56 +000028 struct fd_pair fd_pipe;
Glenn L McGrath5699b852003-11-15 23:19:05 +000029 int pid;
30
Denis Vlasenko37188322008-02-16 13:20:56 +000031 xpiped_pair(fd_pipe);
Pascal Bellard926031b2010-07-04 15:32:38 +020032 pid = BB_MMU ? xfork() : xvfork();
Glenn L McGrath5699b852003-11-15 23:19:05 +000033 if (pid == 0) {
Pascal Bellard926031b2010-07-04 15:32:38 +020034 /* Child */
Denis Vlasenkob6052722008-07-10 17:43:01 +000035 close(fd_pipe.rd); /* we don't want to read from the parent */
Denis Vlasenkoea620772006-10-14 02:23:43 +000036 // FIXME: error check?
Denis Vlasenko211f7f82007-09-05 11:48:32 +000037#if BB_MMU
Denis Vlasenkob6052722008-07-10 17:43:01 +000038 transformer(fd, fd_pipe.wr);
Denis Vlasenko7e0fbf92007-09-04 19:33:22 +000039 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkob6052722008-07-10 17:43:01 +000040 close(fd_pipe.wr); /* send EOF */
41 close(fd);
Denis Vlasenko7e0fbf92007-09-04 19:33:22 +000042 }
Denis Vlasenko2649f212008-06-26 03:26:57 +000043 /* must be _exit! bug was actually seen here */
44 _exit(EXIT_SUCCESS);
Denis Vlasenko211f7f82007-09-05 11:48:32 +000045#else
Denis Vlasenko059c9172007-11-12 02:13:12 +000046 {
47 char *argv[4];
Denis Vlasenkob6052722008-07-10 17:43:01 +000048 xmove_fd(fd, 0);
Denis Vlasenko37188322008-02-16 13:20:56 +000049 xmove_fd(fd_pipe.wr, 1);
Denis Vlasenko059c9172007-11-12 02:13:12 +000050 argv[0] = (char*)transform_prog;
51 argv[1] = (char*)"-cf";
52 argv[2] = (char*)"-";
53 argv[3] = NULL;
54 BB_EXECVP(transform_prog, argv);
Denis Vlasenkof9d4fc32009-04-21 20:40:51 +000055 bb_perror_msg_and_die("can't execute '%s'", transform_prog);
Denis Vlasenko059c9172007-11-12 02:13:12 +000056 }
Denis Vlasenko211f7f82007-09-05 11:48:32 +000057#endif
Denis Vlasenkoea620772006-10-14 02:23:43 +000058 /* notreached */
Glenn L McGrath5699b852003-11-15 23:19:05 +000059 }
Glenn L McGrath20872be2003-11-18 21:31:19 +000060
Glenn L McGrath5699b852003-11-15 23:19:05 +000061 /* parent process */
Denis Vlasenkob6052722008-07-10 17:43:01 +000062 close(fd_pipe.wr); /* don't want to write to the child */
63 xmove_fd(fd_pipe.rd, fd);
Glenn L McGrath5699b852003-11-15 23:19:05 +000064}
Denys Vlasenko59655072012-03-06 16:23:50 +010065
66
67/* Used by e.g. rpm which gives us a fd without filename,
68 * thus we can't guess the format from filename's extension.
69 */
70#if ZIPPED
71void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
72{
73 const int fail_if_not_detected = 1;
74 union {
75 uint8_t b[4];
76 uint16_t b16[2];
77 uint32_t b32[1];
78 } magic;
79 int offset = -2;
80# if BB_MMU
81 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
82 enum { xformer_prog = 0 };
83# else
84 enum { xformer = 0 };
85 const char *xformer_prog;
86# endif
87
88 /* .gz and .bz2 both have 2-byte signature, and their
89 * unpack_XXX_stream wants this header skipped. */
90 xread(fd, magic.b16, sizeof(magic.b16[0]));
91 if (ENABLE_FEATURE_SEAMLESS_GZ
92 && magic.b16[0] == GZIP_MAGIC
93 ) {
94# if BB_MMU
95 xformer = unpack_gz_stream;
96# else
97 xformer_prog = "gunzip";
98# endif
99 goto found_magic;
100 }
101 if (ENABLE_FEATURE_SEAMLESS_BZ2
102 && magic.b16[0] == BZIP2_MAGIC
103 ) {
104# if BB_MMU
105 xformer = unpack_bz2_stream;
106# else
107 xformer_prog = "bunzip2";
108# endif
109 goto found_magic;
110 }
111 if (ENABLE_FEATURE_SEAMLESS_XZ
112 && magic.b16[0] == XZ_MAGIC1
113 ) {
114 offset = -6;
115 xread(fd, magic.b32, sizeof(magic.b32[0]));
116 if (magic.b32[0] == XZ_MAGIC2) {
117# if BB_MMU
118 xformer = unpack_xz_stream;
119 /* unpack_xz_stream wants fd at position 6, no need to seek */
120 //xlseek(fd, offset, SEEK_CUR);
121# else
122 xformer_prog = "unxz";
123# endif
124 goto found_magic;
125 }
126 }
127
128 /* No known magic seen */
129 if (fail_if_not_detected)
130 bb_error_msg_and_die("no gzip"
131 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
132 IF_FEATURE_SEAMLESS_XZ("/xz")
133 " magic");
134 xlseek(fd, offset, SEEK_CUR);
135 return;
136
137 found_magic:
138# if !BB_MMU
139 /* NOMMU version of open_transformer execs
140 * an external unzipper that wants
141 * file position at the start of the file */
142 xlseek(fd, offset, SEEK_CUR);
143# endif
144 open_transformer(fd, xformer, xformer_prog);
145}
146#endif /* ZIPPED */
147
148int FAST_FUNC open_zipped(const char *fname)
149{
150#if !ZIPPED
151 return open(fname, O_RDONLY);
152#else
153 char *sfx;
154 int fd;
155
156 fd = open(fname, O_RDONLY);
157 if (fd < 0)
158 return fd;
159
160 sfx = strrchr(fname, '.');
161 if (sfx) {
162 sfx++;
163 if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0)
164 /* .lzma has no header/signature, just trust it */
165 open_transformer(fd, unpack_lzma_stream, "unlzma");
166 else
167 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0)
168 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0)
169 || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0)
170 ) {
171 setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/);
172 }
173 }
174
175 return fd;
176#endif
177}
178
179void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
180{
181 int fd;
182 char *image;
183
184 fd = open_zipped(fname);
185 if (fd < 0)
186 return NULL;
187
188 image = xmalloc_read(fd, maxsz_p);
189 if (!image)
190 bb_perror_msg("read error from '%s'", fname);
191 close(fd);
192
193 return image;
194}