summaryrefslogtreecommitdiff
path: root/lib/cpio.c
diff options
context:
space:
mode:
authorJinkun Jang <jinkun.jang@samsung.com>2013-03-12 15:17:20 +0900
committerJinkun Jang <jinkun.jang@samsung.com>2013-03-12 15:17:20 +0900
commit7df2385c2f6c93f96e00bc87f2086066cae89ecc (patch)
tree79d5c20a494622eb084de831a2a51530cd421e33 /lib/cpio.c
parentb7a3bffb8e0341b7e4ef69def268bca3a7f279ff (diff)
downloadrpm-tizen_2.2.tar.gz
rpm-tizen_2.2.tar.bz2
rpm-tizen_2.2.zip
Diffstat (limited to 'lib/cpio.c')
-rw-r--r--lib/cpio.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/lib/cpio.c b/lib/cpio.c
new file mode 100644
index 0000000..b5c39c0
--- /dev/null
+++ b/lib/cpio.c
@@ -0,0 +1,245 @@
+/** \ingroup payload
+ * \file lib/cpio.c
+ * Handle cpio payloads within rpm packages.
+ *
+ * \warning FIXME: We don't translate between cpio and system mode bits! These
+ * should both be the same, but really odd things are going to happen if
+ * that's not true!
+ */
+
+#include "system.h"
+
+#if MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#elif MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#else
+#include <sys/types.h> /* already included from system.h */
+#endif
+#include <errno.h>
+
+#include <rpm/rpmio.h>
+#include <rpm/rpmlog.h>
+
+#include "lib/cpio.h"
+#include "lib/fsm.h"
+
+#include "debug.h"
+
+
+/**
+ * Convert string to unsigned integer (with buffer size check).
+ * @param str input string
+ * @retval endptr address of 1st character not processed
+ * @param base numerical conversion base
+ * @param num max no. of bytes to read
+ * @return converted integer
+ */
+static unsigned long strntoul(const char *str,char **endptr, int base, size_t num)
+{
+ char buf[num+1], * end;
+ unsigned long ret;
+
+ strncpy(buf, str, num);
+ buf[num] = '\0';
+
+ ret = strtoul(buf, &end, base);
+ if (*end != '\0')
+ *endptr = ((char *)str) + (end - buf); /* XXX discards const */
+ else
+ *endptr = ((char *)str) + strlen(buf);
+
+ return ret;
+}
+
+#define GET_NUM_FIELD(phys, log) \
+ \
+ log = strntoul(phys, &end, 16, sizeof(phys)); \
+ \
+ if ( (end - phys) != sizeof(phys) ) return CPIOERR_BAD_HEADER;
+#define SET_NUM_FIELD(phys, val, space) \
+ sprintf(space, "%8.8lx", (unsigned long) (val)); \
+ \
+ memcpy(phys, space, 8) \
+
+int cpioTrailerWrite(FSM_t fsm)
+{
+ struct cpioCrcPhysicalHeader * hdr =
+ (struct cpioCrcPhysicalHeader *)fsm->rdbuf;
+ int rc;
+
+ memset(hdr, '0', PHYS_HDR_SIZE);
+ memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
+ memcpy(hdr->nlink, "00000001", 8);
+ memcpy(hdr->namesize, "0000000b", 8);
+ memcpy(fsm->rdbuf + PHYS_HDR_SIZE, CPIO_TRAILER, sizeof(CPIO_TRAILER));
+
+ /* XXX DWRITE uses rdnb for I/O length. */
+ fsm->rdnb = PHYS_HDR_SIZE + sizeof(CPIO_TRAILER);
+ rc = fsmNext(fsm, FSM_DWRITE);
+
+ /*
+ * GNU cpio pads to 512 bytes here, but we don't. This may matter for
+ * tape device(s) and/or concatenated cpio archives. <shrug>
+ */
+ if (!rc)
+ rc = fsmNext(fsm, FSM_PAD);
+
+ return rc;
+}
+
+int cpioHeaderWrite(FSM_t fsm, struct stat * st)
+{
+ struct cpioCrcPhysicalHeader * hdr = (struct cpioCrcPhysicalHeader *)fsm->rdbuf;
+ char field[64];
+ size_t len;
+ dev_t dev;
+ int rc = 0;
+
+ memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
+ SET_NUM_FIELD(hdr->inode, st->st_ino, field);
+ SET_NUM_FIELD(hdr->mode, st->st_mode, field);
+ SET_NUM_FIELD(hdr->uid, st->st_uid, field);
+ SET_NUM_FIELD(hdr->gid, st->st_gid, field);
+ SET_NUM_FIELD(hdr->nlink, st->st_nlink, field);
+ SET_NUM_FIELD(hdr->mtime, st->st_mtime, field);
+ SET_NUM_FIELD(hdr->filesize, st->st_size, field);
+
+ dev = major(st->st_dev); SET_NUM_FIELD(hdr->devMajor, dev, field);
+ dev = minor(st->st_dev); SET_NUM_FIELD(hdr->devMinor, dev, field);
+ dev = major(st->st_rdev); SET_NUM_FIELD(hdr->rdevMajor, dev, field);
+ dev = minor(st->st_rdev); SET_NUM_FIELD(hdr->rdevMinor, dev, field);
+
+ len = strlen(fsm->path) + 1; SET_NUM_FIELD(hdr->namesize, len, field);
+ memcpy(hdr->checksum, "00000000", 8);
+ memcpy(fsm->rdbuf + PHYS_HDR_SIZE, fsm->path, len);
+
+ /* XXX DWRITE uses rdnb for I/O length. */
+ fsm->rdnb = PHYS_HDR_SIZE + len;
+ rc = fsmNext(fsm, FSM_DWRITE);
+ if (!rc && fsm->rdnb != fsm->wrnb)
+ rc = CPIOERR_WRITE_FAILED;
+ if (!rc)
+ rc = fsmNext(fsm, FSM_PAD);
+ return rc;
+}
+
+int cpioHeaderRead(FSM_t fsm, struct stat * st)
+{
+ struct cpioCrcPhysicalHeader hdr;
+ int nameSize;
+ char * end;
+ unsigned int major, minor;
+ int rc = 0;
+
+ fsm->wrlen = PHYS_HDR_SIZE;
+ rc = fsmNext(fsm, FSM_DREAD);
+ if (!rc && fsm->rdnb != fsm->wrlen)
+ rc = CPIOERR_READ_FAILED;
+ if (rc) return rc;
+ memcpy(&hdr, fsm->wrbuf, fsm->rdnb);
+
+ if (strncmp(CPIO_CRC_MAGIC, hdr.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
+ strncmp(CPIO_NEWC_MAGIC, hdr.magic, sizeof(CPIO_NEWC_MAGIC)-1))
+ return CPIOERR_BAD_MAGIC;
+
+ GET_NUM_FIELD(hdr.inode, st->st_ino);
+ GET_NUM_FIELD(hdr.mode, st->st_mode);
+ GET_NUM_FIELD(hdr.uid, st->st_uid);
+ GET_NUM_FIELD(hdr.gid, st->st_gid);
+ GET_NUM_FIELD(hdr.nlink, st->st_nlink);
+ GET_NUM_FIELD(hdr.mtime, st->st_mtime);
+ GET_NUM_FIELD(hdr.filesize, st->st_size);
+
+ GET_NUM_FIELD(hdr.devMajor, major);
+ GET_NUM_FIELD(hdr.devMinor, minor);
+ st->st_dev = makedev(major, minor);
+
+ GET_NUM_FIELD(hdr.rdevMajor, major);
+ GET_NUM_FIELD(hdr.rdevMinor, minor);
+ st->st_rdev = makedev(major, minor);
+
+ GET_NUM_FIELD(hdr.namesize, nameSize);
+ if (nameSize >= fsm->wrsize)
+ return CPIOERR_BAD_HEADER;
+
+ { char * t = xmalloc(nameSize + 1);
+ fsm->wrlen = nameSize;
+ rc = fsmNext(fsm, FSM_DREAD);
+ if (!rc && fsm->rdnb != fsm->wrlen)
+ rc = CPIOERR_BAD_HEADER;
+ if (rc) {
+ t = _free(t);
+ fsm->path = NULL;
+ return rc;
+ }
+ memcpy(t, fsm->wrbuf, fsm->rdnb);
+ t[nameSize] = '\0';
+ fsm->path = t;
+ }
+
+ return 0;
+}
+
+const char * cpioStrerror(int rc)
+{
+ static char msg[256];
+ const char *s;
+ int myerrno = errno;
+ size_t l;
+
+ strcpy(msg, "cpio: ");
+ switch (rc) {
+ default: {
+ char *t = msg + strlen(msg);
+ sprintf(t, _("(error 0x%x)"), (unsigned)rc);
+ s = NULL;
+ break;
+ }
+ case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
+ case CPIOERR_BAD_HEADER: s = _("Bad/unreadable header");break;
+
+ case CPIOERR_OPEN_FAILED: s = "open"; break;
+ case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
+ case CPIOERR_CHOWN_FAILED: s = "chown"; break;
+ case CPIOERR_WRITE_FAILED: s = "write"; break;
+ case CPIOERR_UTIME_FAILED: s = "utime"; break;
+ case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
+ case CPIOERR_RENAME_FAILED: s = "rename"; break;
+ case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
+ case CPIOERR_STAT_FAILED: s = "stat"; break;
+ case CPIOERR_LSTAT_FAILED: s = "lstat"; break;
+ case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
+ case CPIOERR_RMDIR_FAILED: s = "rmdir"; break;
+ case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
+ case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
+ case CPIOERR_LINK_FAILED: s = "link"; break;
+ case CPIOERR_READLINK_FAILED: s = "readlink"; break;
+ case CPIOERR_READ_FAILED: s = "read"; break;
+ case CPIOERR_COPY_FAILED: s = "copy"; break;
+ case CPIOERR_LSETFCON_FAILED: s = "lsetfilecon"; break;
+ case CPIOERR_SETCAP_FAILED: s = "cap_set_file"; break;
+
+ case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
+ case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
+ case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break;
+ case CPIOERR_DIGEST_MISMATCH: s = _("Digest mismatch"); break;
+ case CPIOERR_INTERNAL: s = _("Internal error"); break;
+ case CPIOERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
+ case CPIOERR_ENOENT: s = strerror(ENOENT); break;
+ case CPIOERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break;
+ }
+
+ l = sizeof(msg) - strlen(msg) - 1;
+ if (s != NULL) {
+ if (l > 0) strncat(msg, s, l);
+ l -= strlen(s);
+ }
+ if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
+ s = _(" failed - ");
+ if (l > 0) strncat(msg, s, l);
+ l -= strlen(s);
+ if (l > 0) strncat(msg, strerror(myerrno), l);
+ }
+ return msg;
+}