static int getNEVRA(Header h, rpmtd td, nevraFlags flags) { const char *val = NULL; char *res = NULL; if ((flags & NEVRA_NAME)) { val = headerGetString(h, RPMTAG_NAME); if (val) rstrscat(&res, val, "-", NULL); } if ((flags & NEVRA_EPOCH)) { char *e = headerGetAsString(h, RPMTAG_EPOCH); if (e) rstrscat(&res, e, ":", NULL); free(e); } if ((flags & NEVRA_VERSION)) { val = headerGetString(h, RPMTAG_VERSION); if (val) rstrscat(&res, val, "-", NULL); } if ((flags & NEVRA_RELEASE)) { val = headerGetString(h, RPMTAG_RELEASE); if (val) rstrscat(&res, val, NULL); } if ((flags & NEVRA_ARCH)) { val = headerGetString(h, RPMTAG_ARCH); if (headerIsSource(h) && val == NULL) val = "src"; if (val) rstrscat(&res, ".", val, NULL); } td->type = RPM_STRING_TYPE; td->data = res; td->count = 1; td->flags = RPMTD_ALLOCED; return 1; }
/** * Wrap tag data in simple header xml markup. * @param td tag data container * @return formatted string */ static char * xmlFormat(rpmtd td) { const char *xtag = NULL; char *val = NULL; char *s = NULL; rpmtdFormats fmt = RPMTD_FORMAT_STRING; switch (rpmtdClass(td)) { case RPM_STRING_CLASS: xtag = "string"; break; case RPM_BINARY_CLASS: fmt = RPMTD_FORMAT_BASE64; xtag = "base64"; break; case RPM_NUMERIC_CLASS: xtag = "integer"; break; case RPM_NULL_TYPE: default: return xstrdup(_("(invalid xml type)")); break; } /* XXX TODO: handle errors */ s = rpmtdFormat(td, fmt, NULL); if (s[0] == '\0') { val = rstrscat(NULL, "\t<", xtag, "/>", NULL); } else { char *new_s = NULL; size_t i, s_size = strlen(s); for (i=0; i<s_size; i++) { switch (s[i]) { case '<': rstrcat(&new_s, "<"); break; case '>': rstrcat(&new_s, ">"); break; case '&': rstrcat(&new_s, "&"); break; default: { char c[2] = " "; *c = s[i]; rstrcat(&new_s, c); break; } } } val = rstrscat(NULL, "\t<", xtag, ">", new_s, "</", xtag, ">", NULL); free(new_s); } free(s); return val; }
/* * Attempt to generate libmagic-style file class if missing from header: * we can easily generate this for symlinks and other special types. * Always return malloced strings to simplify life in fileclassTag(). */ static char *makeFClass(rpmfi fi) { char *fclass = NULL; const char *hc = rpmfiFClass(fi); if (hc != NULL && hc[0] != '\0') { fclass = xstrdup(hc); } else { switch (rpmfiFMode(fi) & S_IFMT) { case S_IFBLK: fclass = xstrdup("block special"); break; case S_IFCHR: fclass = xstrdup("character special"); break; case S_IFDIR: fclass = xstrdup("directory"); break; case S_IFIFO: fclass = xstrdup("fifo (named pipe)"); break; case S_IFSOCK: fclass = xstrdup("socket"); break; case S_IFLNK: fclass = rstrscat(NULL, "symbolic link to `", rpmfiFLink(fi), "'", NULL); break; } } return (fclass != NULL) ? fclass : xstrdup(""); }
/* * Try to acquire db environment open/close serialization lock. * Return the open, locked fd on success, -1 on failure. */ static int serialize_env(const char *dbhome) { char *lock_path = rstrscat(NULL, dbhome, "/.dbenv.lock", NULL); mode_t oldmask = umask(022); int fd = open(lock_path, (O_RDWR|O_CREAT), 0644); umask(oldmask); if (fd >= 0) { int rc; struct flock info; memset(&info, 0, sizeof(info)); info.l_type = F_WRLCK; info.l_whence = SEEK_SET; do { rc = fcntl(fd, F_SETLKW, &info); } while (rc == -1 && errno == EINTR); if (rc == -1) { close(fd); fd = -1; } } free(lock_path); return fd; }
const char * Fdescr(FD_t fd) { if (fd == NULL) return _("[none]"); /* Lazy lookup if description is not set (eg dupped fd) */ if (fd->descr == NULL) { int fdno = fd->fps->fdno; #if defined(__linux__) /* Grab the path from /proc if we can */ char *procpath = NULL; char buf[PATH_MAX]; ssize_t llen; rasprintf(&procpath, "/proc/self/fd/%d", fdno); llen = readlink(procpath, buf, sizeof(buf)-1); free(procpath); if (llen >= 1) { buf[llen] = '\0'; /* Real paths in /proc are always absolute */ if (buf[0] == '/') fd->descr = xstrdup(buf); else fd->descr = rstrscat(NULL, "[", buf, "]", NULL); } #endif /* Still no description, base it on fdno which is always there */ if (fd->descr == NULL) rasprintf(&(fd->descr), "[fd %d]", fdno); } return fd->descr; }
static rpmPlugin rpmPluginNew(const char *name, const char *path, const char *opts) { rpmPlugin plugin = NULL; rpmPluginHooks hooks = NULL; char *error; char *hooks_name = NULL; void *handle = dlopen(path, RTLD_LAZY); if (!handle) { rpmlog(RPMLOG_ERR, _("Failed to dlopen %s %s\n"), path, dlerror()); return NULL; } /* make sure the plugin has the supported hooks flag */ hooks_name = rstrscat(NULL, name, "_hooks", NULL); hooks = dlsym(handle, hooks_name); if ((error = dlerror()) != NULL) { rpmlog(RPMLOG_ERR, _("Failed to resolve symbol %s: %s\n"), hooks_name, error); } else { plugin = xcalloc(1, sizeof(*plugin)); plugin->name = xstrdup(name); plugin->handle = handle; plugin->hooks = hooks; if (opts) plugin->opts = xstrdup(opts); } free(hooks_name); return plugin; }
char * rpmfiFNIndex(rpmfi fi, int ix) { char *fn = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { fn = rstrscat(NULL, fi->dnl[fi->dil[ix]], fi->bnl[ix], NULL); } return fn; }
char * rpmfiFNIndex(rpmfi fi, int ix) { char *fn = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { fn = rstrscat(NULL, rpmstrPoolStr(fi->pool, fi->dnid[fi->dil[ix]]), rpmstrPoolStr(fi->pool, fi->bnid[ix]), NULL); } return fn; }
static int rpmfd_init(rpmfdObject *s, PyObject *args, PyObject *kwds) { char *kwlist[] = { "obj", "mode", "flags", NULL }; const char *mode = "r"; const char *flags = "ufdio"; char *rpmio_mode = NULL; PyObject *fo = NULL; FD_t fd = NULL; int fdno; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ss", kwlist, &fo, &mode, &flags)) return -1; rpmio_mode = rstrscat(NULL, mode, ".", flags, NULL); if (PyBytes_Check(fo)) { fd = openPath(PyBytes_AsString(fo), rpmio_mode); } else if (PyUnicode_Check(fo)) { PyObject *enc = NULL; int rc; #if PY_MAJOR_VERSION >= 3 rc = PyUnicode_FSConverter(fo, &enc); #else rc = utf8FromPyObject(fo, &enc); #endif if (rc) { fd = openPath(PyBytes_AsString(enc), rpmio_mode); Py_DECREF(enc); } } else if (rpmfdObject_Check(fo)) { rpmfdObject *fdo = (rpmfdObject *)fo; fd = openFd(fdDup(Fileno(fdo->fd)), rpmio_mode); } else if ((fdno = PyObject_AsFileDescriptor(fo)) >= 0) { fd = openFd(fdDup(fdno), rpmio_mode); } else { PyErr_SetString(PyExc_TypeError, "path or file object expected"); } if (fd != NULL) { Fclose(s->fd); /* in case __init__ was called again */ free(s->mode); free(s->flags); s->fd = fd; s->mode = rstrdup(mode); s->flags = rstrdup(flags); } else { PyErr_SetString(PyExc_IOError, Fstrerror(fd)); } free(rpmio_mode); return (fd == NULL) ? -1 : 0; }
static void dbDetectBackend(rpmdb rdb) { #ifdef ENABLE_NDB const char *dbhome = rpmdbHome(rdb); char *path = rstrscat(NULL, dbhome, "/Packages", NULL); rdb->db_ops = &ndb_dbops; if (access(path, F_OK) == 0) rdb->db_ops = &db3_dbops; free(path); #else rdb->db_ops = &db3_dbops; #endif }
/** * Generate GPG signature(s) for a header+payload file. * @param sigh signature header * @param ishdr header-only signature? * @param sigt signature target * @param passPhrase private key pass phrase * @return generated sigtag on success, 0 on failure */ static rpmtd makeGPGSignature(Header sigh, int ishdr, sigTarget sigt) { char * sigfile = rstrscat(NULL, sigt->fileName, ".sig", NULL); struct stat st; uint8_t * pkt = NULL; size_t pktlen = 0; rpmtd sigtd = NULL; if (runGPG(sigt, sigfile)) goto exit; if (stat(sigfile, &st)) { /* GPG failed to write signature */ rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n")); goto exit; } pktlen = st.st_size; rpmlog(RPMLOG_DEBUG, "GPG sig size: %zd\n", pktlen); pkt = xmalloc(pktlen); { FD_t fd; int rc = 0; fd = Fopen(sigfile, "r.ufdio"); if (fd != NULL && !Ferror(fd)) { rc = Fread(pkt, sizeof(*pkt), pktlen, fd); (void) Fclose(fd); } if (rc != pktlen) { rpmlog(RPMLOG_ERR, _("unable to read the signature\n")); goto exit; } } rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", pktlen); /* Parse the signature, change signature tag as appropriate. */ sigtd = makeSigTag(sigh, ishdr, pkt, pktlen); exit: (void) unlink(sigfile); free(sigfile); free(pkt); return sigtd; }
static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi) { archive_entry_clear(entry); char * filename = rstrscat(NULL, ".", rpmfiDN(fi), rpmfiBN(fi), NULL); archive_entry_copy_pathname(entry, filename); _free(filename); archive_entry_set_size(entry, rpmfiFSize(fi)); rpm_mode_t mode = rpmfiFMode(fi); archive_entry_set_filetype(entry, mode & S_IFMT); archive_entry_set_perm(entry, mode); archive_entry_set_uname(entry, rpmfiFUser(fi)); archive_entry_set_gname(entry, rpmfiFGroup(fi)); archive_entry_set_rdev(entry, rpmfiFRdev(fi)); archive_entry_set_mtime(entry, rpmfiFMtime(fi), 0); if (S_ISLNK(mode)) archive_entry_set_symlink(entry, rpmfiFLink(fi)); }
static int fsmRename(const char *opath, const char *path) { removeSBITS(path); int rc = rename(opath, path); #if defined(ETXTBSY) && defined(__HPUX__) /* XXX HP-UX (and other os'es) don't permit rename to busy files. */ if (rc && errno == ETXTBSY) { char *rmpath = NULL; rstrscat(&rmpath, path, "-RPMDELETE", NULL); rc = rename(path, rmpath); if (!rc) rc = rename(opath, path); free(rmpath); } #endif if (_fsm_debug) rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, opath, path, (rc < 0 ? strerror(errno) : "")); if (rc < 0) rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED); return rc; }
/* * Format sigcheck result for output, appending the message spew to buf and * bad/missing keyids to keyprob. * * In verbose mode, just dump it all. Otherwise ok signatures * are dumped lowercase, bad sigs uppercase and for PGP/GPG * if misssing/untrusted key it's uppercase in parenthesis * and stash the key id as <SIGTYPE>#<keyid>. Pfft. */ static void formatResult(rpmTagVal sigtag, rpmRC sigres, const char *result, char **keyprob, char **buf) { char *msg = NULL; if (rpmIsVerbose()) { rasprintf(&msg, " %s\n", result); } else { /* Check for missing / untrusted keys in result. */ const char *signame = sigtagname(sigtag, (sigres != RPMRC_OK)); if (sigres == RPMRC_NOKEY || sigres == RPMRC_NOTTRUSTED) { const char *tempKey = strstr(result, "ey ID"); if (tempKey) { char keyid[sizeof(pgpKeyID_t) + 1]; rstrlcpy(keyid, tempKey + 6, sizeof(keyid)); rstrscat(keyprob, " ", signame, "#", keyid, NULL); } } rasprintf(&msg, (*keyprob ? "(%s) " : "%s "), signame); } rstrcat(buf, msg); free(msg); }
int main(int argc, char *argv[]) { FD_t fdi, fdo; Header h; char * rpmio_flags = NULL; rpmRC rc; FD_t gzdi; setprogname(argv[0]); /* Retrofit glibc __progname */ rpmReadConfigFiles(NULL, NULL); if (argc == 1) fdi = fdDup(STDIN_FILENO); else { if (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")) { fprintf(stderr, "Usage: rpm2cpio file.rpm\n"); exit(EXIT_FAILURE); } fdi = Fopen(argv[1], "r.ufdio"); } if (Ferror(fdi)) { fprintf(stderr, "%s: %s: %s\n", argv[0], (argc == 1 ? "<stdin>" : argv[1]), Fstrerror(fdi)); exit(EXIT_FAILURE); } fdo = fdDup(STDOUT_FILENO); { 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, "rpm2cpio", &h); ts = rpmtsFree(ts); } switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: fprintf(stderr, _("argument is not an RPM package\n")); exit(EXIT_FAILURE); break; case RPMRC_FAIL: default: fprintf(stderr, _("error reading header from package\n")); exit(EXIT_FAILURE); break; } /* Retrieve type of payload compression. */ { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); } gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ free(rpmio_flags); if (gzdi == NULL) { fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); exit(EXIT_FAILURE); } rc = ufdCopy(gzdi, fdo); rc = (rc <= 0) ? EXIT_FAILURE : EXIT_SUCCESS; Fclose(fdo); Fclose(gzdi); /* XXX gzdi == fdi */ return rc; }
void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, rpmfs fs, Header h) { char ** baseNames; char ** dirNames; uint32_t * dirIndexes; rpm_count_t fileCount, dirCount; int nrelocated = 0; int fileAlloced = 0; char * fn = NULL; int haveRelocatedBase = 0; size_t maxlen = 0; int i, j; struct rpmtd_s bnames, dnames, dindexes, fmodes; if (!addPrefixes(h, relocations, numRelocations)) return; if (rpmIsDebug()) { rpmlog(RPMLOG_DEBUG, "========== relocations\n"); for (i = 0; i < numRelocations; i++) { if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */ if (relocations[i].newPath == NULL) rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n", i, relocations[i].oldPath); else rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n", i, relocations[i].oldPath, relocations[i].newPath); } } for (i = 0; i < numRelocations; i++) { if (relocations[i].newPath == NULL) continue; size_t len = strlen(relocations[i].newPath); if (len > maxlen) maxlen = len; } headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, HEADERGET_ALLOC); headerGet(h, RPMTAG_DIRNAMES, &dnames, HEADERGET_MINMEM); headerGet(h, RPMTAG_FILEMODES, &fmodes, HEADERGET_MINMEM); /* TODO XXX ugh.. use rpmtd iterators & friends instead */ baseNames = bnames.data; dirIndexes = dindexes.data; fileCount = rpmtdCount(&bnames); dirCount = rpmtdCount(&dnames); /* XXX TODO: use rpmtdDup() instead */ dirNames = dnames.data = duparray(dnames.data, dirCount); dnames.flags |= RPMTD_PTR_ALLOCED; /* * For all relocations, we go through sorted file/relocation lists * backwards so that /usr/local relocations take precedence over /usr * ones. */ /* Relocate individual paths. */ for (i = fileCount - 1; i >= 0; i--) { rpmFileTypes ft; int fnlen; size_t len = maxlen + strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1; if (len >= fileAlloced) { fileAlloced = len * 2; fn = xrealloc(fn, fileAlloced); } assert(fn != NULL); /* XXX can't happen */ *fn = '\0'; fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn; /* * See if this file path needs relocating. */ /* * XXX FIXME: Would a bsearch of the (already sorted) * relocation list be a good idea? */ for (j = numRelocations - 1; j >= 0; j--) { if (relocations[j].oldPath == NULL) /* XXX can't happen */ continue; len = !rstreq(relocations[j].oldPath, "/") ? strlen(relocations[j].oldPath) : 0; if (fnlen < len) continue; /* * Only subdirectories or complete file paths may be relocated. We * don't check for '\0' as our directory names all end in '/'. */ if (!(fn[len] == '/' || fnlen == len)) continue; if (!rstreqn(relocations[j].oldPath, fn, len)) continue; break; } if (j < 0) continue; rpmtdSetIndex(&fmodes, i); ft = rpmfiWhatis(rpmtdGetNumber(&fmodes)); /* On install, a relocate to NULL means skip the path. */ if (relocations[j].newPath == NULL) { if (ft == XDIR) { /* Start with the parent, looking for directory to exclude. */ for (j = dirIndexes[i]; j < dirCount; j++) { len = strlen(dirNames[j]) - 1; while (len > 0 && dirNames[j][len-1] == '/') len--; if (fnlen != len) continue; if (!rstreqn(fn, dirNames[j], fnlen)) continue; break; } } rpmfsSetAction(fs, i, FA_SKIPNSTATE); rpmlog(RPMLOG_DEBUG, "excluding %s %s\n", ftstring(ft), fn); continue; } /* Relocation on full paths only, please. */ if (fnlen != len) continue; rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n", fn, relocations[j].newPath); nrelocated++; strcpy(fn, relocations[j].newPath); { char * te = strrchr(fn, '/'); if (te) { if (te > fn) te++; /* root is special */ fnlen = te - fn; } else te = fn + strlen(fn); if (!rstreq(baseNames[i], te)) { /* basename changed too? */ if (!haveRelocatedBase) { /* XXX TODO: use rpmtdDup() instead */ bnames.data = baseNames = duparray(baseNames, fileCount); bnames.flags |= RPMTD_PTR_ALLOCED; haveRelocatedBase = 1; } free(baseNames[i]); baseNames[i] = xstrdup(te); } *te = '\0'; /* terminate new directory name */ } /* Does this directory already exist in the directory list? */ for (j = 0; j < dirCount; j++) { if (fnlen != strlen(dirNames[j])) continue; if (!rstreqn(fn, dirNames[j], fnlen)) continue; break; } if (j < dirCount) { dirIndexes[i] = j; continue; } /* Creating new paths is a pita */ dirNames = dnames.data = xrealloc(dnames.data, sizeof(*dirNames) * (dirCount + 1)); dirNames[dirCount] = xstrdup(fn); dirIndexes[i] = dirCount; dirCount++; dnames.count++; } /* Finish off by relocating directories. */ for (i = dirCount - 1; i >= 0; i--) { for (j = numRelocations - 1; j >= 0; j--) { if (relocations[j].oldPath == NULL) /* XXX can't happen */ continue; size_t len = !rstreq(relocations[j].oldPath, "/") ? strlen(relocations[j].oldPath) : 0; if (len && !rstreqn(relocations[j].oldPath, dirNames[i], len)) continue; /* * Only subdirectories or complete file paths may be relocated. We * don't check for '\0' as our directory names all end in '/'. */ if (dirNames[i][len] != '/') continue; if (relocations[j].newPath) { /* Relocate the path */ char *t = NULL; rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL); /* Unfortunately rpmCleanPath strips the trailing slash.. */ (void) rpmCleanPath(t); rstrcat(&t, "/"); rpmlog(RPMLOG_DEBUG, "relocating directory %s to %s\n", dirNames[i], t); free(dirNames[i]); dirNames[i] = t; nrelocated++; } } } /* Save original filenames in header and replace (relocated) filenames. */ if (nrelocated) { saveOrig(h); headerMod(h, &bnames); headerMod(h, &dnames); headerMod(h, &dindexes); } rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); rpmtdFreeData(&fmodes); free(fn); }
/* Check file for to be installed symlinks in their path and correct their fp */ static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, int filenr) { rpmfiles fi = rpmteFiles(p); struct fingerPrint_s current_fp; const char *currentsubdir; size_t lensubDir, bnStart, bnEnd; struct rpmffi_s * recs; int numRecs; int i; fingerPrint *fp = rpmfilesFps(fi) + filenr; int symlinkcount = 0; struct rpmffi_s ffi = { p, filenr}; if (fp->subDirId == 0) { rpmFpHashAddEntry(fpc->fp, fp, ffi); goto exit; } currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId); lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId); current_fp = *fp; /* Set baseName to the upper most dir */ bnStart = bnEnd = 1; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; /* no subDir for now */ current_fp.subDirId = 0; while (bnEnd < lensubDir) { char found = 0; current_fp.baseNameId = rpmstrPoolIdn(fpc->pool, currentsubdir + bnStart, bnEnd - bnStart, 1); rpmFpHashGetEntry(symlinks, ¤t_fp, &recs, &numRecs, NULL); for (i = 0; i < numRecs; i++) { rpmfiles foundfi = rpmteFiles(recs[i].p); char const *linktarget = rpmfilesFLink(foundfi, recs[i].fileno); char *link; /* Ignore already removed (by eg %pretrans) links */ if (linktarget && rpmteType(recs[i].p) == TR_REMOVED) { char *path = rpmfilesFN(foundfi, recs[i].fileno); struct stat sb; if (lstat(path, &sb) == -1) linktarget = NULL; free(path); } foundfi = rpmfilesFree(foundfi); if (linktarget && *linktarget != '\0') { const char *bn; /* this "directory" is a symlink */ link = NULL; if (*linktarget != '/') { const char *dn, *subDir = NULL; dn = rpmstrPoolStr(fpc->pool, current_fp.entry->dirId); if (current_fp.subDirId) { subDir = rpmstrPoolStr(fpc->pool, current_fp.subDirId); } rstrscat(&link, dn, subDir ? subDir : "", "/", NULL); } rstrscat(&link, linktarget, "/", NULL); if (strlen(currentsubdir + bnEnd)) { rstrscat(&link, currentsubdir + bnEnd, NULL); } bn = rpmstrPoolStr(fpc->pool, fp->baseNameId); doLookup(fpc, link, bn, fp); free(link); symlinkcount++; /* setup current_fp for the new path */ found = 1; current_fp = *fp; if (fp->subDirId == 0) { /* directory exists - no need to look for symlinks */ rpmFpHashAddEntry(fpc->fp, fp, ffi); goto exit; } currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId); lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId); /* no subDir for now */ current_fp.subDirId = 0; /* Set baseName to the upper most dir */ bnStart = bnEnd = 1; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; break; } } if (symlinkcount > 50) { // found too many symlinks in the path // most likley a symlink cicle // giving up // TODO warning/error break; } if (found) { continue; // restart loop after symlink } /* Set former baseName as subDir */ bnEnd++; current_fp.subDirId = rpmstrPoolIdn(fpc->pool, currentsubdir, bnEnd, 1); /* set baseName to the next lower dir */ bnStart = bnEnd; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; } rpmFpHashAddEntry(fpc->fp, fp, ffi); exit: rpmfilesFree(fi); }
/** \ingroup payload * Build path to file from file info, optionally ornamented with suffix. * @param fi file info iterator * @param suffix suffix to use (NULL disables) * @retval path to file (malloced) */ static char * fsmFsPath(rpmfi fi, const char * suffix) { return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL); }
static int process_package(rpmts ts, char * filename) { FD_t fdi; FD_t gzdi; Header h; int rc = 0; char * rpmio_flags = NULL; struct archive *a; struct archive_entry *entry; if (!strcmp(filename, "-")) { fdi = fdDup(STDIN_FILENO); } else { fdi = Fopen(filename, "r.ufdio"); } if (Ferror(fdi)) { fprintf(stderr, "rpm2archive: %s: %s\n", filename, Fstrerror(fdi)); exit(EXIT_FAILURE); } rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h); switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: fprintf(stderr, _("argument is not an RPM package\n")); exit(EXIT_FAILURE); break; case RPMRC_FAIL: default: fprintf(stderr, _("error reading header from package\n")); exit(EXIT_FAILURE); break; } /* Retrieve payload size and compression type. */ { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); } gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ free(rpmio_flags); if (gzdi == NULL) { fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); exit(EXIT_FAILURE); } rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); rpmfi fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST); /* create archive */ a = archive_write_new(); archive_write_add_filter_gzip(a); archive_write_set_format_pax_restricted(a); if (!strcmp(filename, "-")) { if (isatty(STDOUT_FILENO)) { fprintf(stderr, "Error: refusing to output archive data to a terminal.\n"); exit(EXIT_FAILURE); } archive_write_open_fd(a, STDOUT_FILENO); } else { char * outname = rstrscat(NULL, filename, ".tgz", NULL); archive_write_open_filename(a, outname); _free(outname); // XXX error handling } entry = archive_entry_new(); char * buf = xmalloc(BUFSIZE); char * hardlink = NULL; rc = 0; while (rc >= 0) { rc = rpmfiNext(fi); if (rc == RPMERR_ITER_END) { break; } rpm_mode_t mode = rpmfiFMode(fi); int nlink = rpmfiFNlink(fi); fill_archive_entry(a, entry, fi); if (nlink > 1) { if (rpmfiArchiveHasContent(fi)) { _free(hardlink); hardlink = rstrscat(NULL, ".", rpmfiFN(fi), NULL); } else { archive_entry_set_hardlink(entry, hardlink); } } archive_write_header(a, entry); if (S_ISREG(mode) && (nlink == 1 || rpmfiArchiveHasContent(fi))) { write_file_content(a, buf, fi); } } /* End of iteration is not an error */ if (rc == RPMERR_ITER_END) { rc = 0; } _free(hardlink); Fclose(gzdi); /* XXX gzdi == fdi */ archive_entry_free(entry); archive_write_close(a); archive_write_free(a); buf = _free(buf); rpmfilesFree(files); rpmfiFree(fi); headerFree(h); return rc; }
/** * Check file info from header against what's actually installed. * @param ts transaction set * @param h header to verify * @param omitMask bits to disable verify checks * @param incAttr skip files without these attrs (eg %ghost) * @param skipAttr skip files with these attrs (eg %ghost) * @return 0 no problems, 1 problems found */ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, rpmfileAttrs incAttrs, rpmfileAttrs skipAttrs) { rpmVerifyAttrs verifyResult = 0; rpmVerifyAttrs verifyAll = 0; /* assume no problems */ rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_FLAGS_VERIFY); if (fi == NULL) return 1; rpmfiInit(fi, 0); while (rpmfiNext(fi) >= 0) { rpmfileAttrs fileAttrs = rpmfiFFlags(fi); char *buf = NULL, *attrFormat; const char *fstate = NULL; char ac; /* If filtering by inclusion, skip non-matching (eg --configfiles) */ if (incAttrs && !(incAttrs & fileAttrs)) continue; /* Skip on attributes (eg from --noghost) */ if (skipAttrs & fileAttrs) continue; verifyResult = rpmfiVerify(fi, omitMask); /* Filter out timestamp differences of shared files */ if (verifyResult & RPMVERIFY_MTIME) { rpmdbMatchIterator mi; mi = rpmtsInitIterator(ts, RPMDBI_BASENAMES, rpmfiFN(fi), 0); if (rpmdbGetIteratorCount(mi) > 1) verifyResult &= ~RPMVERIFY_MTIME; rpmdbFreeIterator(mi); } /* State is only meaningful for installed packages */ if (headerGetInstance(h)) fstate = stateStr(rpmfiFState(fi)); attrFormat = rpmFFlagsString(fileAttrs, ""); ac = rstreq(attrFormat, "") ? ' ' : attrFormat[0]; if (verifyResult & RPMVERIFY_LSTATFAIL) { if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) { rasprintf(&buf, _("missing %c %s"), ac, rpmfiFN(fi)); if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) { char *app; rasprintf(&app, " (%s)", strerror(errno)); rstrcat(&buf, app); free(app); } } } else if (verifyResult || fstate || rpmIsVerbose()) { char *verifyFormat = rpmVerifyString(verifyResult, "."); rasprintf(&buf, "%s %c %s", verifyFormat, ac, rpmfiFN(fi)); free(verifyFormat); } free(attrFormat); if (buf) { if (fstate) buf = rstrscat(&buf, " (", fstate, ")", NULL); rpmlog(RPMLOG_NOTICE, "%s\n", buf); buf = _free(buf); } verifyAll |= verifyResult; } rpmfiFree(fi); return (verifyAll != 0) ? 1 : 0; }