Add macro %isu_package to generate ISU Package
[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 <errno.h>
20 #include <string.h>
21
22 #include <rpm/rpmio.h>
23 #include <rpm/rpmlog.h>
24 #include <rpm/rpmstring.h>
25
26 #include "lib/cpio.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 rpmcpio_t rpmcpioOpen(FD_t fd, char mode)
39 {
40     if ((mode & O_ACCMODE) != O_RDONLY &&
41         (mode & O_ACCMODE) != O_WRONLY)
42         return NULL;
43
44     rpmcpio_t cpio = xcalloc(1, sizeof(*cpio));
45     cpio->fd = fdLink(fd);
46     cpio->mode = mode;
47     cpio->offset = 0;
48     return cpio;
49 }
50
51 off_t rpmcpioTell(rpmcpio_t cpio)
52 {
53     return cpio->offset;
54 }
55
56
57 /**
58  * Convert string to unsigned integer (with buffer size check).
59  * @param str           input string
60  * @retval endptr       address of 1st character not processed
61  * @param base          numerical conversion base
62  * @param num           max no. of bytes to read
63  * @return              converted integer
64  */
65 static unsigned long strntoul(const char *str,char **endptr, int base, size_t num)
66 {
67     char buf[num+1], * end;
68     unsigned long ret;
69
70     strncpy(buf, str, num);
71     buf[num] = '\0';
72
73     ret = strtoul(buf, &end, base);
74     if (*end != '\0')
75         *endptr = ((char *)str) + (end - buf);  /* XXX discards const */
76     else
77         *endptr = ((char *)str) + strlen(buf);
78
79     return ret;
80 }
81
82
83 static int rpmcpioWritePad(rpmcpio_t cpio, ssize_t modulo)
84 {
85     char buf[modulo];
86     ssize_t left, writen;
87     memset(buf, 0, modulo);
88     left = (modulo - ((cpio->offset) % modulo)) % modulo;
89     if (left <= 0)
90         return 0;
91     writen = Fwrite(&buf, left, 1, cpio->fd);
92     if (writen != left) {
93         return CPIOERR_WRITE_FAILED;
94     }
95     cpio->offset += writen;
96     return 0;
97 }
98
99 static int rpmcpioReadPad(rpmcpio_t cpio)
100 {
101     ssize_t modulo = 4;
102     char buf[4];
103     ssize_t left, read;
104     left = (modulo - (cpio->offset % modulo)) % modulo;
105     if (left <= 0)
106         return 0;
107     read = Fread(&buf, left, 1, cpio->fd);
108     cpio->offset += read;
109     if (read != left) {
110         return CPIOERR_READ_FAILED;
111     }
112     return 0;
113 }
114
115 #define GET_NUM_FIELD(phys, log) \
116         \
117         log = strntoul(phys, &end, 16, sizeof(phys)); \
118         \
119         if ( (end - phys) != sizeof(phys) ) return CPIOERR_BAD_HEADER;
120 #define SET_NUM_FIELD(phys, val, space) \
121         sprintf(space, "%8.8lx", (unsigned long) (val)); \
122         \
123         memcpy(phys, space, 8) \
124
125 static int rpmcpioTrailerWrite(rpmcpio_t cpio)
126 {
127     struct cpioCrcPhysicalHeader hdr;
128     int rc;
129     size_t writen;
130
131     if (cpio->fileend != cpio->offset) {
132         return CPIOERR_WRITE_FAILED;
133     }
134
135     rc = rpmcpioWritePad(cpio, 4);
136     if (rc)
137         return rc;
138
139     memset(&hdr, '0', PHYS_HDR_SIZE);
140     memcpy(&hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
141     memcpy(&hdr.nlink, "00000001", 8);
142     memcpy(&hdr.namesize, "0000000b", 8);
143     writen = Fwrite(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
144     cpio->offset += writen;
145     if (writen != PHYS_HDR_SIZE) {
146         return CPIOERR_WRITE_FAILED;
147     }
148     writen = Fwrite(&CPIO_TRAILER, sizeof(CPIO_TRAILER), 1, cpio->fd);
149     cpio->offset += writen;
150     if (writen != sizeof(CPIO_TRAILER)) {
151         return CPIOERR_WRITE_FAILED;
152     }
153
154     /*
155      * XXX GNU cpio pads to 512 bytes. This may matter for
156      * tape device(s) and/or concatenated cpio archives.
157      */
158
159     rc = rpmcpioWritePad(cpio, 4);
160
161     return rc;
162 }
163
164 int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
165 {
166     struct cpioCrcPhysicalHeader hdr_s;
167     struct cpioCrcPhysicalHeader * hdr = &hdr_s;
168     char field[64];
169     size_t len, writen;
170     dev_t dev;
171     int rc = 0;
172
173     if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
174         return CPIOERR_WRITE_FAILED;
175     }
176
177     if (cpio->fileend != cpio->offset) {
178         return CPIOERR_WRITE_FAILED;
179     }
180
181     if (st->st_size >= CPIO_FILESIZE_MAX) {
182         return CPIOERR_FILE_SIZE;
183     }
184
185     rc = rpmcpioWritePad(cpio, 4);
186     if (rc) {
187         return rc;
188     }
189
190     memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
191     SET_NUM_FIELD(hdr->inode, st->st_ino, field);
192     SET_NUM_FIELD(hdr->mode, st->st_mode, field);
193     SET_NUM_FIELD(hdr->uid, st->st_uid, field);
194     SET_NUM_FIELD(hdr->gid, st->st_gid, field);
195     SET_NUM_FIELD(hdr->nlink, st->st_nlink, field);
196     SET_NUM_FIELD(hdr->mtime, st->st_mtime, field);
197     SET_NUM_FIELD(hdr->filesize, st->st_size, field);
198
199     dev = major(st->st_dev); SET_NUM_FIELD(hdr->devMajor, dev, field);
200     dev = minor(st->st_dev); SET_NUM_FIELD(hdr->devMinor, dev, field);
201     dev = major(st->st_rdev); SET_NUM_FIELD(hdr->rdevMajor, dev, field);
202     dev = minor(st->st_rdev); SET_NUM_FIELD(hdr->rdevMinor, dev, field);
203
204     len = strlen(path) + 1;
205     SET_NUM_FIELD(hdr->namesize, len, field);
206
207     memcpy(hdr->checksum, "00000000", 8);
208
209     writen = Fwrite(hdr, PHYS_HDR_SIZE, 1, cpio->fd);
210     cpio->offset += writen;
211     if (writen != PHYS_HDR_SIZE) {
212         return CPIOERR_WRITE_FAILED;
213     }
214
215     writen = Fwrite(path, len, 1, cpio->fd);
216     cpio->offset += writen;
217     if (writen != len) {
218         return CPIOERR_WRITE_FAILED;
219     }
220
221     rc = rpmcpioWritePad(cpio, 4);
222
223     cpio->fileend = cpio->offset + st->st_size;
224
225     return rc;
226 }
227
228 ssize_t rpmcpioWrite(rpmcpio_t cpio, void * buf, size_t size)
229 {
230     size_t writen, left;
231
232     if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
233         return CPIOERR_WRITE_FAILED;
234     }
235
236     // Do not write beyond file length
237     left = cpio->fileend - cpio->offset;
238     size = size > left ? left : size;
239     writen = Fwrite(buf, size, 1, cpio->fd);
240     cpio->offset += writen;
241     return writen;
242 }
243
244
245 int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, struct stat * st)
246 {
247     struct cpioCrcPhysicalHeader hdr;
248     int nameSize;
249     char * end;
250     unsigned int major, minor;
251     int rc = 0;
252     ssize_t read;
253
254     if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
255         return CPIOERR_READ_FAILED;
256     }
257
258     /* Move to next file */
259     if (cpio->fileend != cpio->offset) {
260         /* XXX try using Fseek() - which is currently broken */
261         char buf[8*BUFSIZ];
262         while (cpio->fileend != cpio->offset) {
263             read = cpio->fileend - cpio->offset > 8*BUFSIZ ? 8*BUFSIZ : cpio->fileend - cpio->offset;
264             if (rpmcpioRead(cpio, &buf, read) != read) {
265                 return CPIOERR_READ_FAILED;
266             }
267         }
268     }
269
270     rc = rpmcpioReadPad(cpio);
271     if (rc) return rc;
272
273     read = Fread(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
274     cpio->offset += read;
275     if (read != PHYS_HDR_SIZE)
276         return CPIOERR_READ_FAILED;
277
278     if (strncmp(CPIO_CRC_MAGIC, hdr.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
279         strncmp(CPIO_NEWC_MAGIC, hdr.magic, sizeof(CPIO_NEWC_MAGIC)-1)) {
280         return CPIOERR_BAD_MAGIC;
281     }
282     GET_NUM_FIELD(hdr.inode, st->st_ino);
283     GET_NUM_FIELD(hdr.mode, st->st_mode);
284     GET_NUM_FIELD(hdr.uid, st->st_uid);
285     GET_NUM_FIELD(hdr.gid, st->st_gid);
286     GET_NUM_FIELD(hdr.nlink, st->st_nlink);
287     GET_NUM_FIELD(hdr.mtime, st->st_mtime);
288     GET_NUM_FIELD(hdr.filesize, st->st_size);
289
290     GET_NUM_FIELD(hdr.devMajor, major);
291     GET_NUM_FIELD(hdr.devMinor, minor);
292     st->st_dev = makedev(major, minor);
293
294     GET_NUM_FIELD(hdr.rdevMajor, major);
295     GET_NUM_FIELD(hdr.rdevMinor, minor);
296     st->st_rdev = makedev(major, minor);
297
298     GET_NUM_FIELD(hdr.namesize, nameSize);
299
300     *path = xmalloc(nameSize + 1);
301     read = Fread(*path, nameSize, 1, cpio->fd);
302     (*path)[nameSize] = '\0';
303     cpio->offset += read;
304     if (read != nameSize ) {
305         return CPIOERR_BAD_HEADER;
306     }
307
308     rc = rpmcpioReadPad(cpio);
309     cpio->fileend = cpio->offset + st->st_size;
310
311     if (!rc && rstreq(*path, CPIO_TRAILER))
312         rc = CPIOERR_HDR_TRAILER;
313
314     return rc;
315 }
316
317 ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size)
318 {
319     size_t read, left;
320
321     if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
322         return CPIOERR_READ_FAILED;
323     }
324
325     left = cpio->fileend - cpio->offset;
326     size = size > left ? left : size;
327     read = Fread(buf, size, 1, cpio->fd);
328     cpio->offset += read;
329     return read;
330 }
331
332 int rpmcpioClose(rpmcpio_t cpio)
333 {
334     int rc = 0;
335     if ((cpio->mode & O_ACCMODE) == O_WRONLY) {
336         rc = rpmcpioTrailerWrite(cpio);
337     }
338     fdFree(cpio->fd);
339     cpio->fd = NULL;
340     return rc;
341 }
342
343 rpmcpio_t rpmcpioFree(rpmcpio_t cpio)
344 {
345     if (cpio) {
346         if (cpio->fd)
347             (void) rpmcpioClose(cpio);
348         free(cpio);
349     }
350     return NULL;
351 }
352
353 const char * rpmcpioStrerror(int rc)
354 {
355     static char msg[256];
356     const char *s;
357     int myerrno = errno;
358     size_t l;
359
360     strcpy(msg, "cpio: ");
361     switch (rc) {
362     default: {
363         char *t = msg + strlen(msg);
364         sprintf(t, _("(error 0x%x)"), (unsigned)rc);
365         s = NULL;
366         break;
367     }
368     case CPIOERR_BAD_MAGIC:     s = _("Bad magic");             break;
369     case CPIOERR_BAD_HEADER:    s = _("Bad/unreadable  header");break;
370
371     case CPIOERR_OPEN_FAILED:   s = "open";     break;
372     case CPIOERR_CHMOD_FAILED:  s = "chmod";    break;
373     case CPIOERR_CHOWN_FAILED:  s = "chown";    break;
374     case CPIOERR_WRITE_FAILED:  s = "write";    break;
375     case CPIOERR_UTIME_FAILED:  s = "utime";    break;
376     case CPIOERR_UNLINK_FAILED: s = "unlink";   break;
377     case CPIOERR_RENAME_FAILED: s = "rename";   break;
378     case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
379     case CPIOERR_STAT_FAILED:   s = "stat";     break;
380     case CPIOERR_LSTAT_FAILED:  s = "lstat";    break;
381     case CPIOERR_MKDIR_FAILED:  s = "mkdir";    break;
382     case CPIOERR_RMDIR_FAILED:  s = "rmdir";    break;
383     case CPIOERR_MKNOD_FAILED:  s = "mknod";    break;
384     case CPIOERR_MKFIFO_FAILED: s = "mkfifo";   break;
385     case CPIOERR_LINK_FAILED:   s = "link";     break;
386     case CPIOERR_READLINK_FAILED: s = "readlink";       break;
387     case CPIOERR_READ_FAILED:   s = "read";     break;
388     case CPIOERR_COPY_FAILED:   s = "copy";     break;
389     case CPIOERR_LSETFCON_FAILED: s = "lsetfilecon";    break;
390     case CPIOERR_SETCAP_FAILED: s = "cap_set_file";     break;
391
392     case CPIOERR_HDR_SIZE:      s = _("Header size too big");   break;
393     case CPIOERR_FILE_SIZE:     s = _("File too large for archive");    break;
394     case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type");  break;
395     case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break;
396     case CPIOERR_DIGEST_MISMATCH: s = _("Digest mismatch");     break;
397     case CPIOERR_INTERNAL:      s = _("Internal error");        break;
398     case CPIOERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
399     case CPIOERR_ENOENT:        s = strerror(ENOENT); break;
400     case CPIOERR_ENOTEMPTY:     s = strerror(ENOTEMPTY); break;
401     }
402
403     l = sizeof(msg) - strlen(msg) - 1;
404     if (s != NULL) {
405         if (l > 0) strncat(msg, s, l);
406         l -= strlen(s);
407     }
408     if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
409         s = _(" failed - ");
410         if (l > 0) strncat(msg, s, l);
411         l -= strlen(s);
412         if (l > 0) strncat(msg, strerror(myerrno), l);
413     }
414     return msg;
415 }