rpm  5.4.10
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 #define _FPRINT_INTERNAL
15 #include "fprint.h"
16 
17 #include "debug.h"
18 
19 /*@access hashTable @*/
20 
22 {
23  fingerPrintCache fpc;
24 
25  fpc = (fingerPrintCache) xmalloc(sizeof(*fpc));
26  fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL);
27 assert(fpc->ht != NULL);
28  return fpc;
29 }
30 
32 {
33  cache->ht = htFree(cache->ht);
34  free(cache);
35  return NULL;
36 }
37 
44 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory(
45  fingerPrintCache cache,
46  const char * dirName)
47  /*@*/
48 {
49  const void ** data;
50 
51  if (htGetEntry(cache->ht, dirName, &data, NULL, NULL))
52  return NULL;
53  return (const struct fprintCacheEntry_s *) data[0];
54 }
55 
65  const char * dirName, const char * baseName, int scareMem)
66  /*@globals fileSystem, internalState @*/
67  /*@modifies cache, fileSystem, internalState @*/
68 {
69  char dir[PATH_MAX];
70  const char * cleanDirName;
71  size_t cdnl;
72  char * end; /* points to the '\0' at the end of "buf" */
73  fingerPrint fp;
74  struct stat sb;
75  char * buf;
76  const struct fprintCacheEntry_s * cacheHit;
77 
78  /* assert(*dirName == '/' || !scareMem); */
79 
80  /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
81  cleanDirName = dirName;
82  cdnl = strlen(cleanDirName);
83 
84  if (*cleanDirName == '/') {
85  if (!scareMem)
86  cleanDirName =
87  rpmCleanPath(strcpy((char *)alloca(cdnl+1), dirName));
88  } else {
89  scareMem = 0; /* XXX causes memory leak */
90 
91  /* Using realpath on the arg isn't correct if the arg is a symlink,
92  * especially if the symlink is a dangling link. What we
93  * do instead is use realpath() on `.' and then append arg to
94  * the result.
95  */
96 
97  /* if the current directory doesn't exist, we might fail.
98  oh well. likewise if it's too long. */
99  dir[0] = '\0';
100  if (Realpath(".", dir) != NULL) {
101  end = dir + strlen(dir);
102  if (end[-1] != '/') *end++ = '/';
103  end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
104  *end = '\0';
105  (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */
106  end = dir + strlen(dir);
107  if (end[-1] != '/') *end++ = '/';
108  *end = '\0';
109  cleanDirName = dir;
110  cdnl = end - dir;
111  }
112  }
113  fp.entry = NULL;
114  fp.subDir = NULL;
115  fp.baseName = NULL;
116  /*@-nullret@*/
117  if (cleanDirName == NULL) return fp; /* XXX can't happen */
118  /*@=nullret@*/
119 
120  buf = strcpy((char *)alloca(cdnl + 1), cleanDirName);
121  end = buf + cdnl;
122 
123  /* no need to pay attention to that extra little / at the end of dirName */
124  if (buf[1] && end[-1] == '/') {
125  end--;
126  *end = '\0';
127  }
128 
129  while (1) {
130 
131  /* as we're stating paths here, we want to follow symlinks */
132 
133  cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
134  if (cacheHit != NULL) {
135  fp.entry = cacheHit;
136  } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
137  size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
138  char * dn = (char *) xmalloc(nb);
139  struct fprintCacheEntry_s * newEntry = (struct fprintCacheEntry_s *)dn;
140 
141  /*@-usereleased@*/ /* LCL: contiguous malloc confusion */
142  dn += sizeof(*newEntry);
143  strcpy(dn, (*buf != '\0' ? buf : "/"));
144  newEntry->ino = (ino_t)sb.st_ino;
145  newEntry->dev = (dev_t)sb.st_dev;
146  newEntry->dirName = dn;
147  fp.entry = newEntry;
148 
149  /*@-kepttrans -dependenttrans @*/
150  htAddEntry(cache->ht, dn, fp.entry);
151  /*@=kepttrans =dependenttrans @*/
152  /*@=usereleased@*/
153  }
154 
155  if (fp.entry) {
156  fp.subDir = cleanDirName + (end - buf);
157  if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
158  fp.subDir++;
159  if (fp.subDir[0] == '\0' ||
160  /* XXX don't bother saving '/' as subdir */
161  (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
162  fp.subDir = NULL;
163  fp.baseName = baseName;
164  if (!scareMem && fp.subDir != NULL)
165  fp.subDir = xstrdup(fp.subDir);
166  /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
167  return fp;
168  /*@=compdef@*/
169  }
170 
171  /* stat of '/' just failed! */
172  if (end == buf + 1)
173  abort();
174 
175  end--;
176  while ((end > buf) && *end != '/') end--;
177  if (end == buf) /* back to stat'ing just '/' */
178  end++;
179 
180  *end = '\0';
181  }
182 
183  /*@notreached@*/
184 
185  /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
186  /*@-nullret@*/ return fp; /*@=nullret@*/ /* LCL: can't happen. */
187  /*@=compdef@*/
188 }
189 
191  const char * baseName, int scareMem)
192 {
193  return doLookup(cache, dirName, baseName, scareMem);
194 }
195 
197  /*@unused@*/ size_t size)
198 {
199  const fingerPrint * fp = (fingerPrint *) data;
200  const char * chptr = fp->baseName;
201  unsigned char ch = '\0';
202 
203  while (*chptr != '\0') ch ^= *chptr++;
204 
205  h |= ((unsigned)ch) << 24;
206  h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
207  h |= fp->entry->ino & 0xFFFF;
208 
209  return h;
210 }
211 
212 int fpEqual(const void * key1, const void * key2)
213 {
214  const fingerPrint *k1 = (fingerPrint *) key1;
215  const fingerPrint *k2 = (fingerPrint *) key2;
216 
217  /* If the addresses are the same, so are the values. */
218  if (k1 == k2)
219  return 0;
220 
221  /* Otherwise, compare fingerprints by value. */
222  /*@-nullpass@*/ /* LCL: whines about (*k2).subdir */
223  if (FP_EQUAL(*k1, *k2))
224  return 0;
225  /*@=nullpass@*/
226  return 1;
227 
228 }
229 
230 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
231  const char ** baseNames, const rpmuint32_t * dirIndexes,
232  rpmuint32_t fileCount, fingerPrint * fpList)
233 {
234  unsigned i;
235 
236  for (i = 0; i < (unsigned) fileCount; i++) {
237  /* If this is in the same directory as the last file, don't bother
238  redoing all of this work */
239  if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
240  fpList[i].entry = fpList[i - 1].entry;
241  fpList[i].subDir = fpList[i - 1].subDir;
242  fpList[i].baseName = baseNames[i];
243  } else {
244  fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
245  1);
246  }
247  }
248 }
249 
250 #ifdef NOTUSED
251 
258 static
259 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
260  /*@modifies h, cache, *fpList @*/
261 {
262  rpmTagData he_p = { .ptr = NULL };
263  HE_s he_s = { .tag = 0, .t = 0, .p = &he_p, .c = 0, .freeData = 0 };
264  HE_t he = &he_s;
265  const char ** baseNames;
266  const char ** dirNames;
267  rpmuint32_t * dirIndexes;
268  rpmTagCount fileCount;
269  int xx;
270 
271  he->tag = RPMTAG_BASENAMES;
272  xx = headerGet(h, he, 0);
273  baseNames = he_p.argv;
274  fileCount = he->c;
275  if (!xx)
276  return;
277 
278  he->tag = RPMTAG_DIRNAMES;
279  xx = headerGet(h, he, 0);
280  dirNames = he_p.argv;
281  he->tag = RPMTAG_DIRINDEXES;
282  xx = headerGet(h, he, 0);
283  dirIndexes = he_p.ui32p;
284 
285  fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
286 
287  dirIndexes = _free(dirIndexes);
288  dirNames = _free(dirNames);
289  baseNames = _free(baseNames);
290 }
291 #endif
292 
293 /* XXX fpLookupSubdir should be moved to lib/rpmfi.c somewhen. */
294 #define _RPMFI_INTERNAL
295 #include "rpmfi.h"
296 #define _RPMTE_INTERNAL
297 #include "rpmte.h"
298 
300  void * _p, int filenr)
301 {
302  rpmte p = (rpmte) _p;
303  rpmfi fi = p->fi;
304  fingerPrint *const fps = fi->fps + filenr;
305 
306  struct fingerPrint_s current_fp;
307  fingerPrint * cfp = &current_fp;
308  int symlinkcount = 0;
309 
310  const char * s;
311  const char * se;
312  size_t ns;
313  char * t;
314  char * te;
315 
316  struct rpmffi_s * ffi = (struct rpmffi_s *) xmalloc(sizeof(*ffi));
317  ffi->p = p;
318  ffi->fileno = filenr;
319 
320 restart:
321  *cfp = *fps;
322  if (cfp->subDir == NULL)
323  goto exit;
324 
325  s = cfp->baseName = te = xstrdup(cfp->subDir);
326  ns = strlen(s);
327  se = s + ns - 1;
328  cfp->subDir = t = NULL; /* no subDir for now */
329 
330  /* Set baseName to the upper most dir */
331  while (*te != '/' && te < se)
332  te++;
333  *te = '\0';
334 
335  while (te < se) {
336  struct rpmffi_s ** recs;
337  int numRecs;
338  int i;
339 
340  recs = NULL;
341  numRecs = 0;
342  (void) htGetEntry(symlinks, cfp, &recs, &numRecs, NULL);
343 
344  for (i = 0; i < numRecs; i++) {
345  const char * flink;
346  const char * link;
347  int fx;
348 
349  fx = recs[i]->fileno;
350  fi = recs[i]->p->fi;
351  flink = fi->flinks[fx];
352  if (!(flink && *flink != '\0'))
353  continue;
354 
355  /* Build a new (directory) fingerprint path. */
356  /* XXX Paths containing '%' will be macro expanded. */
357  if (*flink == '/')
358  link = rpmGetPath(flink, "/", te+1, "/", NULL);
359  else if (cfp->subDir == NULL)
360  link = rpmGetPath(cfp->entry->dirName, "/",
361  flink, "/", te+1, "/", NULL);
362  else
363  link = rpmGetPath(cfp->entry->dirName, "/", cfp->subDir, "/",
364  flink, "/", te+1, "/", NULL);
365 
366 #ifdef NOTNOW /* XXX avoid strlen on fast path */
367 assert(link[strlen(link)-1] == '/');
368 #endif
369 
370  /* Find the new (directory) fingerprint starting point. */
371  *fps = fpLookup(fpc, link, fps->baseName, 0);
372  link = _free(link);
373 
374  s = _free(s);
375  if (++symlinkcount > 50)
376  goto exit;
377  goto restart;
378  }
379 
380  if (cfp->subDir == NULL)
381  cfp->subDir = s;
382  else
383  *t = '/';
384  t = te;
385  cfp->baseName = t + 1;
386 
387  /* Set baseName to the next lower dir. */
388  te++;
389  while (*te != '\0' && *te != '/')
390  te++;
391  *te = '\0';
392 
393  }
394  s = _free(s);
395 
396 exit:
397  htAddEntry(fphash, fps, ffi);
398  return;
399 }
fingerPrint fpLookup(fingerPrintCache cache, const char *dirName, const char *baseName, int scareMem)
Return finger print of a file path.
Definition: fprint.c:190
rpmTag tag
Definition: rpmtag.h:504
const char ** argv
Definition: rpmtag.h:74
const char * baseName
Definition: fprint.h:57
static fingerPrint doLookup(fingerPrintCache cache, const char *dirName, const char *baseName, int scareMem)
Return finger print of a file path.
Definition: fprint.c:64
Structures used for an "rpmte" transaction element.
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
char * rpmCleanPath(char *path)
Canonicalize file path.
Definition: macro.c:3218
rpmuint32_t * ui32p
Definition: rpmtag.h:69
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3310
Structure(s) used for file info tag sets.
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2222
The Header data structure.
rpmuint32_t fpHashFunction(rpmuint32_t h, const void *data, size_t size)
Definition: fprint.c:196
static rpmlogRec recs
Definition: rpmlog.c:21
fingerPrintCache fpCacheFree(fingerPrintCache cache)
Destroy finger print cache.
Definition: fprint.c:31
struct rpmte_s * rpmte
An element of a transaction set, i.e.
Definition: rpmtypes.h:38
int htGetEntry(hashTable ht, const void *key, const void *data, int *dataCount, const void *tableKey)
Retrieve item from hash table.
Definition: rpmhash.c:188
char * alloca()
const char * subDir
Definition: fprint.h:55
#define FP_EQUAL(a, b)
Definition: fprint.h:66
unsigned int rpmuint32_t
Definition: rpmiotypes.h:25
void * ptr
Definition: rpmtag.h:66
static const struct fprintCacheEntry_s * cacheContainsDirectory(fingerPrintCache cache, const char *dirName)
Find directory name entry in cache.
Definition: fprint.c:44
struct rpmfi_s * rpmfi
File info tag sets from a header, so that a header can be discarded early.
Definition: rpmfi.h:78
char * stpncpy(char *dest, const char *src, size_t n)
hashTable htFree(hashTable ht)
Destroy hash table.
void fpLookupList(fingerPrintCache cache, const char **dirNames, const char **baseNames, const rpmuint32_t *dirIndexes, rpmuint32_t fileCount, fingerPrint *fpList)
Return finger prints of an array of file paths.
Definition: fprint.c:230
rpmTagCount c
Definition: rpmtag.h:508
int fpEqual(const void *key1, const void *key2)
Compare two finger print entries.
Definition: fprint.c:212
Identify a file name path by a unique "finger print".
Associates a trailing sub-directory and final base name with an existing directory finger print...
Definition: fprint.h:50
Definition: rpmtag.h:503
static const char * dirName
Definition: parsePrep.c:28
void htAddEntry(hashTable ht, const void *key, const void *data)
Add item to hash table.
Definition: rpmhash.c:150
const struct fprintCacheEntry_s * entry
Definition: fprint.h:52
struct fprintCache_s * fingerPrintCache
Definition: fprint.h:13
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
void fpLookupSubdir(hashTable symlinks, hashTable fphash, fingerPrintCache fpc, void *_p, int filenr)
Check file for to be installed symlinks in their path, correct their fingerprint and add it to newht...
Definition: fprint.c:299
#define xmalloc
Definition: system.h:33
Access RPM indices using Berkeley DB interface(s).
hashTable htCreate(int numBuckets, size_t keySize, int freeData, hashFunctionType fn, hashEqualityType eq)
Create hash table.
Definition: rpmhash.c:277
#define PATH_MAX
Definition: query.c:10
char * Realpath(const char *path, char *resolved_path)
realpath(3) clone.
Definition: rpmrpc.c:2330
rpmuint32_t rpmTagCount
Definition: rpmtag.h:54
fingerPrintCache fpCacheCreate(int sizeHint)
Create finger print cache.
Definition: fprint.c:21