- use rpmdb-redhat to suggest dependency resolution(s).
[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 #include <rpmio_internal.h>
13 #include <rpmlib.h>
14
15 #include "cpio.h"
16 #include "fsm.h"
17
18 #include "rpmerr.h"
19 #include "debug.h"
20
21 /*@access FSM_t @*/
22
23 /**
24  * Convert string to unsigned integer (with buffer size check).
25  * @param str           input string
26  * @retval endptr       address of 1st character not processed
27  * @param base          numerical conversion base
28  * @param num           max no. of bytes to read
29  * @return              converted integer
30  */
31 static int strntoul(const char *str, /*@out@*/char **endptr, int base, int num)
32         /*@modifies *endptr @*/
33 {
34     char * buf, * end;
35     unsigned long ret;
36
37     buf = alloca(num + 1);
38     strncpy(buf, str, num);
39     buf[num] = '\0';
40
41     ret = strtoul(buf, &end, base);
42     if (*end != '\0')
43         *endptr = ((char *)str) + (end - buf);  /* XXX discards const */
44     else
45         *endptr = ((char *)str) + strlen(buf);
46
47     return ret;
48 }
49
50 #define GET_NUM_FIELD(phys, log) \
51         log = strntoul(phys, &end, 16, sizeof(phys)); \
52         if ( (end - phys) != sizeof(phys) ) return CPIOERR_BAD_HEADER;
53 #define SET_NUM_FIELD(phys, val, space) \
54         sprintf(space, "%8.8lx", (unsigned long) (val)); \
55         memcpy(phys, space, 8);
56
57 int cpioTrailerWrite(FSM_t fsm)
58 {
59     struct cpioCrcPhysicalHeader * hdr =
60         (struct cpioCrcPhysicalHeader *)fsm->rdbuf;
61     int rc;
62
63     memset(hdr, '0', PHYS_HDR_SIZE);
64     memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
65     memcpy(hdr->nlink, "00000001", 8);
66     memcpy(hdr->namesize, "0000000b", 8);
67     memcpy(fsm->rdbuf + PHYS_HDR_SIZE, CPIO_TRAILER, sizeof(CPIO_TRAILER));
68
69     /* XXX DWRITE uses rdnb for I/O length. */
70     fsm->rdnb = PHYS_HDR_SIZE + sizeof(CPIO_TRAILER);
71     rc = fsmStage(fsm, FSM_DWRITE);
72
73     /*
74      * GNU cpio pads to 512 bytes here, but we don't. This may matter for
75      * tape device(s) and/or concatenated cpio archives. <shrug>
76      */
77     if (!rc)
78         rc = fsmStage(fsm, FSM_PAD);
79
80     return rc;
81 }
82
83 int cpioHeaderWrite(FSM_t fsm, struct stat * st)
84 {
85     struct cpioCrcPhysicalHeader * hdr = (struct cpioCrcPhysicalHeader *)fsm->rdbuf;
86     char field[64];
87     size_t len;
88     dev_t dev;
89     int rc = 0;
90
91     memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
92     SET_NUM_FIELD(hdr->inode, st->st_ino, field);
93     SET_NUM_FIELD(hdr->mode, st->st_mode, field);
94     SET_NUM_FIELD(hdr->uid, st->st_uid, field);
95     SET_NUM_FIELD(hdr->gid, st->st_gid, field);
96     SET_NUM_FIELD(hdr->nlink, st->st_nlink, field);
97     SET_NUM_FIELD(hdr->mtime, st->st_mtime, field);
98     SET_NUM_FIELD(hdr->filesize, st->st_size, field);
99
100     dev = major((unsigned)st->st_dev); SET_NUM_FIELD(hdr->devMajor, dev, field);
101     dev = minor((unsigned)st->st_dev); SET_NUM_FIELD(hdr->devMinor, dev, field);
102     dev = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr->rdevMajor, dev, field);
103     dev = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr->rdevMinor, dev, field);
104
105     len = strlen(fsm->path) + 1; SET_NUM_FIELD(hdr->namesize, len, field);
106     memcpy(hdr->checksum, "00000000", 8);
107     memcpy(fsm->rdbuf + PHYS_HDR_SIZE, fsm->path, len);
108
109     /* XXX DWRITE uses rdnb for I/O length. */
110     fsm->rdnb = PHYS_HDR_SIZE + len;
111     rc = fsmStage(fsm, FSM_DWRITE);
112     if (!rc && fsm->rdnb != fsm->wrnb)
113         rc = CPIOERR_WRITE_FAILED;
114     if (!rc)
115         rc = fsmStage(fsm, FSM_PAD);
116     return rc;
117 }
118
119 int cpioHeaderRead(FSM_t fsm, struct stat * st)
120         /*@modifies fsm, *st @*/
121 {
122     struct cpioCrcPhysicalHeader hdr;
123     int nameSize;
124     char * end;
125     int major, minor;
126     int rc = 0;
127
128     fsm->wrlen = PHYS_HDR_SIZE;
129     rc = fsmStage(fsm, FSM_DREAD);
130     if (!rc && fsm->rdnb != fsm->wrlen)
131         rc = CPIOERR_READ_FAILED;
132     if (rc) return rc;
133     memcpy(&hdr, fsm->wrbuf, fsm->rdnb);
134
135     if (strncmp(CPIO_CRC_MAGIC, hdr.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
136         strncmp(CPIO_NEWC_MAGIC, hdr.magic, sizeof(CPIO_NEWC_MAGIC)-1))
137         return CPIOERR_BAD_MAGIC;
138
139     GET_NUM_FIELD(hdr.inode, st->st_ino);
140     GET_NUM_FIELD(hdr.mode, st->st_mode);
141     GET_NUM_FIELD(hdr.uid, st->st_uid);
142     GET_NUM_FIELD(hdr.gid, st->st_gid);
143     GET_NUM_FIELD(hdr.nlink, st->st_nlink);
144     GET_NUM_FIELD(hdr.mtime, st->st_mtime);
145     GET_NUM_FIELD(hdr.filesize, st->st_size);
146
147     GET_NUM_FIELD(hdr.devMajor, major);
148     GET_NUM_FIELD(hdr.devMinor, minor);
149     /*@-shiftimplementation@*/
150     st->st_dev = makedev(major, minor);
151     /*@=shiftimplementation@*/
152
153     GET_NUM_FIELD(hdr.rdevMajor, major);
154     GET_NUM_FIELD(hdr.rdevMinor, minor);
155     /*@-shiftimplementation@*/
156     st->st_rdev = makedev(major, minor);
157     /*@=shiftimplementation@*/
158
159     GET_NUM_FIELD(hdr.namesize, nameSize);
160     if (nameSize >= fsm->wrsize)
161         return CPIOERR_BAD_HEADER;
162
163     {   char * t = xmalloc(nameSize + 1);
164         fsm->wrlen = nameSize;
165         rc = fsmStage(fsm, FSM_DREAD);
166         if (!rc && fsm->rdnb != fsm->wrlen)
167             rc = CPIOERR_BAD_HEADER;
168         if (rc) {
169             t = _free(t);
170             fsm->path = NULL;
171             return rc;
172         }
173         memcpy(t, fsm->wrbuf, fsm->rdnb);
174         t[nameSize] = '\0';
175         fsm->path = t;
176     }
177
178     return 0;
179 }
180
181 const char *const cpioStrerror(int rc)
182 {
183     static char msg[256];
184     char *s;
185     int l, myerrno = errno;
186
187     strcpy(msg, "cpio: ");
188     /*@-branchstate@*/
189     switch (rc) {
190     default:
191         s = msg + strlen(msg);
192         sprintf(s, _("(error 0x%x)"), (unsigned)rc);
193         s = NULL;
194         break;
195     case CPIOERR_BAD_MAGIC:     s = _("Bad magic");             break;
196     case CPIOERR_BAD_HEADER:    s = _("Bad/unreadable  header");break;
197
198     case CPIOERR_OPEN_FAILED:   s = "open";     break;
199     case CPIOERR_CHMOD_FAILED:  s = "chmod";    break;
200     case CPIOERR_CHOWN_FAILED:  s = "chown";    break;
201     case CPIOERR_WRITE_FAILED:  s = "write";    break;
202     case CPIOERR_UTIME_FAILED:  s = "utime";    break;
203     case CPIOERR_UNLINK_FAILED: s = "unlink";   break;
204     case CPIOERR_RENAME_FAILED: s = "rename";   break;
205     case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
206     case CPIOERR_STAT_FAILED:   s = "stat";     break;
207     case CPIOERR_LSTAT_FAILED:  s = "lstat";    break;
208     case CPIOERR_MKDIR_FAILED:  s = "mkdir";    break;
209     case CPIOERR_RMDIR_FAILED:  s = "rmdir";    break;
210     case CPIOERR_MKNOD_FAILED:  s = "mknod";    break;
211     case CPIOERR_MKFIFO_FAILED: s = "mkfifo";   break;
212     case CPIOERR_LINK_FAILED:   s = "link";     break;
213     case CPIOERR_READLINK_FAILED: s = "readlink";       break;
214     case CPIOERR_READ_FAILED:   s = "read";     break;
215     case CPIOERR_COPY_FAILED:   s = "copy";     break;
216
217     case CPIOERR_HDR_SIZE:      s = _("Header size too big");   break;
218     case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type");  break;
219     case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break;
220     case CPIOERR_MD5SUM_MISMATCH: s = _("MD5 sum mismatch");    break;
221     case CPIOERR_INTERNAL:      s = _("Internal error");        break;
222     case CPIOERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
223     }
224     /*@=branchstate@*/
225
226     l = sizeof(msg) - strlen(msg) - 1;
227     if (s != NULL) {
228         if (l > 0) strncat(msg, s, l);
229         l -= strlen(s);
230     }
231     /*@-branchstate@*/
232     if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
233         s = _(" failed - ");
234         if (l > 0) strncat(msg, s, l);
235         l -= strlen(s);
236         if (l > 0) strncat(msg, strerror(myerrno), l);
237     }
238     /*@=branchstate@*/
239     return msg;
240 }