diff options
author | Per Øyvind Karlsen <peroyvind@mandriva.org> | 2011-03-09 06:39:31 +0000 |
---|---|---|
committer | Per Øyvind Karlsen <peroyvind@mandriva.org> | 2011-03-09 06:39:31 +0000 |
commit | c3108621aea9515f86147866ac8d793b950557a4 (patch) | |
tree | db5d1db62144e9e2a3a62b5049dcf324330a77dc /URPM.xs | |
parent | f2f0c3c6d11044cbb2e245d90092e15d00049e08 (diff) | |
download | perl-URPM-c3108621aea9515f86147866ac8d793b950557a4.tar perl-URPM-c3108621aea9515f86147866ac8d793b950557a4.tar.gz perl-URPM-c3108621aea9515f86147866ac8d793b950557a4.tar.bz2 perl-URPM-c3108621aea9515f86147866ac8d793b950557a4.tar.xz perl-URPM-c3108621aea9515f86147866ac8d793b950557a4.zip |
add support for doing comparision against provides with distepoch to allow
fresh install of newer releases into chroots
- convert suggests to compatible tags when loading package headers
- fix incorrect arch returned for packages without any (ie. public keys)
- eliminate disttag & distepoch when extracting name, version, release to
handle upgrade
Diffstat (limited to 'URPM.xs')
-rw-r--r-- | URPM.xs | 323 |
1 files changed, 298 insertions, 25 deletions
@@ -127,6 +127,25 @@ int rpmError_callback() { static int rpm_codeset_is_utf8 = 0; +static struct s_backup { + char *ptr; + char chr; +} char_backups[32]; + +static int BI = 0; + +static void +backup_char(char *c) { + char_backups[BI].chr = *c, + *(char_backups[BI++].ptr = &(*c)) = 0; /* mark end of string to enable searching backwards */ +} + +static void +restore_chars() { + for(; BI > 0; char_backups[BI].ptr = NULL) + BI--, *char_backups[BI].ptr = char_backups[BI].chr; +} + static SV* newSVpv_utf8(const char *s, STRLEN len) { @@ -138,12 +157,47 @@ newSVpv_utf8(const char *s, STRLEN len) static void get_fullname_parts(URPM__Package pkg, char **name, char **version, char **release, char **arch, char **eos) { char *_version = NULL, *_release = NULL, *_arch = NULL, *_eos = NULL; + int distepoch = 0; + char *tmp; + /* search through provides for distepoch */ + if ((tmp = pkg->provides)) { + do { + if((_eos = strchr(tmp, '@'))) + *_eos = 0; + + if((tmp = strchr(tmp, '[')) && + (tmp = strchr(tmp, '-')) && + (tmp = strchr(tmp, ':'))) + distepoch = 1; + if(_eos) { + *_eos++ = '@'; + tmp = _eos; + } + } while(!distepoch && _eos != NULL); + /* XXX: filename at end of line, don't bother to support it, just make sure + * for it not to cause crash... + */ + if ((tmp = strrchr(pkg->info, '.')) && !strcmp(tmp, ".rpm")) + distepoch = 0; + } if ((_eos = strchr(pkg->info, '@')) != NULL) { *_eos = 0; /* mark end of string to enable searching backwards */ if ((_arch = strrchr(pkg->info, '.')) != NULL) { *_arch = 0; if ((release != NULL || version != NULL || name != NULL) && (_release = strrchr(pkg->info, '-')) != NULL) { + if (distepoch) { + tmp = _release; + while(tmp != _arch) { + backup_char(tmp++); + } + if((tmp = strrchr(pkg->info, '-'))) { + _release = tmp; + } else { + restore_chars(); + croak("failed while eliminating distepoch, this should never happen! :("); + } + } *_release = 0; if ((version != NULL || name != NULL) && (_version = strrchr(pkg->info, '-')) != NULL) { if (name != NULL) *name = pkg->info; @@ -178,6 +232,156 @@ get_int(Header header, int32_t tag) { return ep ? *ep : 0; } +static void +strip_distepoch(Header header, int32_t tag) { + struct rpmtd_s val; + + headerGet(header, tag, &val, HEADERGET_DEFAULT); + char **list = val.data; + for (val.ix = 0; val.ix < (int)val.count; val.ix++) { + char *tmp = strchr(list[val.ix], '-'); + if(tmp) { + tmp = strchr(tmp, ':'); + if(tmp) { + memset(tmp, 0, strlen(tmp)); + } + } + } + headerMod(header, &val); +} + +static void +pretend_distepoch(Header header, int32_t names_tag, int32_t flags_tag, int32_t versions_tag) { + struct rpmtd_s names, flags, versions; + char *EVR = headerFormat(header, "%|EPOCH?{%{EPOCH}:}|%{VERSION}-%{RELEASE}", NULL); + + headerGet(header, flags_tag, &flags, HEADERGET_DEFAULT); + headerGet(header, versions_tag, &versions, HEADERGET_DEFAULT); + + char **name = NULL; + char **name2 = NULL; + int32_t *flag = flags.data; + int32_t *flag2 = NULL; + char **version = versions.data; + char **version2 = NULL; + + for (flags.ix = 0; flags.ix < (int)flags.count; flags.ix++) { + if(!(flag[flags.ix] & ((RPMSENSE_LESS|RPMSENSE_GREATER|~RPMSENSE_EQUAL))) && version[flags.ix] && *version[flags.ix] && !strcmp(EVR, version[flags.ix])) { + if(!name) { + headerGet(header, names_tag, &names, HEADERGET_DEFAULT); + + name = names.data; + name2 = malloc(++names.count * sizeof(*name)); + names.data = memcpy(name2, name, sizeof(*name)*names.count); + flag2 = malloc(names.count * sizeof(flag)); + flags.data = memcpy(flag2, flag, sizeof(flag)*names.count); + version2 = malloc(names.count * sizeof(*version)); + versions.data = memcpy(version2, version, sizeof(*version)*names.count); + } else { + names.data = name2 = realloc(name2, sizeof(*name) * ++names.count); + flags.data = flag2 = realloc(flag2, sizeof(flag) * names.count); + versions.data = version2 = realloc(version2, sizeof(*version) * names.count); + } + name2[names.count-1] = name[flags.ix]; + flag2[names.count-1] = (flag[flags.ix] | RPMSENSE_LESS) & ~RPMSENSE_EQUAL; + flag2[flags.ix] |= RPMSENSE_GREATER; + version2[names.count-1] = strdup(version[flags.ix]); + char *v = version2[names.count-1]; + (*(&v[strlen(v)-1]))++; + } + } + if(name) { + flags.count = versions.count = names.count; + headerMod(header, &names); + headerMod(header, &flags); + headerMod(header, &versions); + /*rpmtdFree(&names);*/ + } + /*rpmtdFree(&flags); + rpmtdFree(&versions);*/ +} + +static void +remap_suggests(Header header) { + struct rpmtd_s list, flags, list_evr; + + if (headerGet(header, RPMTAG_REQUIREFLAGS, &flags, HEADERGET_DEFAULT)) { + rpm_count_t count = 0; + for(flags.ix = 0; flags.ix < (int)flags.count; flags.ix++) + if(((uint32_t*)flags.data)[flags.ix] & RPMSENSE_MISSINGOK) + count++; + + if(count) { + if(headerGet(header, RPMTAG_REQUIRENAME, &list, HEADERGET_DEFAULT)) { + headerGet(header, RPMTAG_REQUIREVERSION, &list_evr, HEADERGET_DEFAULT); + struct rpmtd_s list_sug, flags_sug, list_evr_sug; + + list_sug.tag = RPMTAG_SUGGESTSNAME; + flags_sug.tag = RPMTAG_SUGGESTSFLAGS; + list_evr_sug.tag = RPMTAG_SUGGESTSVERSION; + list_sug.count = flags_sug.count = list_evr_sug.count = count; + list_sug.type = list.type; + flags_sug.type = flags_sug.type; + list_evr_sug.type = list_evr_sug.type; + list_sug.flags = list.flags; + flags_sug.flags = flags.flags; + list_evr_sug.flags = list_evr.flags; + list_sug.data = malloc(count * sizeof(char*)); + flags_sug.data = malloc(count * sizeof(uint32_t)); + list_evr_sug.data = malloc(count * sizeof(char*)); + + for(list.ix = flags.ix = flags_sug.ix = 0; flags.ix < (int)flags.count; flags.ix++) { + if(((uint32_t*)flags.data)[flags.ix] & RPMSENSE_MISSINGOK) { + ((char**)list_sug.data)[flags_sug.ix] = ((char**)list.data)[flags.ix]; + ((uint32_t*)flags_sug.data)[flags_sug.ix] = ((uint32_t*)flags.data)[flags.ix]; + ((char**)list_evr_sug.data)[flags_sug.ix] = ((char**)list_evr.data)[flags.ix]; + + flags_sug.ix++; + list.count--; + } + else { + ((char**)list.data)[list.ix] = ((char**)list.data)[flags.ix]; + ((uint32_t*)flags.data)[list.ix] = ((uint32_t*)flags.data)[flags.ix]; + ((char**)list_evr.data)[list.ix] = ((char**)list_evr.data)[flags.ix]; + list.ix++; + } + } + flags.count = list_evr.count = list.count; + + headerMod(header, &list); + headerMod(header, &flags); + headerMod(header, &list_evr); + headerPut(header, &list_sug, HEADERPUT_DEFAULT); + /* XXX: unused + headerPut(header, &flags_sug, HEADERPUT_DEFAULT); + headerPut(header, &list_evr_sug, HEADERPUT_DEFAULT); + */ + + rpmtdFreeData(&list); + rpmtdFreeData(&list_evr); + + rpmtdFreeData(&list_sug); + rpmtdFreeData(&flags_sug); + rpmtdFreeData(&list_evr_sug); + } + rpmtdFreeData(&flags); + } + } +} + +static void +convert_header(Header header) { + if (header) { + if (headerIsEntry(header, RPMTAG_DISTEPOCH)) { + strip_distepoch(header, RPMTAG_PROVIDEVERSION); + strip_distepoch(header, RPMTAG_REQUIREVERSION); + strip_distepoch(header, RPMTAG_OBSOLETEVERSION); + strip_distepoch(header, RPMTAG_CONFLICTVERSION); + } + remap_suggests(header); + } +} + static int sigsize_to_filesize(int sigsize) { return sigsize + 440; /* 440 is the rpm header size (?) empirical, but works */ @@ -222,7 +426,7 @@ ranges_overlap(uint32_t aflags, char *sa, uint32_t bflags, char *sb, int b_nopro int sense = 0; char *eosa = strchr(sa, ']'); char *eosb = strchr(sb, ']'); - char *ea, *va, *ra, *eb, *vb, *rb; + char *ea, *va, *ra, *da, *eb, *vb, *rb, *db; if (eosa) *eosa = 0; if (eosb) *eosb = 0; @@ -236,6 +440,9 @@ ranges_overlap(uint32_t aflags, char *sa, uint32_t bflags, char *sb, int b_nopro ea = NULL; } if ((ra = strrchr(sa, '-'))) *ra++ = 0; + if (ra && (da = strchr(ra, ':'))) *da++ = 0; + else da = NULL; + /* parse sb as an [epoch:]version[-release] */ for (eb = sb; *sb >= '0' && *sb <= '9'; ++sb); if (*sb == ':') { @@ -246,6 +453,8 @@ ranges_overlap(uint32_t aflags, char *sa, uint32_t bflags, char *sb, int b_nopro eb = NULL; } if ((rb = strrchr(sb, '-'))) *rb++ = 0; + if (rb && (db = strchr(rb, ':'))) *db++ = 0; + else db = NULL; /* now compare epoch */ if (ea && eb) sense = rpmvercmp(*ea ? ea : "0", *eb ? eb : "0"); @@ -260,6 +469,8 @@ ranges_overlap(uint32_t aflags, char *sa, uint32_t bflags, char *sb, int b_nopro sense = rpmvercmp(ra, rb); } /* restore all character that have been modified inline */ + if (db) db[-1] = ':'; + if (da) da[-1] = ':'; if (rb) rb[-1] = '-'; if (ra) ra[-1] = '-'; if (eb) vb[-1] = ':'; @@ -405,11 +616,28 @@ return_list_str(char *s, Header header, int32_t tag_name, int32_t tag_flags, int if (tag_flags && tag_version) { while(ps != NULL) { ++count; - if (f(s, ps-s, NULL, 0, NULL, param)) return -count; + char *tmp, *ps2 = NULL; + if((tmp = strchr(s, '[')) && + (tmp = strchr(tmp, '-')) && + (tmp = strchr(tmp, ':')) && + tmp < ps) { + backup_char(tmp); + *tmp = ']'; + ps2 = ++tmp; + } + if (f(s, ps2 ? ps2-s : ps-s, NULL, 0, NULL, param)) { restore_chars(); return -count; } + restore_chars(); s = ps + 1; ps = strchr(s, '@'); } ++count; - if (f(s, 0, NULL, 0, NULL, param)) return -count; + if((ps = strchr(s, '[')) && + (ps = strchr(ps, '-')) && + (ps = strchr(ps, ':'))) { + backup_char(ps); + *ps++ = ']'; + } + if (f(s, ps ? ps-s : 0, NULL, 0, NULL, param)) { restore_chars(); return -count; } + restore_chars(); } else { char *eos; while(ps != NULL) { @@ -425,6 +653,9 @@ return_list_str(char *s, Header header, int32_t tag_name, int32_t tag_flags, int } } else if (header) { struct rpmtd_s list, flags, list_evr; + memset(&list, 0, sizeof(list)); + memset(&flags, 0, sizeof(flags)); + memset(&list_evr, 0, sizeof(list_evr)); if (headerGet(header, tag_name, &list, HEADERGET_DEFAULT)) { if (tag_flags) headerGet(header, tag_flags, &flags, HEADERGET_DEFAULT); @@ -622,13 +853,14 @@ return_list_tag(URPM__Package pkg, int32_t tag_name) { case RPMTAG_ARCH: { get_fullname_parts(pkg, &name, &version, &release, &arch, &eos); - XPUSHs(sv_2mortal(newSVpv(arch, eos-arch))); + XPUSHs(sv_2mortal(newSVpv(arch == eos ? "" : arch, eos-arch))); } break; case RPMTAG_SUMMARY: XPUSHs(sv_2mortal(newSVpv(pkg->summary, 0))); break; } + restore_chars(); } PUTBACK; } @@ -797,15 +1029,17 @@ pack_header(URPM__Package pkg) { if (pkg->info == NULL) { char buff[1024]; char *p = buff; - char *name = get_name(pkg->h, RPMTAG_NAME); - char *version = get_name(pkg->h, RPMTAG_VERSION); - char *release = get_name(pkg->h, RPMTAG_RELEASE); - char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src"; - - p += 1 + snprintf(buff, sizeof(buff), "%s-%s-%s.%s@%d@%d@%s", name, version, release, arch, + const char *group = get_name(pkg->h, RPMTAG_GROUP); + const char *nvra = headerFormat(pkg->h, + "%{NAME}-%{VERSION}-%{RELEASE}%|DISTTAG?{-%{DISTTAG}%|DISTEPOCH?" + "{%{DISTEPOCH}}|}|.%|ARCH?{%|SOURCERPM?{%{ARCH}}:{src}|}:{}|", + NULL + ); + p += 1 + snprintf(buff, sizeof(buff), "%s@%d@%d@%s", nvra, get_int(pkg->h, RPMTAG_EPOCH), get_int(pkg->h, RPMTAG_SIZE), - get_name(pkg->h, RPMTAG_GROUP)); + group); pkg->info = memcpy(malloc(p-buff), buff, p-buff); + _free(nvra); } if (pkg->filesize == 0) pkg->filesize = sigsize_to_filesize(get_int(pkg->h, RPMTAG_SIGSIZE)); if (pkg->requires == NULL && pkg->suggests == NULL) @@ -1269,6 +1503,7 @@ update_header(char *filename, URPM__Package pkg, __attribute__((unused)) int kee if (fd != NULL) { if (pkg->h && !(pkg->flag & FLAG_NO_HEADER_FREE)) pkg->h = headerFree(pkg->h); pkg->h = headerRead(fd, HEADER_MAGIC_YES); + pkg->flag &= ~FLAG_NO_HEADER_FREE; Fclose(fd); return 1; @@ -1459,6 +1694,7 @@ Pkg_name(pkg) get_fullname_parts(pkg, &name, &version, NULL, NULL, NULL); if (version - name < 1) croak("invalid fullname"); XPUSHs(sv_2mortal(newSVpv(name, version-name-1))); + restore_chars(); } else if (pkg->h) { XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_NAME), 0))); } @@ -1474,6 +1710,7 @@ Pkg_version(pkg) get_fullname_parts(pkg, NULL, &version, &release, NULL, NULL); if (release - version < 1) croak("invalid fullname"); XPUSHs(sv_2mortal(newSVpv(version, release-version-1))); + restore_chars(); } else if (pkg->h) { XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_VERSION), 0))); } @@ -1489,6 +1726,7 @@ Pkg_release(pkg) get_fullname_parts(pkg, NULL, NULL, &release, &arch, NULL); if (arch - release < 1) croak("invalid fullname"); XPUSHs(sv_2mortal(newSVpv(release, arch-release-1))); + restore_chars(); } else if (pkg->h) { XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_RELEASE), 0))); } @@ -1502,7 +1740,8 @@ Pkg_arch(pkg) char *eos; get_fullname_parts(pkg, NULL, NULL, NULL, &arch, &eos); - XPUSHs(sv_2mortal(newSVpv(arch, eos-arch))); + XPUSHs(sv_2mortal(newSVpv(arch == eos ? "" : arch, eos-arch))); + restore_chars(); } else if (pkg->h) { XPUSHs(sv_2mortal(newSVpv(headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src", 0))); } @@ -1539,6 +1778,7 @@ Pkg_is_arch_compat__XS(pkg) #else RETVAL = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch); #endif + restore_chars(); } else { RETVAL = 0; } @@ -1571,6 +1811,7 @@ Pkg_is_platform_compat(pkg) RETVAL = rpmPlatformScore(platform, NULL, 0); *eos = '@'; _free(platform); + restore_chars(); } else { #else croak("is_platform_compat() is available only since rpm 4.4.8"); @@ -1717,7 +1958,8 @@ Pkg_fullname(pkg) PUSHs(sv_2mortal(newSVpv(name, version-name-1))); PUSHs(sv_2mortal(newSVpv(version, release-version-1))); PUSHs(sv_2mortal(newSVpv(release, arch-release-1))); - PUSHs(sv_2mortal(newSVpv(arch, eos-arch))); + PUSHs(sv_2mortal(newSVpv(arch == eos ? "" : arch, eos-arch))); + restore_chars(); } } else if (pkg->h) { char *name = get_name(pkg->h, RPMTAG_NAME); @@ -1726,7 +1968,13 @@ Pkg_fullname(pkg) char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src"; if (gimme == G_SCALAR) { - XPUSHs(sv_2mortal(newSVpvf("%s-%s-%s.%s", name, version, release, arch))); + const char *nvra = headerFormat(pkg->h, + "%{NAME}-%{VERSION}-%{RELEASE}%|DISTTAG?{-%{DISTTAG}%|DISTEPOCH?" + "{%{DISTEPOCH}}|}|.%|ARCH?{%|SOURCERPM?{%{ARCH}}:{src}|}:{}|", + NULL + ); + XPUSHs(sv_2mortal(newSVpvf("%s", nvra))); + _free(nvra); } else if (gimme == G_ARRAY) { EXTEND(SP, 4); PUSHs(sv_2mortal(newSVpv(name, 0))); @@ -1820,6 +2068,7 @@ Pkg_compare_pkg(lpkg, rpkg) lrelease[-1] = '-'; larch[-1] = '.'; } + restore_chars(); croak("undefined package"); } compare = lepoch - repoch; @@ -1865,6 +2114,7 @@ Pkg_compare_pkg(lpkg, rpkg) rrelease[-1] = '-'; rarch[-1] = '.'; } + restore_chars(); RETVAL = compare; } OUTPUT: @@ -1938,6 +2188,7 @@ Pkg_compare(pkg, evr) if (pkg->info) { _release[-1] = '-'; _eos[-1] = '.'; + restore_chars(); } RETVAL = compare; OUTPUT: @@ -2005,12 +2256,14 @@ Pkg_filename(pkg) memcpy(eon, savbuf, 4); } } else if (pkg->h) { - char *name = get_name(pkg->h, RPMTAG_NAME); - char *version = get_name(pkg->h, RPMTAG_VERSION); - char *release = get_name(pkg->h, RPMTAG_RELEASE); - char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src"; - - XPUSHs(sv_2mortal(newSVpvf("%s-%s-%s.%s.rpm", name, version, release, arch))); + const char *nvra = headerFormat(pkg->h, + "%{NAME}-%{VERSION}-%{RELEASE}%|DISTTAG?{-%{DISTTAG}%|DISTEPOCH?" + "{%{DISTEPOCH}}|}|.%|ARCH?{%|SOURCERPM?{%{ARCH}}:{src}|}:{}|", + NULL + ); + + XPUSHs(sv_2mortal(newSVpvf("%s.rpm", nvra))); + _free(nvra); } # deprecated @@ -2027,13 +2280,17 @@ Pkg_header_filename(pkg) } else if (pkg->h) { char buff[1024]; char *p = buff; - char *name = get_name(pkg->h, RPMTAG_NAME); - char *version = get_name(pkg->h, RPMTAG_VERSION); - char *release = get_name(pkg->h, RPMTAG_RELEASE); - char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src"; - p += snprintf(buff, sizeof(buff), "%s-%s-%s.%s", name, version, release, arch); + const char *nvra = headerFormat(pkg->h, + "%{NAME}-%{VERSION}-%{RELEASE}%|DISTTAG?{-%{DISTTAG}%|DISTEPOCH?" + "{%{DISTEPOCH}}|}|.%|ARCH?{%|SOURCERPM?{%{ARCH}}:{src}|}:{}|", + NULL + ); + + p += snprintf(buff, sizeof(buff), "%s", nvra); XPUSHs(sv_2mortal(newSVpv(buff, p-buff))); + _free(nvra); + } void @@ -3050,7 +3307,18 @@ Trans_add(trans, pkg, ...) } } } + + if(headerIsEntry(pkg->h, RPMTAG_DISTEPOCH)) { + pretend_distepoch(pkg->h, RPMTAG_REQUIRENAME, RPMTAG_REQUIREFLAGS, RPMTAG_REQUIREVERSION); + } + RETVAL = rpmtsAddInstallElement(trans->ts, pkg->h, (fnpyKey)(1+(long)(pkg->flag & FLAG_ID)), update, relocations) == 0; + + rpmte te = rpmtsElement(trans->ts, 0); + headerLink(pkg->h); + rpmteSetHeader(te, pkg->h); + headerUnlink(pkg->h); + /* free allocated memory, check rpm is copying it just above, at least in 4.0.4 */ #ifndef RPM_ORG rpmfiFreeRelocations(relocations); @@ -3525,6 +3793,8 @@ Urpm_parse_hdlist__XS(urpm, filename, ...) struct s_Package pkg, *_pkg; SV *sv_pkg; + convert_header(header); + memset(&pkg, 0, sizeof(struct s_Package)); pkg.flag = 1 + av_len(depslist); pkg.h = header; @@ -3885,6 +4155,9 @@ Urpm_stream2header(fp) pkg->h = headerRead(fd, HEADER_MAGIC_YES); if (pkg->h) { SV *sv_pkg; + + convert_header(pkg->h); + EXTEND(SP, 1); sv_pkg = sv_newmortal(); sv_setref_pv(sv_pkg, "URPM::Package", (void*)pkg); |