Re: [PATCH 6/7] Add the cpio routine and interface to librpm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Well I had couple of reasons:

1) We had (in the recent past) a problem with the initrd being too big for PXE boot on some PPC machines
2) Including one library is better and faster than calling binary for every rpm we encounter
3) I have to check that the RPM provides specific stuff before exploding it (well I could use rpm binary too but..)
4) I want only modules and firmware files, because the initrd resides in memory and I do not want to pollute it more than necessary
5) I need them in different place because of multiple DDs (I know that rpm could install them in chroot too..)
5) The general movement in anaconda is towards libraries. We are getting rid of app calls everywhere.. so why not here? librpm is library and the code is pretty straightforward..
 - open RPM
 - get header
 - read whatever from the header
 - get compression
 - get me stream of uncompressed data
 - feed it to cpio unpacker
 - done

Yum API is much worse according to what I have seen. And we still use it.

Martin

----- "David Cantrell" <dcantrell@xxxxxxxxxx> wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On Wed, 2 Dec 2009, Martin Sivak wrote:
> 
> > - adds the code to unpack RPMs which provide specific Provide:
> > - adds the code to unpack cpio directly from the RPM
> > - adds the dependency on librpm
> > ---
> 
> I really don't want to see cpio code or even rpmlib code in the
> loader.  As
> previously mentioned, I think libarchive would work fine for cpio
> usage, but I
> was thinking about this a bit more and wonder why we can't just force
> a run of
> '/bin/rpm -Ivh --nodeps --force' from inside the loader.
> 
> The driver disks are allowing OEMs to ship addon drivers as RPMs so
> that we
> can add them to the yum transaction set and have the packaging system
> track
> them.  We do need it during installation, but instead of jumping
> through hoops
> to extract the payload, why not force /bin/rpm to run in the initrd to
> drop
> the module in place for installation?  We'd need an rpm --initdb, but
> it
> doesn't matter.  The whole purpose there would be to quickly get the
> driver in
> place and loaded for installation.  The rpm run during loader is just
> throw
> away.
> 
> > anaconda.spec.in    |    1 +
> > loader/Makefile.am  |    6 +-
> > loader/cpio.c       |  192
> +++++++++++++++++++++++++++++++++++++++++++
> > loader/cpio.h       |  116 ++++++++++++++++++++++++++
> > loader/rpmextract.c |  227
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> > loader/rpmextract.h |   47 +++++++++++
> > 6 files changed, 587 insertions(+), 2 deletions(-)
> > create mode 100644 loader/cpio.c
> > create mode 100644 loader/cpio.h
> > create mode 100644 loader/rpmextract.c
> > create mode 100644 loader/rpmextract.h
> >
> > diff --git a/anaconda.spec.in b/anaconda.spec.in
> > index 862e306..8344105 100644
> > --- a/anaconda.spec.in
> > +++ b/anaconda.spec.in
> > @@ -69,6 +69,7 @@ BuildRequires: pango-devel
> > BuildRequires: pykickstart >= %{pykickstartver}
> > BuildRequires: python-devel
> > BuildRequires: python-urlgrabber
> > +BuildRequires: rpm-devel
> > BuildRequires: rpm-python >= %{rpmpythonver}
> > BuildRequires: slang-devel >= %{slangver}
> > BuildRequires: xmlto
> > diff --git a/loader/Makefile.am b/loader/Makefile.am
> > index e5d1b7f..2d3b39b 100644
> > --- a/loader/Makefile.am
> > +++ b/loader/Makefile.am
> > @@ -45,13 +45,15 @@ loader_CFLAGS      = $(COMMON_CFLAGS)
> $(GLIB_CFLAGS) $(LIBNM_GLIB_CFLAGS) \
> > loader_LDADD       = $(NEWT_LIBS) $(GLIB_LIBS) $(LIBNL_LIBS) \
> >                      $(LIBNM_GLIB_LIBS) $(CHECKISOMD5_LIBS) \
> >                      $(LIBCURL_LIBS) \
> > -                     $(ISCSI_LIBS) $(top_srcdir)/isys/libisys.la
> > +                     $(ISCSI_LIBS) $(top_srcdir)/isys/libisys.la \
> > +		     -lrpm -lrpmio
> > loader_SOURCES     = loader.c copy.c log.c moduleinfo.c loadermisc.c
> \
> >                      modules.c windows.c lang.c kbd.c driverdisk.c
> \
> >                      selinux.c mediacheck.c kickstart.c
> driverselect.c \
> >                      getparts.c dirbrowser.c fwloader.c ibft.c
> hardware.c \
> >                      method.c cdinstall.c hdinstall.c nfsinstall.c
> \
> > -                     urlinstall.c net.c urls.c telnet.c telnetd.c
> > +                     urlinstall.c net.c urls.c telnet.c telnetd.c
> \
> > +		     cpio.c rpmextract.c
> >
> > init_CFLAGS        = $(COMMON_CFLAGS)
> > init_SOURCES       = init.c undomounts.c shutdown.c copy.c
> > diff --git a/loader/cpio.c b/loader/cpio.c
> > new file mode 100644
> > index 0000000..36335fc
> > --- /dev/null
> > +++ b/loader/cpio.c
> > @@ -0,0 +1,192 @@
> > +/** \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 <string.h>
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <errno.h>
> > +
> > +#include <rpm/rpmio.h>
> > +#include <rpm/rpmlog.h>
> > +#include <rpm/header.h>
> > +
> > +#include "cpio.h"
> > +
> > +
> > +const char * headerGetString(Header h, rpmTag tag)
> > +{
> > +    const char *res = NULL;
> > +    struct rpmtd_s td;
> > +
> > +    if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
> > +        if (rpmtdCount(&td) == 1) {
> > +            res = rpmtdGetString(&td);
> > +        }
> > +        rpmtdFreeData(&td);
> > +    }
> > +    return res;
> > +}
> > +
> > +/**
> > + * 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 cpioReadFileHdr(FD_t fd, struct stat * st, char** name)
> > +{
> > +    struct cpioCrcPhysicalHeader hdr;
> > +    int nameSize;
> > +    char * end;
> > +    unsigned int major, minor;
> > +    int rc = 0;
> > +    char paddingBuffer[4];
> > +
> > +    rc = Fread(&hdr, PHYS_HDR_SIZE, 1, fd);
> > +    if(rc!=1) return CPIOERR_BAD_HEADER;
> > +
> > +    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;
> > +
> > +    long padding = (nameSize+PHYS_HDR_SIZE)%4;
> > +    if(padding>0) padding = 4-padding;
> > +
> > +    {   char * t = malloc(nameSize + 1);
> > +        rc = Fread(t, nameSize, 1, fd);
> > +        if (rc != 1) {
> > +            free(t);
> > +            return CPIOERR_BAD_HEADER;
> > +        }
> > +        t[nameSize] = '\0';
> > +        *name = t;
> > +    }
> > +
> > +    if(padding){
> > +      rc = Fread(paddingBuffer, padding, 1, fd);
> > +      if (rc != 1) {
> > +        free(*name);
> > +        return CPIOERR_BAD_HEADER;
> > +      }
> > +    }
> > +
> > +    return (st->st_ino == 0 && st->st_size == 0 && st->st_mode ==
> 0)?CPIOERR_HDR_TRAILER: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;
> > +}
> > diff --git a/loader/cpio.h b/loader/cpio.h
> > new file mode 100644
> > index 0000000..7e70cce
> > --- /dev/null
> > +++ b/loader/cpio.h
> > @@ -0,0 +1,116 @@
> > +#ifndef H_CPIO
> > +#define H_CPIO
> > +
> > +/** \ingroup payload
> > + * \file lib/cpio.h
> > + *  Structures used to handle cpio payloads within rpm packages.
> > + *
> > + *  @warning Rpm's cpio implementation may be different than
> standard cpio.
> > + *  The implementation is pretty close, but it has some behaviors
> which are
> > + *  more to RPM's liking. I tried to document the differing
> behavior in cpio.c,
> > + *  but I may have missed some (ewt).
> > + *
> > + */
> > +
> > +/** \ingroup payload
> > + * @note CPIO_CHECK_ERRNO bit is set only if errno is valid.
> > + */
> > +#define CPIOERR_CHECK_ERRNO	0x00008000
> > +
> > +/** \ingroup payload
> > + */
> > +enum cpioErrorReturns {
> > +        CPIOERR_BAD_MAGIC       = 2,
> > +        CPIOERR_BAD_HEADER      = 3,
> > +        CPIOERR_OPEN_FAILED     = 4     | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_CHMOD_FAILED    = 5     | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_CHOWN_FAILED    = 6     | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_WRITE_FAILED    = 7     | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_UTIME_FAILED    = 8     | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_UNLINK_FAILED   = 9     | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_RENAME_FAILED   = 10    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_SYMLINK_FAILED  = 11    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_STAT_FAILED     = 12    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_LSTAT_FAILED    = 13    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_MKDIR_FAILED    = 14    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_RMDIR_FAILED    = 15    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_MKNOD_FAILED    = 16    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_MKFIFO_FAILED   = 17    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_LINK_FAILED     = 18    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_READLINK_FAILED = 19    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_READ_FAILED     = 20    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_COPY_FAILED     = 21    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_LSETFCON_FAILED = 22    | CPIOERR_CHECK_ERRNO,
> > +        CPIOERR_HDR_SIZE        = 23,
> > +        CPIOERR_HDR_TRAILER     = 24,
> > +        CPIOERR_UNKNOWN_FILETYPE= 25,
> > +        CPIOERR_MISSING_HARDLINK= 26,
> > +        CPIOERR_DIGEST_MISMATCH = 27,
> > +        CPIOERR_INTERNAL        = 28,
> > +        CPIOERR_UNMAPPED_FILE   = 29,
> > +        CPIOERR_ENOENT          = 30,
> > +        CPIOERR_ENOTEMPTY       = 31,
> > +        CPIOERR_SETCAP_FAILED   = 32    | CPIOERR_CHECK_ERRNO,
> > +};
> > +
> > +/*
> > + * Size limit for individual files in "new ascii format" cpio
> archives.
> > + * The max size of the entire archive is unlimited from cpio POV,
> > + * but subject to filesystem limitations.
> > + */
> > +#define CPIO_FILESIZE_MAX UINT32_MAX
> > +
> > +#define CPIO_NEWC_MAGIC "070701"
> > +#define CPIO_CRC_MAGIC  "070702"
> > +#define CPIO_TRAILER    "TRAILER!!!"
> > +
> > +/** \ingroup payload
> > + * Cpio archive header information.
> > + */
> > +struct cpioCrcPhysicalHeader {
> > +    char magic[6];
> > +    char inode[8];
> > +    char mode[8];
> > +    char uid[8];
> > +    char gid[8];
> > +    char nlink[8];
> > +    char mtime[8];
> > +    char filesize[8];
> > +    char devMajor[8];
> > +    char devMinor[8];
> > +    char rdevMajor[8];
> > +    char rdevMinor[8];
> > +    char namesize[8];
> > +    char checksum[8];                   /* ignored !! */
> > +};
> > +
> > +#define PHYS_HDR_SIZE   110             /* Don't depend on
> sizeof(struct) */
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +const char * headerGetString(Header h, rpmTag tag);
> > +
> > +/**
> > + * Read cpio header.
> > + * @retval fsm          file path and stat info
> > + * @retval st
> > + * @return              0 on success
> > + */
> > +RPM_GNUC_INTERNAL
> > +int cpioReadFileHdr(FD_t fd, struct stat * st, char** name);
> > +
> > +/** \ingroup payload
> > + * Return formatted error message on payload handling failure.
> > + * @param rc            error code
> > + * @return              formatted error string
> > + */
> > +/* XXX should be RPM_GNUC_INTERNAL too but build/pack.c uses */
> > +const char * cpioStrerror(int rc);
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif  /* H_CPIO */
> > diff --git a/loader/rpmextract.c b/loader/rpmextract.c
> > new file mode 100644
> > index 0000000..ca741ad
> > --- /dev/null
> > +++ b/loader/rpmextract.c
> > @@ -0,0 +1,227 @@
> > +/* rpm2dir: unpack the payload of RPM package to the current
> directory*/
> > +/* Based on rpm2cpio */
> > +
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +
> > +#include <rpm/rpmlib.h>		/* rpmReadPackageFile .. */
> > +#include <rpm/rpmtag.h>
> > +#include <rpm/rpmio.h>
> > +#include <rpm/rpmpgp.h>
> > +
> > +#include <rpm/rpmts.h>
> > +
> > +#include <stdio.h>
> > +
> > +#include "cpio.h"
> > +#include "rpmextract.h"
> > +
> > +/*
> > + * explode source RPM into the current directory
> > + * use filters to skip packages and files we do not need
> > + */
> > +int explodeRPM(const char *source,
> > +               filterfunc filter,
> > +               dependencyfunc provides,
> > +               dependencyfunc deps,
> > +               void* userptr)
> > +{
> > +    char buffer[BUFFERSIZE+1]; /* make space for trailing \0 */
> > +    FD_t fdi;
> > +    Header h;
> > +    char * rpmio_flags = NULL;
> > +    rpmRC rc;
> > +    FD_t gzdi;
> > +
> > +    if (strcmp(source, "-") == 0)
> > +        fdi = fdDup(STDIN_FILENO);
> > +    else
> > +        fdi = Fopen(source, "r.ufdio");
> > +
> > +    if (Ferror(fdi)) {
> > +        logMessage(ERROR, "%s: %s\n", (strcmp(source, "-") == 0 ?
> "<stdin>" : source), Fstrerror(fdi));
> > +        return EXIT_FAILURE;
> > +    }
> > +    rpmReadConfigFiles(NULL, NULL);
> > +
> > +    {   rpmts ts = rpmtsCreate();
> > +        rpmVSFlags vsflags = 0;
> > +
> > +        /* XXX retain the ageless behavior of rpm2cpio */
> > +        vsflags |= _RPMVSF_NODIGESTS;
> > +        vsflags |= _RPMVSF_NOSIGNATURES;
> > +        vsflags |= RPMVSF_NOHDRCHK;
> > +        (void) rpmtsSetVSFlags(ts, vsflags);
> > +
> > +        rc = rpmReadPackageFile(ts, fdi, "rpm2dir", &h);
> > +
> > +        ts = rpmtsFree(ts);
> > +    }
> > +
> > +    switch (rc) {
> > +    case RPMRC_OK:
> > +    case RPMRC_NOKEY:
> > +    case RPMRC_NOTTRUSTED:
> > +        break;
> > +    case RPMRC_NOTFOUND:
> > +        logMessage(ERROR, "argument is not an RPM package\n");
> > +        return EXIT_FAILURE;
> > +        break;
> > +    case RPMRC_FAIL:
> > +    default:
> > +        logMessage(ERROR, "error reading header from package\n");
> > +        return EXIT_FAILURE;
> > +        break;
> > +    }
> > +
> > +    /* Retrieve all dependencies and run them through deps function
> */
> > +    while(deps){
> > +        struct rpmtd_s td;
> > +        const char *depname;
> > +
> > +        if (!headerGet(h, RPMTAG_REQUIRENAME, &td,
> HEADERGET_MINMEM))
> > +          break;
> > +
> > +        /* iterator */
> > +        while ((depname = rpmtdNextString(&td))) {
> > +          if(deps(depname, userptr)){
> > +            Fclose(fdi);
> > +            return EXIT_BADDEPS;
> > +          }
> > +        }
> > +        rpmtdFreeData(&td);
> > +        break;
> > +    }
> > +
> > +    /* Retrieve all provides and run them through provides function
> */
> > +    while(provides){
> > +        struct rpmtd_s td;
> > +        const char *depname;
> > +        int found = 0;
> > +
> > +        if (!headerGet(h, RPMTAG_PROVIDES, &td, HEADERGET_MINMEM))
> > +          break;
> > +
> > +        /* iterator */
> > +        while ((depname = rpmtdNextString(&td))) {
> > +          if(!provides(depname, userptr)){
> > +            found++;
> > +          }
> > +        }
> > +        rpmtdFreeData(&td);
> > +        if(found<=0)
> > +            return EXIT_BADDEPS;
> > +        break;
> > +    }
> > +
> > +    /* Retrieve type of payload compression. */
> > +    {
> > +        const char *compr = headerGetString(h,
> RPMTAG_PAYLOADCOMPRESSOR);
> > +        if(compr && strcmp(compr, "gzip")) rpmio_flags =
> rstrscat(NULL, "r.", compr, "dio", NULL);
> > +        else rpmio_flags = rstrscat(NULL, "r.", "gzdio", NULL);
> > +    }
> > +
> > +    gzdi = Fdopen(fdi, rpmio_flags);    /* XXX gzdi == fdi */
> > +    free(rpmio_flags);
> > +
> > +    if (gzdi == NULL) {
> > +        logMessage(ERROR, "cannot re-open payload: %s\n",
> Fstrerror(gzdi));
> > +        return EXIT_FAILURE;
> > +    }
> > +
> > +    while(!rc){
> > +      char *filename = NULL;
> > +      struct stat fstat;
> > +      int offset = 0;
> > +      int towrite = 1;
> > +
> > +      rc = cpioReadFileHdr(gzdi, &fstat, &filename);
> > +      if(rc == CPIOERR_HDR_TRAILER){
> > +        rc = 0;
> > +        break;
> > +      } else if(rc != 0){
> > +        break;
> > +      }
> > +
> > +      /* Strip leading slashes */
> > +      while(filename[offset] == '/') offset+=1;
> > +      /* Strip leading ./ */
> > +      while(filename[offset] == '.' && filename[offset+1] == '/')
> offset+=2;
> > +
> > +      /* Other file type - we do not care except special cases */
> > +      if(!S_ISREG(fstat.st_mode)) towrite = 1;
> > +      else towrite = 2;
> > +
> > +      if(filter && filter(filename+offset, &fstat, userptr)){
> > +        /* filter this file */
> > +        towrite = 0;
> > +      }
> > +
> > +      /* Create directories */
> > +      char* dirname = strdup(filename+offset);
> > +      char* dirptr = dirname;
> > +      while(dirptr!=NULL && *dirptr!=0){
> > +        dirptr = strchr(dirptr, '/');
> > +        if(dirptr){
> > +          *dirptr = 0;
> > +          mkdir(dirname, 0700);
> > +          *dirptr = '/';
> > +          dirptr++;
> > +        }
> > +      }
> > +      free(dirname);
> > +
> > +      /* Regular file */
> > +      long readbytes = 0;
> > +      long padding = fstat.st_size%4;
> > +      FILE *fdout = NULL;
> > +      if(padding>0) padding = 4-padding;
> > +
> > +      if(towrite>=2){
> > +        fdout = fopen(filename+offset, "w");
> > +
> > +        if(fdout==NULL){
> > +          free(filename);
> > +          rc = 33;
> > +          break;
> > +        }
> > +      }
> > +
> > +      while(1){
> > +        long toread = (BUFFERSIZE>fstat.st_size) ? fstat.st_size :
> BUFFERSIZE;
> > +        if(toread<=0) break;
> > +        readbytes = Fread(buffer, toread, 1, gzdi);
> > +        if(readbytes<=0){
> > +          rc = 34; //truncated archive? set error flag...
> > +          break;
> > +        }
> > +        else{
> > +          fstat.st_size-=toread;
> > +          if(towrite>=2)
> > +            if(fwrite(buffer, toread, 1, fdout)!=1){
> > +              /* TODO: error handling */
> > +            }
> > +          buffer[toread] = 0;
> > +        }
> > +      }
> > +
> > +      /* symlink, we assume that the path comtained in symlink
> > +       * is shorter than BUFFERSIZE */
> > +      if(towrite && !rc && S_ISLNK(fstat.st_mode)){
> > +        if(symlink(buffer, filename+offset)){
> > +          /* TODO: error handling */
> > +        }
> > +      }
> > +
> > +      free(filename);
> > +      if(towrite>=2) fclose(fdout);
> > +
> > +      if(padding) readbytes = Fread(buffer, padding, 1, gzdi);
> > +    }
> > +
> > +
> > +    Fclose(gzdi);       /* XXX gzdi == fdi */
> > +
> > +    return rc;
> > +}
> > diff --git a/loader/rpmextract.h b/loader/rpmextract.h
> > new file mode 100644
> > index 0000000..0348b49
> > --- /dev/null
> > +++ b/loader/rpmextract.h
> > @@ -0,0 +1,47 @@
> > +/*
> > +   File name: rpmextract.h
> > +   Date:      2009/09/16
> > +   Author:    msivak
> > +
> > +   Copyright (C) 2009 msivak
> > +
> > +   This program is free software; you can redistribute it and/or
> > +   modify it under the terms of the GNU General Public License as
> > +   published by the Free Software Foundation; either version 2 of
> the
> > +   License, or (at your option) any later version.
> > +
> > +   This program is distributed in the hope that it will be useful,
> but
> > +   WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU
> > +   General Public License for more details.
> > +
> > +   You should have received a copy of the GNU General Public
> License
> > +   in a file called COPYING along with this program; if not, write
> to
> > +   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
> > +   02139, USA.
> > +*/
> > +
> > +
> > +#ifndef __RPMEXTRACT_H__
> > +#define __RPMEXTRACT_H__
> > +
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <unistd.h>
> > +
> > +#define EXIT_BADDEPS 4
> > +#define BUFFERSIZE 1024
> > +
> > +/* both filter functions return 0 - match, 1 - match not found */
> > +typedef int (*filterfunc)(const char* name, struct stat *fstat,
> void *userptr);
> > +typedef int (*dependencyfunc)(const char* depends, void *userptr);
> > +
> > +int explodeRPM(const char* file,
> > +               filterfunc filter,
> > +               dependencyfunc provides,
> > +               dependencyfunc deps,
> > +               void* userptr);
> > +
> > +#endif
> > +
> > +/* end of rpmextract.h */
> >
> 
> - -- 
> David Cantrell <dcantrell@xxxxxxxxxx>
> Red Hat / Honolulu, HI
> 
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.10 (GNU/Linux)
> 
> iEYEARECAAYFAksdaRUACgkQ5hsjjIy1VklgDQCfeTayd0si2ANwyBLxISFRYcnz
> XHsAoOZvHPkRvljRkB/jlB9EOhaQmc9H
> =lCuD
> -----END PGP SIGNATURE-----
> 
> _______________________________________________
> Anaconda-devel-list mailing list
> Anaconda-devel-list@xxxxxxxxxx
> https://www.redhat.com/mailman/listinfo/anaconda-devel-list

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux