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