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