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