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