diff options
author | Kim Kibum <kb0929.kim@samsung.com> | 2012-05-21 17:49:08 +0900 |
---|---|---|
committer | Kim Kibum <kb0929.kim@samsung.com> | 2012-05-21 17:49:08 +0900 |
commit | dec48cfa66e17ba4a7e50c92cb24b913289feb12 (patch) | |
tree | e1f48cd5cabb40a1d604b36949ff072d01267cb5 /lib/cpio.c | |
parent | b7a3bffb8e0341b7e4ef69def268bca3a7f279ff (diff) | |
download | rpm-dec48cfa66e17ba4a7e50c92cb24b913289feb12.tar.gz rpm-dec48cfa66e17ba4a7e50c92cb24b913289feb12.tar.bz2 rpm-dec48cfa66e17ba4a7e50c92cb24b913289feb12.zip |
Upload Tizen:Base source
Diffstat (limited to 'lib/cpio.c')
-rw-r--r-- | lib/cpio.c | 245 |
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; +} |