/* * Helper to convert 32bit tag to 64bit version. * If header has new 64bit tag then just return the data, * otherwise convert 32bit old tag data to 64bit values. * For consistency, always return malloced data. */ static int get64(Header h, rpmtd td, rpmTag newtag, rpmTag oldtag) { int rc; if (headerIsEntry(h, newtag)) { rc = headerGet(h, newtag, td, HEADERGET_ALLOC); } else { struct rpmtd_s olddata; uint32_t *d32 = NULL; uint64_t *d64 = NULL; headerGet(h, oldtag, &olddata, HEADERGET_MINMEM); if (rpmtdType(&olddata) == RPM_INT32_TYPE) { td->type = RPM_INT64_TYPE; td->count = olddata.count; td->flags = RPMTD_ALLOCED; td->data = xmalloc(sizeof(*d64) * td->count); d64 = td->data; while ((d32 = rpmtdNextUint32(&olddata))) { *d64++ = *d32; } } rpmtdFreeData(&olddata); rc = d64 ? 1 : 0; } return rc; }
int headerFindSpec(Header h) { struct rpmtd_s filenames; int specix = -1; if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_MINMEM)) { struct rpmtd_s td; const char *str; /* Try to find spec by file flags */ if (headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) { rpmfileAttrs *flags; while (specix < 0 && (flags = rpmtdNextUint32(&td))) { if (*flags & RPMFILE_SPECFILE) specix = rpmtdGetIndex(&td); } rpmtdFreeData(&td); } /* Still no spec? Look by filename. */ while (specix < 0 && (str = rpmtdNextString(&filenames))) { if (rpmFileHasSuffix(str, ".spec")) specix = rpmtdGetIndex(&filenames); } rpmtdFreeData(&filenames); } return specix; }
static int headercolorTag(Header h, rpmtd td, headerGetFlags hgflags) { rpm_color_t *fcolor, hcolor = 0; struct rpmtd_s fcolors; headerGet(h, RPMTAG_FILECOLORS, &fcolors, HEADERGET_MINMEM); while ((fcolor = rpmtdNextUint32(&fcolors)) != NULL) { hcolor |= *fcolor; } rpmtdFreeData(&fcolors); hcolor &= 0x0f; return numberTag(td, hcolor); }
/* validate a indexed tag data triplet (such as file bn/dn/dx) */ static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd) { int sane = 0; uint32_t xc = rpmtdCount(xd); uint32_t yc = rpmtdCount(yd); uint32_t zc = rpmtdCount(zd); /* check that the amount of data in each is sane */ if (xc > 0 && yc > 0 && yc <= xc && zc == xc) { uint32_t * i; /* ...and that the indexes are within bounds */ while ((i = rpmtdNextUint32(zd))) { if (*i >= yc) break; } /* unless the loop runs to finish, the data is broken */ sane = (i == NULL); } return sane; }
static sepol *sepolNew(rpmte te) { sepol *head = NULL; sepol *ret = NULL; sepolAction action; Header h; struct rpmtd_s policies, names, types, typesidx, flags; int i, j; int count; rpmtdReset(&policies); rpmtdReset(&names); rpmtdReset(&types); rpmtdReset(&typesidx); rpmtdReset(&flags); h = rpmteHeader(te); if (!h) { goto exit; } if (!headerIsEntry(h, RPMTAG_POLICIES)) { goto exit; } if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) { goto exit; } count = rpmtdCount(&policies); if (count <= 0) { goto exit; } if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM) || rpmtdCount(&names) != count) { goto exit; } if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM) || rpmtdCount(&flags) != count) { goto exit; } if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) { goto exit; } if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM) || rpmtdCount(&types) != rpmtdCount(&typesidx)) { goto exit; } action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE; for (i = 0; i < count; i++) { sepol *pol = xcalloc(1, sizeof(*pol)); pol->next = head; head = pol; pol->data = xstrdup(rpmtdNextString(&policies)); pol->name = xstrdup(rpmtdNextString(&names)); pol->flags = *rpmtdNextUint32(&flags); pol->action = action; for (j = 0; j < rpmtdCount(&types); j++) { uint32_t index = ((uint32_t *) typesidx.data)[j]; if (index < 0 || index >= count) { goto exit; } if (index != i) { continue; } argvAdd(&pol->types, rpmtdNextString(&types)); } argvSort(pol->types, NULL); } ret = head; exit: headerFree(h); rpmtdFreeData(&policies); rpmtdFreeData(&names); rpmtdFreeData(&types); rpmtdFreeData(&typesidx); rpmtdFreeData(&flags); if (!ret) { sepolFree(head); } return ret; }
rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd, char ** specFilePtr, char ** cookie) { rpmfi fi = NULL; char * specFile = NULL; const char *rootdir = rpmtsRootDir(ts); Header h = NULL; rpmpsm psm = NULL; rpmte te = NULL; rpmRC rpmrc; int specix = -1; struct rpmtd_s filenames; rpmtdReset(&filenames); rpmrc = rpmReadPackageFile(ts, fd, NULL, &h); switch (rpmrc) { case RPMRC_NOTTRUSTED: case RPMRC_NOKEY: case RPMRC_OK: break; default: goto exit; break; } if (h == NULL) goto exit; rpmrc = RPMRC_FAIL; /* assume failure */ if (!headerIsSource(h)) { rpmlog(RPMLOG_ERR, _("source package expected, binary found\n")); goto exit; } /* src.rpm install can require specific rpmlib features, check them */ if (!rpmlibDeps(h)) goto exit; if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_ALLOC)) { struct rpmtd_s td; const char *str; const char *_cookie = headerGetString(h, RPMTAG_COOKIE); if (cookie && _cookie) *cookie = xstrdup(_cookie); /* Try to find spec by file flags */ if (_cookie && headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) { rpmfileAttrs *flags; while (specix < 0 && (flags = rpmtdNextUint32(&td))) { if (*flags & RPMFILE_SPECFILE) specix = rpmtdGetIndex(&td); } } /* Still no spec? Look by filename. */ while (specix < 0 && (str = rpmtdNextString(&filenames))) { if (rpmFileHasSuffix(str, ".spec")) specix = rpmtdGetIndex(&filenames); } } if (rootdir && rstreq(rootdir, "/")) rootdir = NULL; /* Macros need to be added before trying to create directories */ rpmInstallLoadMacros(h); if (specix >= 0) { const char *bn; headerDel(h, RPMTAG_BASENAMES); headerDel(h, RPMTAG_DIRNAMES); headerDel(h, RPMTAG_DIRINDEXES); rpmtdInit(&filenames); for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) { int spec = (i == specix); char *fn = rpmGenPath(rpmtsRootDir(ts), spec ? "%{_specdir}" : "%{_sourcedir}", bn); headerPutString(h, RPMTAG_OLDFILENAMES, fn); if (spec) specFile = xstrdup(fn); free(fn); } headerConvert(h, HEADERCONV_COMPRESSFILELIST); } else { rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n")); goto exit; }; if (rpmtsAddInstallElement(ts, h, NULL, 0, NULL)) { goto exit; } te = rpmtsElement(ts, 0); if (te == NULL) { /* XXX can't happen */ goto exit; } rpmteSetFd(te, fd); rpmteSetHeader(te, h); fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); h = headerFree(h); if (fi == NULL) { goto exit; } fi->apath = filenames.data; /* Ick */ rpmteSetFI(te, fi); fi = rpmfiFree(fi); if (rpmMkdirs(rpmtsRootDir(ts), "%{_topdir}:%{_sourcedir}:%{_specdir}")) { goto exit; } { /* set all files to be installed */ rpmfs fs = rpmteGetFileStates(te); int i; unsigned int fc = rpmfiFC(fi); for (i=0; i<fc; i++) rpmfsSetAction(fs, i, FA_CREATE); } psm = rpmpsmNew(ts, te); psm->goal = PKG_INSTALL; /* FIX: psm->fi->dnl should be owned. */ if (rpmpsmStage(psm, PSM_PROCESS) == RPMRC_OK) rpmrc = RPMRC_OK; (void) rpmpsmStage(psm, PSM_FINI); rpmpsmFree(psm); exit: if (specFilePtr && specFile && rpmrc == RPMRC_OK) *specFilePtr = specFile; else free(specFile); headerFree(h); rpmfiFree(fi); /* XXX nuke the added package(s). */ rpmtsClean(ts); return rpmrc; }
/* * Create a spec file object from a spec file * @param [String] filename Spec file path * @return [Spec] */ static VALUE spec_s_open(VALUE klass, VALUE filename) { #if RPM_VERSION_CODE < RPM_VERSION(4,1,0) Spec rspec; #else rpmts ts = NULL; #endif if (TYPE(filename) != T_STRING) { rb_raise(rb_eTypeError, "illegal argument type"); } #if RPM_VERSION_CODE < RPM_VERSION(4,1,0) switch (parseSpec(&rspec, RSTRING_PTR(filename), "/", NULL, 0, "", NULL, 1, 1)) { case 0: if (rspec != NULL) { break; } default: rb_raise(rb_eRuntimeError, "specfile `%s' parsing failed", RSTRING_PTR(filename)); } return Data_Wrap_Struct(klass, NULL, spec_free, rspec); #else ts = rpmtsCreate(); #if RPM_VERSION_CODE < RPM_VERSION(4,4,8) switch (parseSpec(ts, RSTRING_PTR(filename), "/", NULL, 0, "", NULL, 1, 1)) { #elif RPM_VERSION_CODE < RPM_VERSION(4,5,90) switch (parseSpec(ts, RSTRING_PTR(filename), "/", 0, "", NULL, 1, 1, 0)) { #elif RPM_VERSION_CODE < RPM_VERSION(5,0,0) switch (parseSpec(ts, RSTRING_PTR(filename), "/", NULL, 0, "", NULL, 1, 1)) { #else switch (parseSpec(ts, RSTRING_PTR(filename), "/", 0, "", NULL, 1, 1, 0)) { #endif case 0: if (ts != NULL) { break; } default: rb_raise(rb_eRuntimeError, "specfile `%s' parsing failed", RSTRING_PTR(filename)); } return Data_Wrap_Struct(klass, NULL, ts_free, ts); #endif } /* * * Alias for Spec#open */ VALUE rpm_spec_open(const char* filename) { return spec_s_open(rpm_cSpec, rb_str_new2(filename)); } /* * @return [String] Return Build root defined in the spec file */ VALUE rpm_spec_get_buildroot(VALUE spec) { #if RPM_VERSION_CODE < RPM_VERSION(4,5,90) if (RPM_SPEC(spec)->buildRootURL) { return rb_str_new2(RPM_SPEC(spec)->buildRootURL); } #elif RPM_VERSION_CODE < RPM_VERSION(4,5,90) if (RPM_SPEC(spec)->rootURL) { return rb_str_new2(RPM_SPEC(spec)->rootURL); } #elif RPM_VERSION_CODE < RPM_VERSION(5,0,0) if (RPM_SPEC(spec)->buildRoot) { return rb_str_new2(RPM_SPEC(spec)->buildRoot); } #else const char *buildRootURL = rpmGenPath(RPM_SPEC(spec)->rootURL, "%{?buildroot}", NULL); VALUE result = rb_str_new2(buildRootURL); buildRootURL = _free(buildRootURL); return result; #endif return Qnil; } /* * @return [String] Return Build subdirectory defined in the spec file */ VALUE rpm_spec_get_buildsubdir(VALUE spec) { if (RPM_SPEC(spec)->buildSubdir) { return rb_str_new2(RPM_SPEC(spec)->buildSubdir); } return Qnil; } /* * @return [Array<String>] Return Build architectures defined in the spec file */ VALUE rpm_spec_get_buildarchs(VALUE spec) { VALUE ba = rb_ivar_get(spec, id_ba); if (NIL_P(ba)) { register int i; ba = rb_ary_new(); for (i = 0; i < RPM_SPEC(spec)->BACount; i++) { rb_ary_push(ba, rb_str_new2(RPM_SPEC(spec)->BANames[i])); } rb_ivar_set(spec, id_ba, ba); } return ba; } /* * @return [Array<RPM::Require>] Return Build requires defined in the spec file */ VALUE rpm_spec_get_buildrequires(VALUE spec) { VALUE br = rb_ivar_get(spec, id_br); #if RPM_VERSION_CODE < RPM_VERSION(4,6,0) || RPM_VERSION_CODE >= RPM_VERSION(5,0,0) if (NIL_P(br)) { const char** names; const char** vers; int_32* flags; int_32 count; rpmTagType nt, vt, type; register int i; br = rb_ary_new(); if (!headerGetEntryMinMemory(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIRENAME, (hTYP_t)&nt, (hPTR_t*)&names, (hCNT_t)&count)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREVERSION, &vt, (void*)&vers); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREFLAGS, &type, (void*)&flags); for (i = 0; i < count; i++) { rb_ary_push(br, rpm_require_new(names[i], rpm_version_new(vers[i]), flags[i], spec)); } release_entry(nt, names); release_entry(vt, vers); rb_ivar_set(spec, id_br, br); } leave: return br; #else rpmtd nametd = rpmtdNew(); rpmtd versiontd = rpmtdNew(); rpmtd flagtd = rpmtdNew(); if (NIL_P(br)) { br = rb_ary_new(); if (!headerGet(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIRENAME, nametd, HEADERGET_MINMEM)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREVERSION, versiontd); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREFLAGS, flagtd); rpmtdInit(nametd); while ( rpmtdNext(nametd) != -1 ) { rb_ary_push(br, rpm_require_new(rpmtdGetString(nametd), rpm_version_new(rpmtdNextString(versiontd)), *rpmtdNextUint32(flagtd), spec)); } rb_ivar_set(spec, id_br, br); } leave: rpmtdFree(nametd); rpmtdFree(versiontd); rpmtdFree(flagtd); return br; #endif } /* * @return [Array<RPM::Conflict>] Return Build conflicts defined in the spec file */ VALUE rpm_spec_get_buildconflicts(VALUE spec) { VALUE bc = rb_ivar_get(spec, id_bc); #if RPM_VERSION_CODE < RPM_VERSION(4,6,0) || RPM_VERSION_CODE >= RPM_VERSION(5,0,0) if (NIL_P(bc)) { const char** names; const char** vers; int_32* flags; int_32 count; rpmTagType nt, vt, type; register int i; bc = rb_ary_new(); if (!headerGetEntryMinMemory(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTNAME, (hTYP_t)&nt, (hPTR_t*)&names, (hCNT_t)&count)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTVERSION, &vt, (void*)&vers); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTFLAGS, &type, (void*)&flags); for (i = 0; i < count; i++) { rb_ary_push(bc, rpm_conflict_new(names[i], rpm_version_new(vers[i]), flags[i], spec)); } release_entry(nt, names); release_entry(vt, vers); rb_ivar_set(spec, id_bc, bc); } leave: return bc; #else rpmtd nametd = rpmtdNew(); rpmtd versiontd = rpmtdNew(); rpmtd flagtd = rpmtdNew(); if (NIL_P(bc)) { bc = rb_ary_new(); if (!headerGet(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTNAME, nametd, HEADERGET_MINMEM)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTVERSION, versiontd); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTFLAGS, flagtd); rpmtdInit(nametd); while ( rpmtdNext(nametd) != -1) { rb_ary_push(bc, rpm_conflict_new(rpmtdGetString(nametd), rpm_version_new(rpmtdNextString(versiontd)), *rpmtdNextUint32(flagtd), spec)); } rb_ivar_set(spec, id_bc, bc); } leave: rpmtdFree(nametd); rpmtdFree(versiontd); rpmtdFree(flagtd); return bc; #endif }
/* * 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; struct archive *cpio; struct archive_entry *cpio_entry; struct cpio_mydata cpio_mydata; rpmts ts; rpmVSFlags vsflags; const char *compr; int packageflags = 0; if (strcmp(source, "-") == 0) fdi = fdDup(STDIN_FILENO); else fdi = Fopen(source, "r.ufdio"); if (Ferror(fdi)) { const char *srcname = (strcmp(source, "-") == 0) ? "<stdin>" : source; logMessage(ERROR, "%s: %s\n", srcname, Fstrerror(fdi)); return EXIT_FAILURE; } rpmReadConfigFiles(NULL, NULL); /* Initialize RPM transaction */ ts = rpmtsCreate(); vsflags = 0; /* Do not check digests, signatures or headers */ 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, "%s is not an RPM package", source); return EXIT_FAILURE; break; case RPMRC_FAIL: default: logMessage(ERROR, "error reading header from %s package\n", source); return EXIT_FAILURE; break; } /* Retrieve all dependencies and run them through deps function */ while (deps) { struct rpmtd_s tddep; struct rpmtd_s tdver; struct rpmtd_s tdsense; const char *depname; const char *depversion; uint32_t depsense; if (!headerGet(h, RPMTAG_REQUIRES, &tddep, HEADERGET_MINMEM)) break; if (!headerGet(h, RPMTAG_REQUIREVERSION, &tdver, HEADERGET_MINMEM)) { rpmtdFreeData(&tddep); break; } if (!headerGet(h, RPMTAG_REQUIREFLAGS, &tdsense, HEADERGET_MINMEM)) { rpmtdFreeData(&tddep); rpmtdFreeData(&tdver); break; } /* iterator */ while ((depname = rpmtdNextString(&tddep))) { depversion = rpmtdNextString(&tdver); depsense = *(rpmtdNextUint32(&tdsense)); if (deps(depname, depversion, depsense, userptr)) { rpmtdFreeData(&tddep); rpmtdFreeData(&tdver); rpmtdFreeData(&tdsense); Fclose(fdi); return EXIT_BADDEPS; } } rpmtdFreeData(&tddep); rpmtdFreeData(&tdver); rpmtdFreeData(&tdsense); break; } /* Retrieve all provides and run them through provides function */ while (provides) { struct rpmtd_s tddep; struct rpmtd_s tdver; struct rpmtd_s tdsense; const char *depname; const char *depversion; uint32_t depsense; if (!headerGet(h, RPMTAG_PROVIDES, &tddep, HEADERGET_MINMEM)) break; if (!headerGet(h, RPMTAG_PROVIDEVERSION, &tdver, HEADERGET_MINMEM)) { rpmtdFreeData(&tddep); break; } if (!headerGet(h, RPMTAG_PROVIDEFLAGS, &tdsense, HEADERGET_MINMEM)) { rpmtdFreeData(&tddep); rpmtdFreeData(&tdver); break; } /* iterator */ while ((depname = rpmtdNextString(&tddep))) { depversion = rpmtdNextString(&tdver); depsense = *(rpmtdNextUint32(&tdsense)); packageflags |= provides(depname, depversion, depsense, userptr); } rpmtdFreeData(&tddep); rpmtdFreeData(&tdver); rpmtdFreeData(&tdsense); if (packageflags == 0) { Fclose(fdi); return EXIT_BADDEPS; } break; } /* Retrieve type of payload compression. */ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); if (compr && strcmp(compr, "gzip")) { checked_asprintf(&rpmio_flags, "r.%sdio", compr); } else { checked_asprintf(&rpmio_flags, "r.gzdio"); } /* Open uncompressed cpio stream */ gzdi = Fdopen(fdi, rpmio_flags); free(rpmio_flags); if (gzdi == NULL) { logMessage(ERROR, "cannot re-open payload: %s", Fstrerror(gzdi)); return EXIT_FAILURE; } /* initialize cpio decompressor */ cpio = archive_read_new(); if (cpio==NULL) { Fclose(gzdi); return -1; } cpio_mydata.gzdi = gzdi; cpio_mydata.buffer = buffer; archive_read_support_compression_all(cpio); archive_read_support_format_all(cpio); rc = archive_read_open(cpio, &cpio_mydata, NULL, rpm_myread, rpm_myclose); /* check the status of archive_open */ if (rc != ARCHIVE_OK) { Fclose(gzdi); return -1; } /* read all files in cpio archive */ while ((rc = archive_read_next_header(cpio, &cpio_entry)) == ARCHIVE_OK) { const struct stat *fstat; int64_t fsize; const char* filename; int needskip = 1; /* do we need to read the data to get to the next header? */ int offset = 0; int towrite = 0; filename = archive_entry_pathname(cpio_entry); fstat = archive_entry_stat(cpio_entry); fsize = archive_entry_size(cpio_entry); /* 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, packageflags, userptr))) { /* filter this file */ towrite = 0; } /* Create directories */ char* dirname = strdup(filename+offset); /* If the dup fails, let's hope the dirs already exist */ if (dirname) { char* dirptr = dirname; while (dirptr && *dirptr) { dirptr = strchr(dirptr, '/'); if (dirptr) { *dirptr = 0; mkdir(dirname, 0700); *dirptr = '/'; dirptr++; } } free(dirname); } /* Regular file */ if (towrite>=2) { FILE *fdout = fopen(filename+offset, "w"); if (fdout==NULL) { rc = 33; break; } rc = archive_read_data_into_fd(cpio, fileno(fdout)); if (rc!=ARCHIVE_OK) { /* XXX We didn't get the file.. well.. */ needskip = 0; } else { needskip = 0; } fclose(fdout); /* set access rights */ if (chmod(filename+offset, fstat->st_mode)) { logMessage(ERROR, "Failed to set the rights for %s to %04o", filename+offset, fstat->st_mode); } } /* symlink, we assume that the path contained in symlink * is shorter than BUFFERSIZE */ while (towrite && S_ISLNK(fstat->st_mode)) { char symlinkbuffer[BUFFERSIZE-1]; needskip = 0; if ((rc = archive_read_data(cpio, symlinkbuffer, fsize))!=ARCHIVE_OK) { /* XXX We didn't get the file.. well.. */ break; } if (symlink(buffer, filename+offset)) { logMessage(ERROR, "Failed to create symlink %s -> %s", filename+offset, buffer); } break; } if(needskip) archive_read_data_skip(cpio); } rc = archive_read_finish(cpio); /* Also closes the RPM stream using callback */ return rc != ARCHIVE_OK; }