1 /** \ingroup payload
2 * \file lib/cpio.c
3 * Handle cpio payloads within rpm packages.
4 *
5 * \warning FIXME: We don't translate between cpio and system mode bits! These
6 * should both be the same, but really odd things are going to happen if
7 * that's not true!
8 */
9
10 #include "system.h"
11
12 #if MAJOR_IN_MKDEV
13 #include <sys/mkdev.h>
14 #elif MAJOR_IN_SYSMACROS
15 #include <sys/sysmacros.h>
16 #else
17 #include <sys/types.h> /* already included from system.h */
18 #endif
19 #include <string.h>
20 #include <fcntl.h>
21
22 #include <rpm/rpmio.h>
23 #include <rpm/rpmlog.h>
24 #include <rpm/rpmstring.h>
25
26 #include "lib/cpio.h"
27 #include "lib/rpmarchive.h"
28
29 #include "debug.h"
30
31
32 struct rpmcpio_s {
33 FD_t fd;
34 char mode;
35 off_t offset;
36 off_t fileend;
37 };
38
39 /*
40 * Size limit for individual files in "new ascii format" cpio archives.
41 * The max size of the entire archive is unlimited from cpio POV,
42 * but subject to filesystem limitations.
43 */
44 #define CPIO_FILESIZE_MAX UINT32_MAX
45
46 #define CPIO_NEWC_MAGIC "070701"
47 #define CPIO_CRC_MAGIC "070702"
48 #define CPIO_STRIPPED_MAGIC "07070X"
49 #define CPIO_TRAILER "TRAILER!!!"
50
51 /** \ingroup payload
52 * Cpio archive header information.
53 */
54 struct cpioCrcPhysicalHeader {
55 /* char magic[6]; handled separately */
56 char inode[8];
57 char mode[8];
58 char uid[8];
59 char gid[8];
60 char nlink[8];
61 char mtime[8];
62 char filesize[8];
63 char devMajor[8];
64 char devMinor[8];
65 char rdevMajor[8];
66 char rdevMinor[8];
67 char namesize[8];
68 char checksum[8]; /* ignored !! */
69 };
70
71 #define PHYS_HDR_SIZE 104 /* Don't depend on sizeof(struct) */
72
73 struct cpioStrippedPhysicalHeader {
74 /* char magic[6]; handled separately */
75 char fx[8];
76 };
77
78 #define STRIPPED_PHYS_HDR_SIZE 8 /* Don't depend on sizeof(struct) */
79
rpmcpioOpen(FD_t fd,char mode)80 rpmcpio_t rpmcpioOpen(FD_t fd, char mode)
81 {
82 if ((mode & O_ACCMODE) != O_RDONLY &&
83 (mode & O_ACCMODE) != O_WRONLY)
84 return NULL;
85
86 rpmcpio_t cpio = xcalloc(1, sizeof(*cpio));
87 cpio->fd = fdLink(fd);
88 cpio->mode = mode;
89 cpio->offset = 0;
90 return cpio;
91 }
92
rpmcpioTell(rpmcpio_t cpio)93 off_t rpmcpioTell(rpmcpio_t cpio)
94 {
95 return cpio->offset;
96 }
97
98
99 /**
100 * Convert string to unsigned integer (with buffer size check).
101 * @param str input string
102 * @retval endptr address of 1st character not processed
103 * @param base numerical conversion base
104 * @param num max no. of bytes to read
105 * @return converted integer
106 */
strntoul(const char * str,char ** endptr,int base,size_t num)107 static unsigned long strntoul(const char *str,char **endptr, int base, size_t num)
108 {
109 char buf[num+1], * end;
110 unsigned long ret;
111
112 strncpy(buf, str, num);
113 buf[num] = '\0';
114
115 ret = strtoul(buf, &end, base);
116 if (*end != '\0')
117 *endptr = ((char *)str) + (end - buf); /* XXX discards const */
118 else
119 *endptr = ((char *)str) + strlen(buf);
120
121 return ret;
122 }
123
124
rpmcpioWritePad(rpmcpio_t cpio,ssize_t modulo)125 static int rpmcpioWritePad(rpmcpio_t cpio, ssize_t modulo)
126 {
127 char buf[modulo];
128 ssize_t left, written;
129 memset(buf, 0, modulo);
130 left = (modulo - ((cpio->offset) % modulo)) % modulo;
131 if (left <= 0)
132 return 0;
133 written = Fwrite(&buf, left, 1, cpio->fd);
134 if (written != left) {
135 return RPMERR_WRITE_FAILED;
136 }
137 cpio->offset += written;
138 return 0;
139 }
140
rpmcpioReadPad(rpmcpio_t cpio)141 static int rpmcpioReadPad(rpmcpio_t cpio)
142 {
143 ssize_t modulo = 4;
144 char buf[4];
145 ssize_t left, read;
146 left = (modulo - (cpio->offset % modulo)) % modulo;
147 if (left <= 0)
148 return 0;
149 read = Fread(&buf, left, 1, cpio->fd);
150 cpio->offset += read;
151 if (read != left) {
152 return RPMERR_READ_FAILED;
153 }
154 return 0;
155 }
156
157 #define GET_NUM_FIELD(phys, log) \
158 \
159 log = strntoul(phys, &end, 16, sizeof(phys)); \
160 \
161 if ( (end - phys) != sizeof(phys) ) return RPMERR_BAD_HEADER;
162 #define SET_NUM_FIELD(phys, val, space) \
163 sprintf(space, "%8.8lx", (unsigned long) (val)); \
164 \
165 memcpy(phys, space, 8) \
166
rpmcpioTrailerWrite(rpmcpio_t cpio)167 static int rpmcpioTrailerWrite(rpmcpio_t cpio)
168 {
169 struct cpioCrcPhysicalHeader hdr;
170 int rc;
171 size_t written;
172
173 if (cpio->fileend != cpio->offset) {
174 return RPMERR_WRITE_FAILED;
175 }
176
177 rc = rpmcpioWritePad(cpio, 4);
178 if (rc)
179 return rc;
180
181 memset(&hdr, '0', PHYS_HDR_SIZE);
182 memcpy(&hdr.nlink, "00000001", 8);
183 memcpy(&hdr.namesize, "0000000b", 8);
184
185 written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
186 cpio->offset += written;
187 if (written != 6) {
188 return RPMERR_WRITE_FAILED;
189 }
190
191 written = Fwrite(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
192 cpio->offset += written;
193 if (written != PHYS_HDR_SIZE) {
194 return RPMERR_WRITE_FAILED;
195 }
196 written = Fwrite(&CPIO_TRAILER, sizeof(CPIO_TRAILER), 1, cpio->fd);
197 cpio->offset += written;
198 if (written != sizeof(CPIO_TRAILER)) {
199 return RPMERR_WRITE_FAILED;
200 }
201
202 /*
203 * XXX GNU cpio pads to 512 bytes. This may matter for
204 * tape device(s) and/or concatenated cpio archives.
205 */
206
207 rc = rpmcpioWritePad(cpio, 4);
208
209 return rc;
210 }
211
rpmcpioHeaderWrite(rpmcpio_t cpio,char * path,struct stat * st)212 int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
213 {
214 struct cpioCrcPhysicalHeader hdr_s;
215 struct cpioCrcPhysicalHeader * hdr = &hdr_s;
216 char field[64];
217 size_t len, written;
218 dev_t dev;
219 int rc = 0;
220
221 if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
222 return RPMERR_WRITE_FAILED;
223 }
224
225 if (cpio->fileend != cpio->offset) {
226 return RPMERR_WRITE_FAILED;
227 }
228
229 if (st->st_size >= CPIO_FILESIZE_MAX) {
230 return RPMERR_FILE_SIZE;
231 }
232
233 rc = rpmcpioWritePad(cpio, 4);
234 if (rc) {
235 return rc;
236 }
237
238 SET_NUM_FIELD(hdr->inode, st->st_ino, field);
239 SET_NUM_FIELD(hdr->mode, st->st_mode, field);
240 SET_NUM_FIELD(hdr->uid, st->st_uid, field);
241 SET_NUM_FIELD(hdr->gid, st->st_gid, field);
242 SET_NUM_FIELD(hdr->nlink, st->st_nlink, field);
243 SET_NUM_FIELD(hdr->mtime, st->st_mtime, field);
244 SET_NUM_FIELD(hdr->filesize, st->st_size, field);
245
246 dev = major(st->st_dev); SET_NUM_FIELD(hdr->devMajor, dev, field);
247 dev = minor(st->st_dev); SET_NUM_FIELD(hdr->devMinor, dev, field);
248 dev = major(st->st_rdev); SET_NUM_FIELD(hdr->rdevMajor, dev, field);
249 dev = minor(st->st_rdev); SET_NUM_FIELD(hdr->rdevMinor, dev, field);
250
251 len = strlen(path) + 1;
252 SET_NUM_FIELD(hdr->namesize, len, field);
253
254 memcpy(hdr->checksum, "00000000", 8);
255
256 written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
257 cpio->offset += written;
258 if (written != 6) {
259 return RPMERR_WRITE_FAILED;
260 }
261
262 written = Fwrite(hdr, PHYS_HDR_SIZE, 1, cpio->fd);
263 cpio->offset += written;
264 if (written != PHYS_HDR_SIZE) {
265 return RPMERR_WRITE_FAILED;
266 }
267
268 written = Fwrite(path, len, 1, cpio->fd);
269 cpio->offset += written;
270 if (written != len) {
271 return RPMERR_WRITE_FAILED;
272 }
273
274 rc = rpmcpioWritePad(cpio, 4);
275
276 cpio->fileend = cpio->offset + st->st_size;
277
278 return rc;
279 }
280
rpmcpioStrippedHeaderWrite(rpmcpio_t cpio,int fx,off_t fsize)281 int rpmcpioStrippedHeaderWrite(rpmcpio_t cpio, int fx, off_t fsize)
282 {
283 struct cpioStrippedPhysicalHeader hdr_s;
284 struct cpioStrippedPhysicalHeader * hdr = &hdr_s;
285 char field[64];
286 size_t written;
287 int rc = 0;
288
289 if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
290 return RPMERR_WRITE_FAILED;
291 }
292
293 if (cpio->fileend != cpio->offset) {
294 return RPMERR_WRITE_FAILED;
295 }
296
297 rc = rpmcpioWritePad(cpio, 4);
298 if (rc) {
299 return rc;
300 }
301
302 SET_NUM_FIELD(hdr->fx, fx, field);
303
304 written = Fwrite(CPIO_STRIPPED_MAGIC, 6, 1, cpio->fd);
305 cpio->offset += written;
306 if (written != 6) {
307 return RPMERR_WRITE_FAILED;
308 }
309
310 written = Fwrite(hdr, STRIPPED_PHYS_HDR_SIZE, 1, cpio->fd);
311 cpio->offset += written;
312 if (written != STRIPPED_PHYS_HDR_SIZE) {
313 return RPMERR_WRITE_FAILED;
314 }
315
316 rc = rpmcpioWritePad(cpio, 4);
317
318 cpio->fileend = cpio->offset + fsize;
319
320 return rc;
321 }
322
rpmcpioWrite(rpmcpio_t cpio,const void * buf,size_t size)323 ssize_t rpmcpioWrite(rpmcpio_t cpio, const void * buf, size_t size)
324 {
325 size_t written, left;
326
327 if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
328 return RPMERR_WRITE_FAILED;
329 }
330
331 // Do not write beyond file length
332 left = cpio->fileend - cpio->offset;
333 size = size > left ? left : size;
334 written = Fwrite(buf, size, 1, cpio->fd);
335 cpio->offset += written;
336 return written;
337 }
338
339
rpmcpioHeaderRead(rpmcpio_t cpio,char ** path,int * fx)340 int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, int * fx)
341 {
342 struct cpioCrcPhysicalHeader hdr;
343 int nameSize;
344 char * end;
345 int rc = 0;
346 ssize_t read;
347 char magic[6];
348 rpm_loff_t fsize;
349
350 if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
351 return RPMERR_READ_FAILED;
352 }
353
354 /* Move to next file */
355 if (cpio->fileend != cpio->offset) {
356 /* XXX try using Fseek() - which is currently broken */
357 char buf[8*BUFSIZ];
358 while (cpio->fileend != cpio->offset) {
359 read = cpio->fileend - cpio->offset > 8*BUFSIZ ? 8*BUFSIZ : cpio->fileend - cpio->offset;
360 if (rpmcpioRead(cpio, &buf, read) != read) {
361 return RPMERR_READ_FAILED;
362 }
363 }
364 }
365
366 rc = rpmcpioReadPad(cpio);
367 if (rc) return rc;
368
369 read = Fread(&magic, 6, 1, cpio->fd);
370 cpio->offset += read;
371 if (read != 6)
372 return RPMERR_BAD_MAGIC;
373
374 /* read stripped header */
375 if (!strncmp(CPIO_STRIPPED_MAGIC, magic,
376 sizeof(CPIO_STRIPPED_MAGIC)-1)) {
377 struct cpioStrippedPhysicalHeader shdr;
378 read = Fread(&shdr, STRIPPED_PHYS_HDR_SIZE, 1, cpio->fd);
379 cpio->offset += read;
380 if (read != STRIPPED_PHYS_HDR_SIZE)
381 return RPMERR_BAD_HEADER;
382
383 GET_NUM_FIELD(shdr.fx, *fx);
384 rc = rpmcpioReadPad(cpio);
385
386 if (!rc && *fx == -1)
387 rc = RPMERR_ITER_END;
388 return rc;
389 }
390
391 if (strncmp(CPIO_CRC_MAGIC, magic, sizeof(CPIO_CRC_MAGIC)-1) &&
392 strncmp(CPIO_NEWC_MAGIC, magic, sizeof(CPIO_NEWC_MAGIC)-1)) {
393 return RPMERR_BAD_MAGIC;
394 }
395
396 read = Fread(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
397 cpio->offset += read;
398 if (read != PHYS_HDR_SIZE)
399 return RPMERR_BAD_HEADER;
400
401 GET_NUM_FIELD(hdr.filesize, fsize);
402 GET_NUM_FIELD(hdr.namesize, nameSize);
403 if (nameSize <= 0 || nameSize > 4096) {
404 return RPMERR_BAD_HEADER;
405 }
406
407 char name[nameSize + 1];
408 read = Fread(name, nameSize, 1, cpio->fd);
409 name[nameSize] = '\0';
410 cpio->offset += read;
411 if (read != nameSize ) {
412 return RPMERR_BAD_HEADER;
413 }
414
415 rc = rpmcpioReadPad(cpio);
416 cpio->fileend = cpio->offset + fsize;
417
418 if (!rc && rstreq(name, CPIO_TRAILER))
419 rc = RPMERR_ITER_END;
420
421 if (!rc && path)
422 *path = xstrdup(name);
423
424 return rc;
425 }
426
rpmcpioSetExpectedFileSize(rpmcpio_t cpio,off_t fsize)427 void rpmcpioSetExpectedFileSize(rpmcpio_t cpio, off_t fsize)
428 {
429 cpio->fileend = cpio->offset + fsize;
430 }
431
rpmcpioRead(rpmcpio_t cpio,void * buf,size_t size)432 ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size)
433 {
434 size_t read, left;
435
436 if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
437 return RPMERR_READ_FAILED;
438 }
439
440 left = cpio->fileend - cpio->offset;
441 size = size > left ? left : size;
442 read = Fread(buf, size, 1, cpio->fd);
443 cpio->offset += read;
444 return read;
445 }
446
rpmcpioClose(rpmcpio_t cpio)447 int rpmcpioClose(rpmcpio_t cpio)
448 {
449 int rc = 0;
450 if ((cpio->mode & O_ACCMODE) == O_WRONLY) {
451 rc = rpmcpioTrailerWrite(cpio);
452 }
453 fdFree(cpio->fd);
454 cpio->fd = NULL;
455 return rc;
456 }
457
rpmcpioFree(rpmcpio_t cpio)458 rpmcpio_t rpmcpioFree(rpmcpio_t cpio)
459 {
460 if (cpio) {
461 if (cpio->fd)
462 (void) rpmcpioClose(cpio);
463 free(cpio);
464 }
465 return NULL;
466 }
467