Convert legacyRetrofit() to new headerGet()
[platform/upstream/rpm.git] / lib / legacy.c
1 /**
2  * \file lib/legacy.c
3  */
4
5 #include "system.h"
6
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>
12
13 #include "lib/legacy.h"
14
15 #include "debug.h"
16
17 int _noDirTokens = 0;
18
19 static int dncmp(const void * a, const void * b)
20 {
21     const char *const * first = a;
22     const char *const * second = b;
23     return strcmp(*first, *second);
24 }
25
26 void compressFilelist(Header h)
27 {
28     HAE_t hae = (HAE_t)headerAddEntry;
29     HRE_t hre = (HRE_t)headerRemoveEntry;
30     struct rpmtd_s fileNames;
31     char ** dirNames;
32     const char ** baseNames;
33     uint32_t * dirIndexes;
34     rpm_count_t count;
35     int xx, i;
36     int dirIndex = -1;
37
38     /*
39      * This assumes the file list is already sorted, and begins with a
40      * single '/'. That assumption isn't critical, but it makes things go
41      * a bit faster.
42      */
43
44     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
45         xx = hre(h, RPMTAG_OLDFILENAMES);
46         return;         /* Already converted. */
47     }
48
49     if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM)) 
50         return;
51     count = rpmtdCount(&fileNames);
52     if (count < 1) 
53         return;
54
55     dirNames = xmalloc(sizeof(*dirNames) * count);      /* worst case */
56     baseNames = xmalloc(sizeof(*dirNames) * count);
57     dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
58
59     if (headerIsSource(h)) {
60         /* HACK. Source RPM, so just do things differently */
61         dirIndex = 0;
62         dirNames[dirIndex] = xstrdup("");
63         while ((i = rpmtdNext(&fileNames)) >= 0) {
64             dirIndexes[i] = dirIndex;
65             baseNames[i] = rpmtdGetString(&fileNames);
66         }
67         goto exit;
68     }
69
70     while ((i = rpmtdNext(&fileNames)) >= 0) {
71         char ** needle;
72         char savechar;
73         char * baseName;
74         size_t len;
75         const char *filename = rpmtdGetString(&fileNames);
76
77         if (filename == NULL)   /* XXX can't happen */
78             continue;
79         baseName = strrchr(filename, '/') + 1;
80         len = baseName - filename;
81         needle = dirNames;
82         savechar = *baseName;
83         *baseName = '\0';
84         if (dirIndex < 0 ||
85             (needle = bsearch(filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
86             char *s = xmalloc(len + 1);
87             rstrlcpy(s, filename, len + 1);
88             dirIndexes[i] = ++dirIndex;
89             dirNames[dirIndex] = s;
90         } else
91             dirIndexes[i] = needle - dirNames;
92
93         *baseName = savechar;
94         baseNames[i] = baseName;
95     }
96
97 exit:
98     if (count > 0) {
99         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
100         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
101                         baseNames, count);
102         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
103                         dirNames, (rpm_count_t) dirIndex + 1);
104     }
105
106     rpmtdFreeData(&fileNames);
107     for (i = 0; i <= dirIndex; i++) {
108         free(dirNames[i]);
109     }
110     free(dirNames);
111     free(baseNames);
112     free(dirIndexes);
113
114     xx = hre(h, RPMTAG_OLDFILENAMES);
115 }
116
117 void expandFilelist(Header h)
118 {
119     HRE_t hre = (HRE_t)headerRemoveEntry;
120     struct rpmtd_s filenames;
121
122     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
123         (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
124         if (rpmtdCount(&filenames) < 1)
125             return;
126         rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
127         headerPut(h, &filenames, HEADERPUT_DEFAULT);
128         rpmtdFreeData(&filenames);
129     }
130
131     (void) hre(h, RPMTAG_DIRNAMES);
132     (void) hre(h, RPMTAG_BASENAMES);
133     (void) hre(h, RPMTAG_DIRINDEXES);
134 }
135
136 /*
137  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
138  * Retrofit an explicit "Provides: name = epoch:version-release.
139  */
140 static void providePackageNVR(Header h)
141 {
142     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
143     HFD_t hfd = headerFreeData;
144     const char *name;
145     char *pEVR;
146     rpmsenseFlags pFlags = RPMSENSE_EQUAL;
147     const char ** provides = NULL;
148     const char ** providesEVR = NULL;
149     rpmTagType pnt, pvt;
150     rpmsenseFlags * provideFlags = NULL;
151     rpm_count_t providesCount, i;
152     int xx;
153     int bingo = 1;
154
155     /* Generate provides for this package name-version-release. */
156     pEVR = headerGetEVR(h, &name);
157     if (!(name && pEVR))
158         return;
159
160     /*
161      * Rpm prior to 3.0.3 does not have versioned provides.
162      * If no provides at all are available, we can just add.
163      */
164     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (rpm_data_t *) &provides, &providesCount))
165         goto exit;
166
167     /*
168      * Otherwise, fill in entries on legacy packages.
169      */
170     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (rpm_data_t *) &providesEVR, NULL)) {
171         for (i = 0; i < providesCount; i++) {
172             const char * vdummy = "";
173             rpmsenseFlags fdummy = RPMSENSE_ANY;
174             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
175                         &vdummy, 1);
176             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
177                         &fdummy, 1);
178         }
179         goto exit;
180     }
181
182     xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (rpm_data_t *) &provideFlags, NULL);
183
184         /* LCL: providesEVR is not NULL */
185     if (provides && providesEVR && provideFlags)
186     for (i = 0; i < providesCount; i++) {
187         if (!(provides[i] && providesEVR[i]))
188             continue;
189         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
190             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
191             continue;
192         bingo = 0;
193         break;
194     }
195
196 exit:
197     provides = hfd(provides, pnt);
198     providesEVR = hfd(providesEVR, pvt);
199
200     if (bingo) {
201         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
202                 &name, 1);
203         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
204                 &pFlags, 1);
205         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
206                 &pEVR, 1);
207     }
208     free(pEVR);
209 }
210
211 void legacyRetrofit(Header h)
212 {
213     struct rpmtd_s dprefix;
214
215     /*
216      * We don't use these entries (and rpm >= 2 never has) and they are
217      * pretty misleading. Let's just get rid of them so they don't confuse
218      * anyone.
219      */
220     if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
221         (void) headerRemoveEntry(h, RPMTAG_FILEUIDS);
222     if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
223         (void) headerRemoveEntry(h, RPMTAG_FILEGIDS);
224
225     /*
226      * We switched the way we do relocatable packages. We fix some of
227      * it up here, though the install code still has to be a bit 
228      * careful. This fixup makes queries give the new values though,
229      * which is quite handy.
230      */
231     if (headerGet(h, RPMTAG_DEFAULTPREFIX, &dprefix, HEADERGET_MINMEM)) {
232         const char *prefix = rpmtdGetString(&dprefix);
233         char * nprefix = stripTrailingChar(xstrdup(prefix), '/');
234         (void) headerAddEntry(h, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE,
235                 &nprefix, 1); 
236         free(nprefix);
237         rpmtdFreeData(&dprefix);
238     }
239
240     /*
241      * The file list was moved to a more compressed format which not
242      * only saves memory (nice), but gives fingerprinting a nice, fat
243      * speed boost (very nice). Go ahead and convert old headers to
244      * the new style (this is a noop for new headers).
245      */
246      compressFilelist(h);
247
248     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
249     if (headerIsSource(h)) {
250         int32_t one = 1;
251         if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
252             (void) headerAddEntry(h, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE,
253                                 &one, 1);
254     } else {
255         /* Retrofit "Provide: name = EVR" for binary packages. */
256         providePackageNVR(h);
257     }
258 }