Move legacy%#¤%#¤ to librpm now that it can move..
[platform/upstream/rpm.git] / lib / legacy.c
1 /**
2  * \file rpmdb/legacy.c
3  */
4
5 #include "system.h"
6
7 #include <rpmlib.h>
8 #include <rpmmacro.h>
9 #include <rpmstring.h>
10 #include "lib/legacy.h"
11 #include "debug.h"
12
13 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
14
15 /**
16  * Open a file descriptor to verify file MD5 and size.
17  * @param path          file path
18  * @retval pidp         prelink helper pid or 0
19  * @retval fsizep       file size
20  * @return              -1 on error, otherwise, an open file descriptor
21  */ 
22 int _noDirTokens = 0;
23
24 static int dncmp(const void * a, const void * b)
25 {
26     const char *const * first = a;
27     const char *const * second = b;
28     return strcmp(*first, *second);
29 }
30
31 void compressFilelist(Header h)
32 {
33     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
34     HAE_t hae = (HAE_t)headerAddEntry;
35     HRE_t hre = (HRE_t)headerRemoveEntry;
36     HFD_t hfd = headerFreeData;
37     char ** fileNames;
38     const char ** dirNames;
39     const char ** baseNames;
40     uint32_t * dirIndexes;
41     rpmTagType fnt;
42     int count;
43     int i, xx;
44     int dirIndex = -1;
45
46     /*
47      * This assumes the file list is already sorted, and begins with a
48      * single '/'. That assumption isn't critical, but it makes things go
49      * a bit faster.
50      */
51
52     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
53         xx = hre(h, RPMTAG_OLDFILENAMES);
54         return;         /* Already converted. */
55     }
56
57     if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
58         return;         /* no file list */
59     if (fileNames == NULL || count <= 0)
60         return;
61
62     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
63     baseNames = alloca(sizeof(*dirNames) * count);
64     dirIndexes = alloca(sizeof(*dirIndexes) * count);
65
66     if (fileNames[0][0] != '/') {
67         /* HACK. Source RPM, so just do things differently */
68         dirIndex = 0;
69         dirNames[dirIndex] = "";
70         for (i = 0; i < count; i++) {
71             dirIndexes[i] = dirIndex;
72             baseNames[i] = fileNames[i];
73         }
74         goto exit;
75     }
76
77     for (i = 0; i < count; i++) {
78         const char ** needle;
79         char savechar;
80         char * baseName;
81         int len;
82
83         if (fileNames[i] == NULL)       /* XXX can't happen */
84             continue;
85         baseName = strrchr(fileNames[i], '/') + 1;
86         len = baseName - fileNames[i];
87         needle = dirNames;
88         savechar = *baseName;
89         *baseName = '\0';
90         if (dirIndex < 0 ||
91             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
92             char *s = alloca(len + 1);
93             memcpy(s, fileNames[i], len + 1);
94             s[len] = '\0';
95             dirIndexes[i] = ++dirIndex;
96             dirNames[dirIndex] = s;
97         } else
98             dirIndexes[i] = needle - dirNames;
99
100         *baseName = savechar;
101         baseNames[i] = baseName;
102     }
103
104 exit:
105     if (count > 0) {
106         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
107         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
108                         baseNames, count);
109         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
110                         dirNames, dirIndex + 1);
111     }
112
113     fileNames = hfd(fileNames, fnt);
114
115     xx = hre(h, RPMTAG_OLDFILENAMES);
116 }
117
118 void rpmfiBuildFNames(Header h, rpmTag tagN,
119         const char *** fnp, int * fcp)
120 {
121     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
122     HFD_t hfd = headerFreeData;
123     const char ** baseNames;
124     const char ** dirNames;
125     uint32_t * dirIndexes;
126     int count;
127     const char ** fileNames;
128     int size;
129     rpmTag dirNameTag = 0;
130     rpmTag dirIndexesTag = 0;
131     rpmTagType bnt, dnt;
132     char * t;
133     int i, xx;
134
135     if (tagN == RPMTAG_BASENAMES) {
136         dirNameTag = RPMTAG_DIRNAMES;
137         dirIndexesTag = RPMTAG_DIRINDEXES;
138     } else if (tagN == RPMTAG_ORIGBASENAMES) {
139         dirNameTag = RPMTAG_ORIGDIRNAMES;
140         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
141     }
142
143     if (!hge(h, tagN, &bnt, (void **) &baseNames, &count)) {
144         if (fnp) *fnp = NULL;
145         if (fcp) *fcp = 0;
146         return;         /* no file list */
147     }
148
149     xx = hge(h, dirNameTag, &dnt, (void **) &dirNames, NULL);
150     xx = hge(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
151
152     size = sizeof(*fileNames) * count;
153     for (i = 0; i < count; i++)
154         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
155
156     fileNames = xmalloc(size);
157     t = ((char *) fileNames) + (sizeof(*fileNames) * count);
158     for (i = 0; i < count; i++) {
159         fileNames[i] = t;
160         t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
161         *t++ = '\0';
162     }
163     baseNames = hfd(baseNames, bnt);
164     dirNames = hfd(dirNames, dnt);
165
166     if (fnp)
167         *fnp = fileNames;
168     else
169         fileNames = _free(fileNames);
170     if (fcp) *fcp = count;
171 }
172
173 void expandFilelist(Header h)
174 {
175     HAE_t hae = (HAE_t)headerAddEntry;
176     HRE_t hre = (HRE_t)headerRemoveEntry;
177     const char ** fileNames = NULL;
178     int count = 0;
179     int xx;
180
181     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
182         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fileNames, &count);
183         if (fileNames == NULL || count <= 0)
184             return;
185         xx = hae(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
186                         fileNames, count);
187         fileNames = _free(fileNames);
188     }
189
190     xx = hre(h, RPMTAG_DIRNAMES);
191     xx = hre(h, RPMTAG_BASENAMES);
192     xx = hre(h, RPMTAG_DIRINDEXES);
193 }
194
195 /*
196  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
197  * Retrofit an explicit "Provides: name = epoch:version-release.
198  */
199 void providePackageNVR(Header h)
200 {
201     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
202     HFD_t hfd = headerFreeData;
203     const char *name, *version, *release;
204     int32_t * epoch;
205     const char *pEVR;
206     char *p;
207     int32_t pFlags = RPMSENSE_EQUAL;
208     const char ** provides = NULL;
209     const char ** providesEVR = NULL;
210     rpmTagType pnt, pvt;
211     int32_t * provideFlags = NULL;
212     int providesCount;
213     int i, xx;
214     int bingo = 1;
215
216     /* Generate provides for this package name-version-release. */
217     xx = headerNVR(h, &name, &version, &release);
218     if (!(name && version && release))
219         return;
220     pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
221     *p = '\0';
222     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
223         sprintf(p, "%d:", *epoch);
224         while (*p != '\0')
225             p++;
226     }
227     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
228
229     /*
230      * Rpm prior to 3.0.3 does not have versioned provides.
231      * If no provides at all are available, we can just add.
232      */
233     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
234         goto exit;
235
236     /*
237      * Otherwise, fill in entries on legacy packages.
238      */
239     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) {
240         for (i = 0; i < providesCount; i++) {
241             char * vdummy = "";
242             int32_t fdummy = RPMSENSE_ANY;
243             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
244                         &vdummy, 1);
245             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
246                         &fdummy, 1);
247         }
248         goto exit;
249     }
250
251     xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
252
253         /* LCL: providesEVR is not NULL */
254     if (provides && providesEVR && provideFlags)
255     for (i = 0; i < providesCount; i++) {
256         if (!(provides[i] && providesEVR[i]))
257             continue;
258         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
259             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
260             continue;
261         bingo = 0;
262         break;
263     }
264
265 exit:
266     provides = hfd(provides, pnt);
267     providesEVR = hfd(providesEVR, pvt);
268
269     if (bingo) {
270         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
271                 &name, 1);
272         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
273                 &pFlags, 1);
274         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
275                 &pEVR, 1);
276     }
277 }
278
279 void legacyRetrofit(Header h)
280 {
281     const char * prefix;
282
283     /*
284      * We don't use these entries (and rpm >= 2 never has) and they are
285      * pretty misleading. Let's just get rid of them so they don't confuse
286      * anyone.
287      */
288     if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
289         (void) headerRemoveEntry(h, RPMTAG_FILEUIDS);
290     if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
291         (void) headerRemoveEntry(h, RPMTAG_FILEGIDS);
292
293     /*
294      * We switched the way we do relocatable packages. We fix some of
295      * it up here, though the install code still has to be a bit 
296      * careful. This fixup makes queries give the new values though,
297      * which is quite handy.
298      */
299     if (headerGetEntry(h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &prefix, NULL))
300     {
301         const char * nprefix = stripTrailingChar(alloca_strdup(prefix), '/');
302         (void) headerAddEntry(h, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE,
303                 &nprefix, 1); 
304     }
305
306     /*
307      * The file list was moved to a more compressed format which not
308      * only saves memory (nice), but gives fingerprinting a nice, fat
309      * speed boost (very nice). Go ahead and convert old headers to
310      * the new style (this is a noop for new headers).
311      */
312      compressFilelist(h);
313
314     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
315     if (!headerIsEntry(h, RPMTAG_SOURCERPM)) {
316         int32_t one = 1;
317         if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
318             (void) headerAddEntry(h, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE,
319                                 &one, 1);
320     } else {
321         /* Retrofit "Provide: name = EVR" for binary packages. */
322         providePackageNVR(h);
323     }
324 }