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>
15 static int dncmp(const void * a, const void * b)
17 const char *const * first = a;
18 const char *const * second = b;
19 return strcmp(*first, *second);
22 static void compressFilelist(Header h)
24 struct rpmtd_s fileNames;
26 const char ** baseNames;
27 uint32_t * dirIndexes;
33 * This assumes the file list is already sorted, and begins with a
34 * single '/'. That assumption isn't critical, but it makes things go
38 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
39 xx = headerDel(h, RPMTAG_OLDFILENAMES);
40 return; /* Already converted. */
43 if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
45 count = rpmtdCount(&fileNames);
49 dirNames = xmalloc(sizeof(*dirNames) * count); /* worst case */
50 baseNames = xmalloc(sizeof(*dirNames) * count);
51 dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
53 /* HACK. Source RPM, so just do things differently */
54 { const char *fn = rpmtdGetString(&fileNames);
55 if (fn && *fn != '/') {
57 dirNames[dirIndex] = xstrdup("");
58 while ((i = rpmtdNext(&fileNames)) >= 0) {
59 dirIndexes[i] = dirIndex;
60 baseNames[i] = rpmtdGetString(&fileNames);
67 * XXX EVIL HACK, FIXME:
68 * This modifies (and then restores) a const string from rpmtd
69 * through basename retrieved from strrchr() which silently
70 * casts away const on return.
72 while ((i = rpmtdNext(&fileNames)) >= 0) {
77 char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */
79 if (filename == NULL) /* XXX can't happen */
81 baseName = strrchr(filename, '/') + 1;
82 len = baseName - filename;
87 (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
88 char *s = xmalloc(len + 1);
89 rstrlcpy(s, filename, len + 1);
90 dirIndexes[i] = ++dirIndex;
91 dirNames[dirIndex] = s;
93 dirIndexes[i] = needle - dirNames;
96 baseNames[i] = baseName;
101 headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, count);
102 headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, count);
103 headerPutStringArray(h, RPMTAG_DIRNAMES,
104 (const char **) dirNames, dirIndex + 1);
107 rpmtdFreeData(&fileNames);
108 for (i = 0; i <= dirIndex; i++) {
115 xx = headerDel(h, RPMTAG_OLDFILENAMES);
118 static void expandFilelist(Header h)
120 struct rpmtd_s filenames;
122 if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
123 (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
124 if (rpmtdCount(&filenames) < 1)
126 rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
127 headerPut(h, &filenames, HEADERPUT_DEFAULT);
128 rpmtdFreeData(&filenames);
131 (void) headerDel(h, RPMTAG_DIRNAMES);
132 (void) headerDel(h, RPMTAG_BASENAMES);
133 (void) headerDel(h, RPMTAG_DIRINDEXES);
137 * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
138 * Retrofit an explicit "Provides: name = epoch:version-release.
140 static void providePackageNVR(Header h)
142 const char *name = headerGetString(h, RPMTAG_NAME);
143 char *pEVR = headerGetAsString(h, RPMTAG_EVR);
144 rpmsenseFlags pFlags = RPMSENSE_EQUAL;
146 struct rpmtd_s pnames;
149 /* Generate provides for this package name-version-release. */
154 * Rpm prior to 3.0.3 does not have versioned provides.
155 * If no provides at all are available, we can just add.
157 if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
162 * Otherwise, fill in entries on legacy packages.
164 if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
165 while (rpmtdNext(&pnames) >= 0) {
166 rpmsenseFlags fdummy = RPMSENSE_ANY;
168 headerPutString(h, RPMTAG_PROVIDEVERSION, "");
169 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
174 /* see if we already have this provide */
175 hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
176 nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
177 if (rpmdsFind(hds, nvrds) >= 0) {
186 headerPutString(h, RPMTAG_PROVIDENAME, name);
187 headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
188 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
190 rpmtdFreeData(&pnames);
194 static void legacyRetrofit(Header h)
197 * The file list was moved to a more compressed format which not
198 * only saves memory (nice), but gives fingerprinting a nice, fat
199 * speed boost (very nice). Go ahead and convert old headers to
200 * the new style (this is a noop for new headers).
204 /* Retrofit "Provide: name = EVR" for binary packages. */
205 if (!headerIsSource(h)) {
206 providePackageNVR(h);
210 int headerConvert(Header h, int op)
218 case HEADERCONV_EXPANDFILELIST:
221 case HEADERCONV_COMPRESSFILELIST:
224 case HEADERCONV_RETROFIT_V3:
235 * Backwards compatibility wrappers for legacy interfaces.
236 * Remove these some day...
238 #define _RPM_4_4_COMPAT
239 #include <rpm/rpmlegacy.h>
241 /* dumb macro to avoid 50 copies of this code while converting... */
248 rpmtdFreeData(&td); \
252 int headerRemoveEntry(Header h, rpm_tag_t tag)
254 return headerDel(h, tag);
257 static void *_headerFreeData(rpm_data_t data, rpm_tagtype_t type)
260 if (type == RPM_FORCEFREE_TYPE ||
261 type == RPM_STRING_ARRAY_TYPE ||
262 type == RPM_I18NSTRING_TYPE ||
263 type == RPM_BIN_TYPE)
269 void * headerFreeData(rpm_data_t data, rpm_tagtype_t type)
271 return _headerFreeData(data, type);
274 void * headerFreeTag(Header h, rpm_data_t data, rpm_tagtype_t type)
276 return _headerFreeData(data, type);
279 static int headerGetWrap(Header h, rpm_tag_t tag,
280 rpm_tagtype_t * type,
283 headerGetFlags flags)
288 rc = headerGet(h, tag, &td, flags);
293 int headerGetEntry(Header h, rpm_tag_t tag,
294 rpm_tagtype_t * type,
298 return headerGetWrap(h, tag, type, p, c, HEADERGET_DEFAULT);
301 int headerGetEntryMinMemory(Header h, rpm_tag_t tag,
302 rpm_tagtype_t * type,
306 return headerGetWrap(h, tag, type, (rpm_data_t) p, c, HEADERGET_MINMEM);
309 /* XXX shut up compiler warning from missing prototype */
310 int headerGetRawEntry(Header h, rpm_tag_t tag, rpm_tagtype_t * type, rpm_data_t * p,
313 int headerGetRawEntry(Header h, rpm_tag_t tag, rpm_tagtype_t * type, rpm_data_t * p,
317 return headerIsEntry(h, tag);
319 return headerGetWrap(h, tag, type, p, c, HEADERGET_RAW);
322 int headerNextIterator(HeaderIterator hi,
324 rpm_tagtype_t * type,
331 rc = headerNext(hi, &td);
338 int headerModifyEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
339 rpm_constdata_t p, rpm_count_t c)
341 struct rpmtd_s td = {
347 return headerMod(h, &td);
350 static int headerPutWrap(Header h, rpm_tag_t tag, rpm_tagtype_t type,
351 rpm_constdata_t p, rpm_count_t c, headerPutFlags flags)
353 struct rpmtd_s td = {
359 return headerPut(h, &td, flags);
362 int headerAddOrAppendEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
363 rpm_constdata_t p, rpm_count_t c)
365 return headerPutWrap(h, tag, type, p, c, HEADERPUT_APPEND);
368 int headerAppendEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
369 rpm_constdata_t p, rpm_count_t c)
371 return headerPutWrap(h, tag, type, p, c, HEADERPUT_APPEND);
374 int headerAddEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
375 rpm_constdata_t p, rpm_count_t c)
377 return headerPutWrap(h, tag, type, p, c, HEADERPUT_DEFAULT);
379 #undef _RPM_4_4_COMPAT