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);
66 while ((i = rpmtdNext(&fileNames)) >= 0) {
71 const char *filename = rpmtdGetString(&fileNames);
73 if (filename == NULL) /* XXX can't happen */
75 baseName = strrchr(filename, '/') + 1;
76 len = baseName - filename;
81 (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
82 char *s = xmalloc(len + 1);
83 rstrlcpy(s, filename, len + 1);
84 dirIndexes[i] = ++dirIndex;
85 dirNames[dirIndex] = s;
87 dirIndexes[i] = needle - dirNames;
90 baseNames[i] = baseName;
95 headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, count);
96 headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, count);
97 headerPutStringArray(h, RPMTAG_DIRNAMES,
98 (const char **) dirNames, dirIndex + 1);
101 rpmtdFreeData(&fileNames);
102 for (i = 0; i <= dirIndex; i++) {
109 xx = headerDel(h, RPMTAG_OLDFILENAMES);
112 static void expandFilelist(Header h)
114 struct rpmtd_s filenames;
116 if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
117 (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
118 if (rpmtdCount(&filenames) < 1)
120 rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
121 headerPut(h, &filenames, HEADERPUT_DEFAULT);
122 rpmtdFreeData(&filenames);
125 (void) headerDel(h, RPMTAG_DIRNAMES);
126 (void) headerDel(h, RPMTAG_BASENAMES);
127 (void) headerDel(h, RPMTAG_DIRINDEXES);
131 * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
132 * Retrofit an explicit "Provides: name = epoch:version-release.
134 static void providePackageNVR(Header h)
136 const char *name = headerGetString(h, RPMTAG_NAME);
137 char *pEVR = headerGetAsString(h, RPMTAG_EVR);
138 rpmsenseFlags pFlags = RPMSENSE_EQUAL;
140 struct rpmtd_s pnames;
143 /* Generate provides for this package name-version-release. */
148 * Rpm prior to 3.0.3 does not have versioned provides.
149 * If no provides at all are available, we can just add.
151 if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
156 * Otherwise, fill in entries on legacy packages.
158 if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
159 while (rpmtdNext(&pnames) >= 0) {
160 rpmsenseFlags fdummy = RPMSENSE_ANY;
162 headerPutString(h, RPMTAG_PROVIDEVERSION, "");
163 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
168 /* see if we already have this provide */
169 hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
170 nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
171 if (rpmdsFind(hds, nvrds) >= 0) {
180 headerPutString(h, RPMTAG_PROVIDENAME, name);
181 headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
182 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
184 rpmtdFreeData(&pnames);
188 static void legacyRetrofit(Header h)
190 struct rpmtd_s dprefix;
193 * We don't use these entries (and rpm >= 2 never has) and they are
194 * pretty misleading. Let's just get rid of them so they don't confuse
197 if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
198 (void) headerDel(h, RPMTAG_FILEUIDS);
199 if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
200 (void) headerDel(h, RPMTAG_FILEGIDS);
203 * We switched the way we do relocatable packages. We fix some of
204 * it up here, though the install code still has to be a bit
205 * careful. This fixup makes queries give the new values though,
206 * which is quite handy.
208 if (headerGet(h, RPMTAG_DEFAULTPREFIX, &dprefix, HEADERGET_MINMEM)) {
209 const char *prefix = rpmtdGetString(&dprefix);
210 char * nprefix = stripTrailingChar(xstrdup(prefix), '/');
212 headerPutString(h, RPMTAG_PREFIXES, nprefix);
214 rpmtdFreeData(&dprefix);
218 * The file list was moved to a more compressed format which not
219 * only saves memory (nice), but gives fingerprinting a nice, fat
220 * speed boost (very nice). Go ahead and convert old headers to
221 * the new style (this is a noop for new headers).
225 /* Retrofit "Provide: name = EVR" for binary packages. */
226 if (!headerIsSource(h)) {
227 providePackageNVR(h);
231 int headerConvert(Header h, headerConvOps op)
239 case HEADERCONV_EXPANDFILELIST:
242 case HEADERCONV_COMPRESSFILELIST:
245 case HEADERCONV_RETROFIT_V3: