7 #include <rpm/header.h>
8 #include <rpm/rpmmacro.h>
9 #include <rpm/rpmstring.h>
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmds.h>
13 #include "lib/legacy.h"
19 static int dncmp(const void * a, const void * b)
21 const char *const * first = a;
22 const char *const * second = b;
23 return strcmp(*first, *second);
26 void compressFilelist(Header h)
28 HAE_t hae = (HAE_t)headerAddEntry;
29 struct rpmtd_s fileNames;
31 const char ** baseNames;
32 uint32_t * dirIndexes;
38 * This assumes the file list is already sorted, and begins with a
39 * single '/'. That assumption isn't critical, but it makes things go
43 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
44 xx = headerDel(h, RPMTAG_OLDFILENAMES);
45 return; /* Already converted. */
48 if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
50 count = rpmtdCount(&fileNames);
54 dirNames = xmalloc(sizeof(*dirNames) * count); /* worst case */
55 baseNames = xmalloc(sizeof(*dirNames) * count);
56 dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
58 if (headerIsSource(h)) {
59 /* HACK. Source RPM, so just do things differently */
61 dirNames[dirIndex] = xstrdup("");
62 while ((i = rpmtdNext(&fileNames)) >= 0) {
63 dirIndexes[i] = dirIndex;
64 baseNames[i] = rpmtdGetString(&fileNames);
69 while ((i = rpmtdNext(&fileNames)) >= 0) {
74 const char *filename = rpmtdGetString(&fileNames);
76 if (filename == NULL) /* XXX can't happen */
78 baseName = strrchr(filename, '/') + 1;
79 len = baseName - filename;
84 (needle = bsearch(filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
85 char *s = xmalloc(len + 1);
86 rstrlcpy(s, filename, len + 1);
87 dirIndexes[i] = ++dirIndex;
88 dirNames[dirIndex] = s;
90 dirIndexes[i] = needle - dirNames;
93 baseNames[i] = baseName;
98 xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
99 xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
101 xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
102 dirNames, (rpm_count_t) dirIndex + 1);
105 rpmtdFreeData(&fileNames);
106 for (i = 0; i <= dirIndex; i++) {
113 xx = headerDel(h, RPMTAG_OLDFILENAMES);
116 void expandFilelist(Header h)
118 struct rpmtd_s filenames;
120 if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
121 (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
122 if (rpmtdCount(&filenames) < 1)
124 rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
125 headerPut(h, &filenames, HEADERPUT_DEFAULT);
126 rpmtdFreeData(&filenames);
129 (void) headerDel(h, RPMTAG_DIRNAMES);
130 (void) headerDel(h, RPMTAG_BASENAMES);
131 (void) headerDel(h, RPMTAG_DIRINDEXES);
135 * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
136 * Retrofit an explicit "Provides: name = epoch:version-release.
138 static void providePackageNVR(Header h)
142 rpmsenseFlags pFlags = RPMSENSE_EQUAL;
144 struct rpmtd_s pnames;
147 /* Generate provides for this package name-version-release. */
148 pEVR = headerGetEVR(h, &name);
153 * Rpm prior to 3.0.3 does not have versioned provides.
154 * If no provides at all are available, we can just add.
156 if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
161 * Otherwise, fill in entries on legacy packages.
163 if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
164 while (rpmtdNext(&pnames) >= 0) {
165 const char * vdummy = "";
166 rpmsenseFlags fdummy = RPMSENSE_ANY;
167 headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
169 headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
175 /* see if we already have this provide */
176 hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 1);
177 nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
178 if (rpmdsFind(hds, nvrds) >= 0) {
187 headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
189 headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
191 headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
194 rpmtdFreeData(&pnames);
198 void legacyRetrofit(Header h)
200 struct rpmtd_s dprefix;
203 * We don't use these entries (and rpm >= 2 never has) and they are
204 * pretty misleading. Let's just get rid of them so they don't confuse
207 if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
208 (void) headerDel(h, RPMTAG_FILEUIDS);
209 if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
210 (void) headerDel(h, RPMTAG_FILEGIDS);
213 * We switched the way we do relocatable packages. We fix some of
214 * it up here, though the install code still has to be a bit
215 * careful. This fixup makes queries give the new values though,
216 * which is quite handy.
218 if (headerGet(h, RPMTAG_DEFAULTPREFIX, &dprefix, HEADERGET_MINMEM)) {
219 const char *prefix = rpmtdGetString(&dprefix);
220 char * nprefix = stripTrailingChar(xstrdup(prefix), '/');
221 (void) headerAddEntry(h, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE,
224 rpmtdFreeData(&dprefix);
228 * The file list was moved to a more compressed format which not
229 * only saves memory (nice), but gives fingerprinting a nice, fat
230 * speed boost (very nice). Go ahead and convert old headers to
231 * the new style (this is a noop for new headers).
235 /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
236 if (headerIsSource(h)) {
238 if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
239 (void) headerAddEntry(h, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE,
242 /* Retrofit "Provide: name = EVR" for binary packages. */
243 providePackageNVR(h);