3 * Handle cpio payloads within rpm packages.
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
13 #include <sys/mkdev.h>
14 #elif MAJOR_IN_SYSMACROS
15 #include <sys/sysmacros.h>
17 #include <sys/types.h> /* already included from system.h */
21 #include <rpm/rpmio.h>
22 #include <rpm/rpmlog.h>
23 #include <rpm/rpmstring.h>
26 #include "lib/rpmarchive.h"
39 * Size limit for individual files in "new ascii format" cpio archives.
40 * The max size of the entire archive is unlimited from cpio POV,
41 * but subject to filesystem limitations.
43 #define CPIO_FILESIZE_MAX UINT32_MAX
45 #define CPIO_NEWC_MAGIC "070701"
46 #define CPIO_CRC_MAGIC "070702"
47 #define CPIO_STRIPPED_MAGIC "07070X"
48 #define CPIO_TRAILER "TRAILER!!!"
51 * Cpio archive header information.
53 struct cpioCrcPhysicalHeader {
54 /* char magic[6]; handled separately */
67 char checksum[8]; /* ignored !! */
70 #define PHYS_HDR_SIZE 104 /* Don't depend on sizeof(struct) */
72 struct cpioStrippedPhysicalHeader {
73 /* char magic[6]; handled separately */
77 #define STRIPPED_PHYS_HDR_SIZE 8 /* Don't depend on sizeof(struct) */
79 rpmcpio_t rpmcpioOpen(FD_t fd, char mode)
81 if ((mode & O_ACCMODE) != O_RDONLY &&
82 (mode & O_ACCMODE) != O_WRONLY)
85 rpmcpio_t cpio = xcalloc(1, sizeof(*cpio));
86 cpio->fd = fdLink(fd);
92 off_t rpmcpioTell(rpmcpio_t cpio)
99 * Convert string to unsigned integer (with buffer size check).
100 * @param str input string
101 * @retval endptr address of 1st character not processed
102 * @param base numerical conversion base
103 * @param num max no. of bytes to read
104 * @return converted integer
106 static unsigned long strntoul(const char *str,char **endptr, int base, size_t num)
108 char buf[num+1], * end;
111 strncpy(buf, str, num);
114 ret = strtoul(buf, &end, base);
116 *endptr = ((char *)str) + (end - buf); /* XXX discards const */
118 *endptr = ((char *)str) + strlen(buf);
124 static int rpmcpioWritePad(rpmcpio_t cpio, ssize_t modulo)
127 ssize_t left, written;
128 memset(buf, 0, modulo);
129 left = (modulo - ((cpio->offset) % modulo)) % modulo;
132 written = Fwrite(&buf, left, 1, cpio->fd);
133 if (written != left) {
134 return RPMERR_WRITE_FAILED;
136 cpio->offset += written;
140 static int rpmcpioReadPad(rpmcpio_t cpio)
145 left = (modulo - (cpio->offset % modulo)) % modulo;
148 read = Fread(&buf, left, 1, cpio->fd);
149 cpio->offset += read;
151 return RPMERR_READ_FAILED;
156 #define GET_NUM_FIELD(phys, log) \
158 log = strntoul(phys, &end, 16, sizeof(phys)); \
160 if ( (end - phys) != sizeof(phys) ) return RPMERR_BAD_HEADER;
161 #define SET_NUM_FIELD(phys, val, space) \
162 sprintf(space, "%8.8lx", (unsigned long) (val)); \
164 memcpy(phys, space, 8) \
166 static int rpmcpioTrailerWrite(rpmcpio_t cpio)
168 struct cpioCrcPhysicalHeader hdr;
172 if (cpio->fileend != cpio->offset) {
173 return RPMERR_WRITE_FAILED;
176 rc = rpmcpioWritePad(cpio, 4);
180 memset(&hdr, '0', PHYS_HDR_SIZE);
181 memcpy(&hdr.nlink, "00000001", 8);
182 memcpy(&hdr.namesize, "0000000b", 8);
184 written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
185 cpio->offset += written;
187 return RPMERR_WRITE_FAILED;
190 written = Fwrite(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
191 cpio->offset += written;
192 if (written != PHYS_HDR_SIZE) {
193 return RPMERR_WRITE_FAILED;
195 written = Fwrite(&CPIO_TRAILER, sizeof(CPIO_TRAILER), 1, cpio->fd);
196 cpio->offset += written;
197 if (written != sizeof(CPIO_TRAILER)) {
198 return RPMERR_WRITE_FAILED;
202 * XXX GNU cpio pads to 512 bytes. This may matter for
203 * tape device(s) and/or concatenated cpio archives.
206 rc = rpmcpioWritePad(cpio, 4);
211 int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
213 struct cpioCrcPhysicalHeader hdr_s;
214 struct cpioCrcPhysicalHeader * hdr = &hdr_s;
220 if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
221 return RPMERR_WRITE_FAILED;
224 if (cpio->fileend != cpio->offset) {
225 return RPMERR_WRITE_FAILED;
228 if (st->st_size >= CPIO_FILESIZE_MAX) {
229 return RPMERR_FILE_SIZE;
232 rc = rpmcpioWritePad(cpio, 4);
237 SET_NUM_FIELD(hdr->inode, st->st_ino, field);
238 SET_NUM_FIELD(hdr->mode, st->st_mode, field);
239 SET_NUM_FIELD(hdr->uid, st->st_uid, field);
240 SET_NUM_FIELD(hdr->gid, st->st_gid, field);
241 SET_NUM_FIELD(hdr->nlink, st->st_nlink, field);
242 SET_NUM_FIELD(hdr->mtime, st->st_mtime, field);
243 SET_NUM_FIELD(hdr->filesize, st->st_size, field);
245 dev = major(st->st_dev); SET_NUM_FIELD(hdr->devMajor, dev, field);
246 dev = minor(st->st_dev); SET_NUM_FIELD(hdr->devMinor, dev, field);
247 dev = major(st->st_rdev); SET_NUM_FIELD(hdr->rdevMajor, dev, field);
248 dev = minor(st->st_rdev); SET_NUM_FIELD(hdr->rdevMinor, dev, field);
250 len = strlen(path) + 1;
251 SET_NUM_FIELD(hdr->namesize, len, field);
253 memcpy(hdr->checksum, "00000000", 8);
255 written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
256 cpio->offset += written;
258 return RPMERR_WRITE_FAILED;
261 written = Fwrite(hdr, PHYS_HDR_SIZE, 1, cpio->fd);
262 cpio->offset += written;
263 if (written != PHYS_HDR_SIZE) {
264 return RPMERR_WRITE_FAILED;
267 written = Fwrite(path, len, 1, cpio->fd);
268 cpio->offset += written;
269 if (written != len) {
270 return RPMERR_WRITE_FAILED;
273 rc = rpmcpioWritePad(cpio, 4);
275 cpio->fileend = cpio->offset + st->st_size;
280 int rpmcpioStrippedHeaderWrite(rpmcpio_t cpio, int fx, off_t fsize)
282 struct cpioStrippedPhysicalHeader hdr_s;
283 struct cpioStrippedPhysicalHeader * hdr = &hdr_s;
288 if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
289 return RPMERR_WRITE_FAILED;
292 if (cpio->fileend != cpio->offset) {
293 return RPMERR_WRITE_FAILED;
296 rc = rpmcpioWritePad(cpio, 4);
301 SET_NUM_FIELD(hdr->fx, fx, field);
303 written = Fwrite(CPIO_STRIPPED_MAGIC, 6, 1, cpio->fd);
304 cpio->offset += written;
306 return RPMERR_WRITE_FAILED;
309 written = Fwrite(hdr, STRIPPED_PHYS_HDR_SIZE, 1, cpio->fd);
310 cpio->offset += written;
311 if (written != STRIPPED_PHYS_HDR_SIZE) {
312 return RPMERR_WRITE_FAILED;
315 rc = rpmcpioWritePad(cpio, 4);
317 cpio->fileend = cpio->offset + fsize;
322 ssize_t rpmcpioWrite(rpmcpio_t cpio, const void * buf, size_t size)
324 size_t written, left;
326 if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
327 return RPMERR_WRITE_FAILED;
330 // Do not write beyond file length
331 left = cpio->fileend - cpio->offset;
332 size = size > left ? left : size;
333 written = Fwrite(buf, size, 1, cpio->fd);
334 cpio->offset += written;
339 int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, int * fx)
341 struct cpioCrcPhysicalHeader hdr;
349 if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
350 return RPMERR_READ_FAILED;
353 /* Move to next file */
354 if (cpio->fileend != cpio->offset) {
355 /* XXX try using Fseek() - which is currently broken */
357 while (cpio->fileend != cpio->offset) {
358 read = cpio->fileend - cpio->offset > 8*BUFSIZ ? 8*BUFSIZ : cpio->fileend - cpio->offset;
359 if (rpmcpioRead(cpio, &buf, read) != read) {
360 return RPMERR_READ_FAILED;
365 rc = rpmcpioReadPad(cpio);
368 read = Fread(&magic, 6, 1, cpio->fd);
369 cpio->offset += read;
371 return RPMERR_BAD_MAGIC;
373 /* read stripped header */
374 if (!strncmp(CPIO_STRIPPED_MAGIC, magic,
375 sizeof(CPIO_STRIPPED_MAGIC)-1)) {
376 struct cpioStrippedPhysicalHeader shdr;
377 read = Fread(&shdr, STRIPPED_PHYS_HDR_SIZE, 1, cpio->fd);
378 cpio->offset += read;
379 if (read != STRIPPED_PHYS_HDR_SIZE)
380 return RPMERR_BAD_HEADER;
382 GET_NUM_FIELD(shdr.fx, *fx);
383 rc = rpmcpioReadPad(cpio);
385 if (!rc && *fx == -1)
386 rc = RPMERR_ITER_END;
390 if (strncmp(CPIO_CRC_MAGIC, magic, sizeof(CPIO_CRC_MAGIC)-1) &&
391 strncmp(CPIO_NEWC_MAGIC, magic, sizeof(CPIO_NEWC_MAGIC)-1)) {
392 return RPMERR_BAD_MAGIC;
395 read = Fread(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
396 cpio->offset += read;
397 if (read != PHYS_HDR_SIZE)
398 return RPMERR_BAD_HEADER;
400 GET_NUM_FIELD(hdr.filesize, fsize);
401 GET_NUM_FIELD(hdr.namesize, nameSize);
402 if (nameSize <= 0 || nameSize > 4096) {
403 return RPMERR_BAD_HEADER;
406 char name[nameSize + 1];
407 read = Fread(name, nameSize, 1, cpio->fd);
408 name[nameSize] = '\0';
409 cpio->offset += read;
410 if (read != nameSize ) {
411 return RPMERR_BAD_HEADER;
414 rc = rpmcpioReadPad(cpio);
415 cpio->fileend = cpio->offset + fsize;
417 if (!rc && rstreq(name, CPIO_TRAILER))
418 rc = RPMERR_ITER_END;
421 *path = xstrdup(name);
426 void rpmcpioSetExpectedFileSize(rpmcpio_t cpio, off_t fsize)
428 cpio->fileend = cpio->offset + fsize;
431 ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size)
435 if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
436 return RPMERR_READ_FAILED;
439 left = cpio->fileend - cpio->offset;
440 size = size > left ? left : size;
441 read = Fread(buf, size, 1, cpio->fd);
442 cpio->offset += read;
446 int rpmcpioClose(rpmcpio_t cpio)
449 if ((cpio->mode & O_ACCMODE) == O_WRONLY) {
450 rc = rpmcpioTrailerWrite(cpio);
457 rpmcpio_t rpmcpioFree(rpmcpio_t cpio)
461 (void) rpmcpioClose(cpio);