rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

fprint.c
Go to the documentation of this file.
1
5 #include "system.h"
6
7 #include <rpmiotypes.h> /* XXX rpmRC codes. */
8 #include <rpmio.h> /* XXX Realpath(). */
9 #include <rpmmacro.h> /* XXX for rpmCleanPath */
10
11 #include <rpmtag.h>
12 #include <rpmdb.h>
13
14 #include "fprint.h"
15 #include "debug.h"
16
17 /*@access hashTable @*/
18
19 fingerPrintCache fpCacheCreate(int sizeHint)
20 {
21 fingerPrintCache fpc;
22
23 fpc = xmalloc(sizeof(*fpc));
24 fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL);
25 assert(fpc->ht != NULL);
26 return fpc;
27 }
28
29 fingerPrintCache fpCacheFree(fingerPrintCache cache)
30 {
31 cache->ht = htFree(cache->ht);
32 free(cache);
33 return NULL;
34 }
35
42 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory(
43 fingerPrintCache cache,
44 const char * dirName)
45 /*@*/
46 {
47 const void ** data;
48
49 if (htGetEntry(cache->ht, dirName, &data, NULL, NULL))
50 return NULL;
51 return data[0];
52 }
53
62 static fingerPrint doLookup(fingerPrintCache cache,
63 const char * dirName, const char * baseName, int scareMem)
64 /*@globals fileSystem, internalState @*/
65 /*@modifies cache, fileSystem, internalState @*/
66 {
67 char dir[PATH_MAX];
68 const char * cleanDirName;
69 size_t cdnl;
70 char * end; /* points to the '\0' at the end of "buf" */
71 fingerPrint fp;
72 struct stat sb;
73 char * buf;
74 const struct fprintCacheEntry_s * cacheHit;
75
76 /* assert(*dirName == '/' || !scareMem); */
77
78 /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
79 cleanDirName = dirName;
80 cdnl = strlen(cleanDirName);
81
82 if (*cleanDirName == '/') {
83 if (!scareMem)
84 cleanDirName =
85 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
86 } else {
87 scareMem = 0; /* XXX causes memory leak */
88
89 /* Using realpath on the arg isn't correct if the arg is a symlink,
90 * especially if the symlink is a dangling link. What we
91 * do instead is use realpath() on `.' and then append arg to
92 * the result.
93 */
94
95 /* if the current directory doesn't exist, we might fail.
96 oh well. likewise if it's too long. */
97 dir[0] = '\0';
98 if (Realpath(".", dir) != NULL) {
99 end = dir + strlen(dir);
100 if (end[-1] != '/') *end++ = '/';
101 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
102 *end = '\0';
103 (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */
104 end = dir + strlen(dir);
105 if (end[-1] != '/') *end++ = '/';
106 *end = '\0';
107 cleanDirName = dir;
108 cdnl = end - dir;
109 }
110 }
111 fp.entry = NULL;
112 fp.subDir = NULL;
113 fp.baseName = NULL;
114 /*@-nullret@*/
115 if (cleanDirName == NULL) return fp; /* XXX can't happen */
116 /*@=nullret@*/
117
118 buf = strcpy(alloca(cdnl + 1), cleanDirName);
119 end = buf + cdnl;
120
121 /* no need to pay attention to that extra little / at the end of dirName */
122 if (buf[1] && end[-1] == '/') {
123 end--;
124 *end = '\0';
125 }
126
127 while (1) {
128
129 /* as we're stating paths here, we want to follow symlinks */
130
131 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
132 if (cacheHit != NULL) {
133 fp.entry = cacheHit;
134 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
135 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
136 char * dn = xmalloc(nb);
137 struct fprintCacheEntry_s * newEntry = (void *)dn;
138
139 /*@-usereleased@*/ /* LCL: contiguous malloc confusion */
140 dn += sizeof(*newEntry);
141 strcpy(dn, (*buf != '\0' ? buf : "/"));
142 newEntry->ino = (ino_t)sb.st_ino;
143 newEntry->dev = (dev_t)sb.st_dev;
144 newEntry->dirName = dn;
145 fp.entry = newEntry;
146
147 /*@-kepttrans -dependenttrans @*/
148 htAddEntry(cache->ht, dn, fp.entry);
149 /*@=kepttrans =dependenttrans @*/
150 /*@=usereleased@*/
151 }
152
153 if (fp.entry) {
154 fp.subDir = cleanDirName + (end - buf);
155 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
156 fp.subDir++;
157 if (fp.subDir[0] == '\0' ||
158 /* XXX don't bother saving '/' as subdir */
159 (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
160 fp.subDir = NULL;
161 fp.baseName = baseName;
162 if (!scareMem && fp.subDir != NULL)
163 fp.subDir = xstrdup(fp.subDir);
164 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
165 return fp;
166 /*@=compdef@*/
167 }
168
169 /* stat of '/' just failed! */
170 if (end == buf + 1)
171 abort();
172
173 end--;
174 while ((end > buf) && *end != '/') end--;
175 if (end == buf) /* back to stat'ing just '/' */
176 end++;
177
178 *end = '\0';
179 }
180
181 /*@notreached@*/
182
183 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
184 /*@-nullret@*/ return fp; /*@=nullret@*/ /* LCL: can't happen. */
185 /*@=compdef@*/
186 }
187
188 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName,
189 const char * baseName, int scareMem)
190 {
191 return doLookup(cache, dirName, baseName, scareMem);
192 }
193
194 rpmuint32_t fpHashFunction(rpmuint32_t h, const void * data,
195 /*@unused@*/ size_t size)
196 {
197 const fingerPrint * fp = data;
198 const char * chptr = fp->baseName;
199 unsigned char ch = '\0';
200
201 while (*chptr != '\0') ch ^= *chptr++;
202
203 h |= ((unsigned)ch) << 24;
204 h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
205 h |= fp->entry->ino & 0xFFFF;
206
207 return h;
208 }
209
210 int fpEqual(const void * key1, const void * key2)
211 {
212 const fingerPrint *k1 = key1;
213 const fingerPrint *k2 = key2;
214
215 /* If the addresses are the same, so are the values. */
216 if (k1 == k2)
217 return 0;
218
219 /* Otherwise, compare fingerprints by value. */
220 /*@-nullpass@*/ /* LCL: whines about (*k2).subdir */
221 if (FP_EQUAL(*k1, *k2))
222 return 0;
223 /*@=nullpass@*/
224 return 1;
225
226 }
227
228 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
229 const char ** baseNames, const rpmuint32_t * dirIndexes,
230 rpmuint32_t fileCount, fingerPrint * fpList)
231 {
232 unsigned i;
233
234 for (i = 0; i < (unsigned) fileCount; i++) {
235 /* If this is in the same directory as the last file, don't bother
236 redoing all of this work */
237 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
238 fpList[i].entry = fpList[i - 1].entry;
239 fpList[i].subDir = fpList[i - 1].subDir;
240 fpList[i].baseName = baseNames[i];
241 } else {
242 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
243 1);
244 }
245 }
246 }
247
248 #ifdef NOTUSED
249
256 static
257 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
258 /*@modifies h, cache, *fpList @*/
259 {
260 rpmTagData he_p = { .ptr = NULL };
261 HE_s he_s = { .tag = 0, .t = 0, .p = &he_p, .c = 0, .freeData = 0 };
262 HE_t he = &he_s;
263 const char ** baseNames;
264 const char ** dirNames;
265 rpmuint32_t * dirIndexes;
266 rpmTagCount fileCount;
267 int xx;
268
269 he->tag = RPMTAG_BASENAMES;
270 xx = headerGet(h, he->tag, &he->t, he->p, &he->c);
271 baseNames = he_p.argv;
272 fileCount = he->c;
273 if (!xx)
274 return;
275
276 he->tag = RPMTAG_DIRNAMES;
277 xx = headerGet(h, he, 0);
278 dirNames = he_p.argv;
279 he->tag = RPMTAG_DIRINDEXES;
280 xx = headerGet(h, he, 0);
281 dirIndexes = he_p.ui32p;
282
283 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
284
285 dirIndexes = _free(dirIndexes);
286 dirNames = _free(dirNames);
287 baseNames = _free(baseNames);
288 }
289 #endif