projects/aports·blob v2.4 · refs

277 lines · 5.5 KiB

1/* abuild-tar.c - A TAR mangling utility for .APK packages
2 *
3 * Copyright (C) 2009 Timo Teräs <[email protected]>
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation. See http://www.gnu.org/ for details.
9 */
10
11#include <stdio.h>
12#include <fcntl.h>
13#include <errno.h>
14#include <stdint.h>
15#include <getopt.h>
16#include <unistd.h>
17#include <string.h>
18
19#include <openssl/evp.h>
20
21#ifndef VERSION
22#define VERSION ""
23#endif
24
25struct tar_header {
26 /* ustar header, Posix 1003.1 */
27 char name[100]; /* 0-99 */
28 char mode[8]; /* 100-107 */
29 char uid[8]; /* 108-115 */
30 char gid[8]; /* 116-123 */
31 char size[12]; /* 124-135 */
32 char mtime[12]; /* 136-147 */
33 char chksum[8]; /* 148-155 */
34 char typeflag; /* 156-156 */
35 char linkname[100]; /* 157-256 */
36 char magic[8]; /* 257-264 */
37 char uname[32]; /* 265-296 */
38 char gname[32]; /* 297-328 */
39 char devmajor[8]; /* 329-336 */
40 char devminor[8]; /* 337-344 */
41 char prefix[155]; /* 345-499 */
42 char padding[12]; /* 500-512 */
43};
44
45#define GET_OCTAL(s) get_octal(s, sizeof(s))
46#define PUT_OCTAL(s,v) put_octal(s, sizeof(s), v)
47
48static inline int dx(int c)
49{
50 if (c >= '0' && c <= '9')
51 return c - '0';
52 if (c >= 'a' && c <= 'f')
53 return c - 'a' + 0xa;
54 if (c >= 'A' && c <= 'F')
55 return c - 'A' + 0xa;
56 return -1;
57}
58
59static int get_octal(char *s, size_t l)
60{
61 unsigned int val;
62 int ch;
63
64 val = 0;
65 while (l && s[0] != 0) {
66 ch = dx(s[0]);
67 if (ch < 0 || ch >= 8)
68 break;
69 val *= 8;
70 val += ch;
71
72 s++;
73 l--;
74 }
75
76 return val;
77}
78
79static void put_octal(char *s, size_t l, size_t value)
80{
81 char *ptr = &s[l - 1];
82
83 *(ptr--) = '\0';
84 while (value != 0 && ptr >= s) {
85 *(ptr--) = '0' + (value % 8);
86 value /= 8;
87 }
88 while (ptr >= s)
89 *(ptr--) = '0';
90}
91
92static int usage(void)
93{
94 fprintf(stderr,
95"abuild-tar " VERSION "\n"
96"\n"
97"usage: abuild-tar [--hash[=<algorithm>]] [--cut]\n"
98"\n"
99"options:\n"
100" --hash[=sha1|md5] Read tar archive from stdin, precalculate hash for \n"
101" regular entries and output tar archive on stdout\n"
102" --cut Remove the end of file tar record\n"
103"\n");
104}
105
106static ssize_t full_read(int fd, void *buf, size_t count)
107{
108 ssize_t total, n;
109
110 total = 0;
111 do {
112 n = read(fd, buf, count);
113 if (n < 0 && errno == EINTR)
114 continue;
115 if (n <= 0)
116 break;
117 buf += n;
118 total += n;
119 count -= n;
120 } while (1);
121
122 if (total == 0 && n < 0)
123 return -1;
124
125 return total;
126}
127
128static ssize_t full_write(int fd, const void *buf, size_t count)
129{
130 ssize_t total, n;
131
132 total = 0;
133 do {
134 n = write(fd, buf, count);
135 if (n < 0 && errno == EINTR)
136 continue;
137 if (n <= 0)
138 break;
139 buf += n;
140 total += n;
141 count -= n;
142 } while (1);
143
144 if (total == 0 && n < 0)
145 return -1;
146
147 return total;
148}
149
150static ssize_t full_splice(int from_fd, int to_fd, size_t count)
151{
152 ssize_t total, n;
153
154 total = 0;
155 do {
156 n = splice(from_fd, NULL, to_fd, NULL, count, 0);
157 if (n < 0 && errno == EINTR)
158 continue;
159 if (n <= 0)
160 break;
161 count -= n;
162 total += n;
163 } while (1);
164
165 if (total == 0 && n < 0)
166 return -1;
167
168 return total;
169}
170
171static int do_it(const EVP_MD *md, int cut)
172{
173 struct tar_header hdr;
174 size_t size, aligned_size;
175 void *ptr;
176 int dohash = 0, r;
177 struct {
178 char id[4];
179 uint16_t nid;
180 uint16_t size;
181 } mdinfo;
182
183 if (md != NULL) {
184 memcpy(mdinfo.id, "APK2", 4);
185 mdinfo.nid = EVP_MD_nid(md);
186 mdinfo.size = EVP_MD_size(md);
187 }
188
189 do {
190 if (full_read(STDIN_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
191 return 0;
192
193 if (cut && hdr.name[0] == 0)
194 return 0;
195
196 size = GET_OCTAL(hdr.size);
197 aligned_size = (size + 511) & ~511;
198
199 if (md != NULL)
200 dohash = (hdr.typeflag == '0' || hdr.typeflag == '7');
201 if (dohash) {
202 const unsigned char *src;
203 int chksum, i;
204
205 ptr = malloc(aligned_size);
206 if (full_read(STDIN_FILENO, ptr, aligned_size) != aligned_size)
207 return 1;
208
209 memcpy(&hdr.linkname[3], &mdinfo, sizeof(mdinfo));
210 EVP_Digest(ptr, size, &hdr.linkname[3+sizeof(mdinfo)],
211 NULL, md, NULL);
212
213 /* Recalculate checksum */
214 memset(hdr.chksum, ' ', sizeof(hdr.chksum));
215 src = (const unsigned char *) &hdr;
216 for (i = chksum = 0; i < sizeof(hdr); i++)
217 chksum += src[i];
218 put_octal(hdr.chksum, sizeof(hdr.chksum)-1, chksum);
219 }
220
221 if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
222 return 2;
223
224 if (dohash) {
225 if (full_write(STDOUT_FILENO, ptr, aligned_size) != aligned_size)
226 return 2;
227 free(ptr);
228 } else if (aligned_size != 0) {
229 r = full_splice(STDIN_FILENO, STDOUT_FILENO, aligned_size);
230 if (r == -1) {
231 while (aligned_size > 0) {
232 if (full_read(STDIN_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
233 return 1;
234 if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
235 return 2;
236 aligned_size -= sizeof(hdr);
237 }
238 } else if (r != aligned_size)
239 return 2;
240 }
241 } while (1);
242}
243
244int main(int argc, char **argv)
245{
246 static int cut = 0;
247 static const struct option options[] = {
248 { "hash", optional_argument },
249 { "cut", no_argument, &cut, 1 },
250 { NULL }
251 };
252 const EVP_MD *md = NULL;
253 char *digest = NULL;
254 int ndx;
255
256 OpenSSL_add_all_algorithms();
257 ENGINE_load_builtin_engines();
258 ENGINE_register_all_complete();
259
260 while (getopt_long(argc, argv, "", options, &ndx) != -1) {
261 if (ndx == 0)
262 digest = optarg ? optarg : "sha1";
263 }
264
265 if (digest == NULL && cut == 0)
266 return usage();
267 if (isatty(STDIN_FILENO))
268 return usage();
269
270 if (digest != NULL) {
271 md = EVP_get_digestbyname(digest);
272 if (md == NULL)
273 return usage();
274 }
275
276 return do_it(md, cut);
277}