upgrade rpm version to 4.14.1
[platform/upstream/rpm.git] / lib / cpio.c
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
21 #include <rpm/rpmio.h>
22 #include <rpm/rpmlog.h>
23 #include <rpm/rpmstring.h>
24
25 #include "lib/cpio.h"
26 #include "lib/rpmarchive.h"
27
28 #include "debug.h"
29
30
31 struct rpmcpio_s {
32     FD_t fd;
33     char mode;
34     off_t offset;
35     off_t fileend;
36 };
37
38 /*
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.
42  */
43 #define CPIO_FILESIZE_MAX UINT32_MAX
44
45 #define CPIO_NEWC_MAGIC "070701"
46 #define CPIO_CRC_MAGIC  "070702"
47 #define CPIO_STRIPPED_MAGIC "07070X"
48 #define CPIO_TRAILER    "TRAILER!!!"
49
50 /** \ingroup payload
51  * Cpio archive header information.
52  */
53 struct cpioCrcPhysicalHeader {
54     /* char magic[6]; handled separately */
55     char inode[8];
56     char mode[8];
57     char uid[8];
58     char gid[8];
59     char nlink[8];
60     char mtime[8];
61     char filesize[8];
62     char devMajor[8];
63     char devMinor[8];
64     char rdevMajor[8];
65     char rdevMinor[8];
66     char namesize[8];
67     char checksum[8];                   /* ignored !! */
68 };
69
70 #define PHYS_HDR_SIZE   104             /* Don't depend on sizeof(struct) */
71
72 struct cpioStrippedPhysicalHeader {
73     /* char magic[6]; handled separately */
74     char fx[8];
75 };
76
77 #define STRIPPED_PHYS_HDR_SIZE 8       /* Don't depend on sizeof(struct) */
78
79 rpmcpio_t rpmcpioOpen(FD_t fd, char mode)
80 {
81     if ((mode & O_ACCMODE) != O_RDONLY &&
82         (mode & O_ACCMODE) != O_WRONLY)
83         return NULL;
84
85     rpmcpio_t cpio = xcalloc(1, sizeof(*cpio));
86     cpio->fd = fdLink(fd);
87     cpio->mode = mode;
88     cpio->offset = 0;
89     return cpio;
90 }
91
92 off_t rpmcpioTell(rpmcpio_t cpio)
93 {
94     return cpio->offset;
95 }
96
97
98 /**
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
105  */
106 static unsigned long strntoul(const char *str,char **endptr, int base, size_t num)
107 {
108     char buf[num+1], * end;
109     unsigned long ret;
110
111     strncpy(buf, str, num);
112     buf[num] = '\0';
113
114     ret = strtoul(buf, &end, base);
115     if (*end != '\0')
116         *endptr = ((char *)str) + (end - buf);  /* XXX discards const */
117     else
118         *endptr = ((char *)str) + strlen(buf);
119
120     return ret;
121 }
122
123
124 static int rpmcpioWritePad(rpmcpio_t cpio, ssize_t modulo)
125 {
126     char buf[modulo];
127     ssize_t left, written;
128     memset(buf, 0, modulo);
129     left = (modulo - ((cpio->offset) % modulo)) % modulo;
130     if (left <= 0)
131         return 0;
132     written = Fwrite(&buf, left, 1, cpio->fd);
133     if (written != left) {
134         return RPMERR_WRITE_FAILED;
135     }
136     cpio->offset += written;
137     return 0;
138 }
139
140 static int rpmcpioReadPad(rpmcpio_t cpio)
141 {
142     ssize_t modulo = 4;
143     char buf[4];
144     ssize_t left, read;
145     left = (modulo - (cpio->offset % modulo)) % modulo;
146     if (left <= 0)
147         return 0;
148     read = Fread(&buf, left, 1, cpio->fd);
149     cpio->offset += read;
150     if (read != left) {
151         return RPMERR_READ_FAILED;
152     }
153     return 0;
154 }
155
156 #define GET_NUM_FIELD(phys, log) \
157         \
158         log = strntoul(phys, &end, 16, sizeof(phys)); \
159         \
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)); \
163         \
164         memcpy(phys, space, 8) \
165
166 static int rpmcpioTrailerWrite(rpmcpio_t cpio)
167 {
168     struct cpioCrcPhysicalHeader hdr;
169     int rc;
170     size_t written;
171
172     if (cpio->fileend != cpio->offset) {
173         return RPMERR_WRITE_FAILED;
174     }
175
176     rc = rpmcpioWritePad(cpio, 4);
177     if (rc)
178         return rc;
179
180     memset(&hdr, '0', PHYS_HDR_SIZE);
181     memcpy(&hdr.nlink, "00000001", 8);
182     memcpy(&hdr.namesize, "0000000b", 8);
183
184     written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
185     cpio->offset += written;
186     if (written != 6) {
187         return RPMERR_WRITE_FAILED;
188     }
189
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;
194     }
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;
199     }
200
201     /*
202      * XXX GNU cpio pads to 512 bytes. This may matter for
203      * tape device(s) and/or concatenated cpio archives.
204      */
205
206     rc = rpmcpioWritePad(cpio, 4);
207
208     return rc;
209 }
210
211 int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
212 {
213     struct cpioCrcPhysicalHeader hdr_s;
214     struct cpioCrcPhysicalHeader * hdr = &hdr_s;
215     char field[64];
216     size_t len, written;
217     dev_t dev;
218     int rc = 0;
219
220     if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
221         return RPMERR_WRITE_FAILED;
222     }
223
224     if (cpio->fileend != cpio->offset) {
225         return RPMERR_WRITE_FAILED;
226     }
227
228     if (st->st_size >= CPIO_FILESIZE_MAX) {
229         return RPMERR_FILE_SIZE;
230     }
231
232     rc = rpmcpioWritePad(cpio, 4);
233     if (rc) {
234         return rc;
235     }
236
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);
244
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);
249
250     len = strlen(path) + 1;
251     SET_NUM_FIELD(hdr->namesize, len, field);
252
253     memcpy(hdr->checksum, "00000000", 8);
254
255     written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
256     cpio->offset += written;
257     if (written != 6) {
258         return RPMERR_WRITE_FAILED;
259     }
260
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;
265     }
266
267     written = Fwrite(path, len, 1, cpio->fd);
268     cpio->offset += written;
269     if (written != len) {
270         return RPMERR_WRITE_FAILED;
271     }
272
273     rc = rpmcpioWritePad(cpio, 4);
274
275     cpio->fileend = cpio->offset + st->st_size;
276
277     return rc;
278 }
279
280 int rpmcpioStrippedHeaderWrite(rpmcpio_t cpio, int fx, off_t fsize)
281 {
282     struct cpioStrippedPhysicalHeader hdr_s;
283     struct cpioStrippedPhysicalHeader * hdr = &hdr_s;
284     char field[64];
285     size_t written;
286     int rc = 0;
287
288     if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
289         return RPMERR_WRITE_FAILED;
290     }
291
292     if (cpio->fileend != cpio->offset) {
293         return RPMERR_WRITE_FAILED;
294     }
295
296     rc = rpmcpioWritePad(cpio, 4);
297     if (rc) {
298         return rc;
299     }
300
301     SET_NUM_FIELD(hdr->fx, fx, field);
302
303     written = Fwrite(CPIO_STRIPPED_MAGIC, 6, 1, cpio->fd);
304     cpio->offset += written;
305     if (written != 6) {
306         return RPMERR_WRITE_FAILED;
307     }
308
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;
313     }
314
315     rc = rpmcpioWritePad(cpio, 4);
316
317     cpio->fileend = cpio->offset + fsize;
318
319     return rc;
320 }
321
322 ssize_t rpmcpioWrite(rpmcpio_t cpio, const void * buf, size_t size)
323 {
324     size_t written, left;
325
326     if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
327         return RPMERR_WRITE_FAILED;
328     }
329
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;
335     return written;
336 }
337
338
339 int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, int * fx)
340 {
341     struct cpioCrcPhysicalHeader hdr;
342     int nameSize;
343     char * end;
344     int rc = 0;
345     ssize_t read;
346     char magic[6];
347     rpm_loff_t fsize;
348
349     if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
350         return RPMERR_READ_FAILED;
351     }
352
353     /* Move to next file */
354     if (cpio->fileend != cpio->offset) {
355         /* XXX try using Fseek() - which is currently broken */
356         char buf[8*BUFSIZ];
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;
361             }
362         }
363     }
364
365     rc = rpmcpioReadPad(cpio);
366     if (rc) return rc;
367
368     read = Fread(&magic, 6, 1, cpio->fd);
369     cpio->offset += read;
370     if (read != 6)
371         return RPMERR_BAD_MAGIC;
372
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;
381
382         GET_NUM_FIELD(shdr.fx, *fx);
383         rc = rpmcpioReadPad(cpio);
384
385         if (!rc && *fx == -1)
386             rc = RPMERR_ITER_END;
387         return rc;
388     }
389
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;
393     }
394
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;
399
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;
404     }
405
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;
412     }
413
414     rc = rpmcpioReadPad(cpio);
415     cpio->fileend = cpio->offset + fsize;
416
417     if (!rc && rstreq(name, CPIO_TRAILER))
418         rc = RPMERR_ITER_END;
419
420     if (!rc && path)
421         *path = xstrdup(name);
422
423     return rc;
424 }
425
426 void rpmcpioSetExpectedFileSize(rpmcpio_t cpio, off_t fsize)
427 {
428     cpio->fileend = cpio->offset + fsize;
429 }
430
431 ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size)
432 {
433     size_t read, left;
434
435     if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
436         return RPMERR_READ_FAILED;
437     }
438
439     left = cpio->fileend - cpio->offset;
440     size = size > left ? left : size;
441     read = Fread(buf, size, 1, cpio->fd);
442     cpio->offset += read;
443     return read;
444 }
445
446 int rpmcpioClose(rpmcpio_t cpio)
447 {
448     int rc = 0;
449     if ((cpio->mode & O_ACCMODE) == O_WRONLY) {
450         rc = rpmcpioTrailerWrite(cpio);
451     }
452     fdFree(cpio->fd);
453     cpio->fd = NULL;
454     return rc;
455 }
456
457 rpmcpio_t rpmcpioFree(rpmcpio_t cpio)
458 {
459     if (cpio) {
460         if (cpio->fd)
461             (void) rpmcpioClose(cpio);
462         free(cpio);
463     }
464     return NULL;
465 }