rpm  5.2.1
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 
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 
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 
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 
189  const char * baseName, int scareMem)
190 {
191  return doLookup(cache, dirName, baseName, scareMem);
192 }
193 
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