rpm  4.5
fprint.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <rpmdb.h>
8 #include <rpmmacro.h> /* XXX for rpmCleanPath */
9 
10 #include "fprint.h"
11 #include "debug.h"
12 
14 {
15  fingerPrintCache fpc;
16 
17  fpc = xmalloc(sizeof(*fpc));
18  fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL);
19  return fpc;
20 }
21 
23 {
24  cache->ht = htFree(cache->ht);
25  free(cache);
26  return NULL;
27 }
28 
35 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory(
36  fingerPrintCache cache,
37  const char * dirName)
38  /*@*/
39 {
40  const void ** data;
41 
42  if (htGetEntry(cache->ht, dirName, &data, NULL, NULL))
43  return NULL;
44 /*@-boundsread@*/
45  return data[0];
46 /*@=boundsread@*/
47 }
48 
57 /*@-bounds@*/ /* LCL: segfault */
59  const char * dirName, const char * baseName, int scareMem)
60  /*@modifies cache @*/
61 {
62  char dir[PATH_MAX];
63  const char * cleanDirName;
64  size_t cdnl;
65  char * end; /* points to the '\0' at the end of "buf" */
66  fingerPrint fp;
67  struct stat sb;
68  char * buf;
69  const struct fprintCacheEntry_s * cacheHit;
70 
71  /* assert(*dirName == '/' || !scareMem); */
72 
73  /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
74  cleanDirName = dirName;
75  cdnl = strlen(cleanDirName);
76 
77  if (*cleanDirName == '/') {
78  /*@-branchstate@*/
79  if (!scareMem)
80  cleanDirName =
81  rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
82  /*@=branchstate@*/
83  } else {
84  scareMem = 0; /* XXX causes memory leak */
85 
86  /* Using realpath on the arg isn't correct if the arg is a symlink,
87  * especially if the symlink is a dangling link. What we
88  * do instead is use realpath() on `.' and then append arg to
89  * the result.
90  */
91 
92  /* if the current directory doesn't exist, we might fail.
93  oh well. likewise if it's too long. */
94  dir[0] = '\0';
95  /*@-branchstate@*/
96  if (realpath(".", dir) != NULL) {
97  end = dir + strlen(dir);
98  if (end[-1] != '/') *end++ = '/';
99  end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
100  *end = '\0';
101  (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */
102  end = dir + strlen(dir);
103  if (end[-1] != '/') *end++ = '/';
104  *end = '\0';
105  cleanDirName = dir;
106  cdnl = end - dir;
107  }
108  /*@=branchstate@*/
109  }
110  fp.entry = NULL;
111  fp.subDir = NULL;
112  fp.baseName = NULL;
113  /*@-nullret@*/
114  if (cleanDirName == NULL) return fp; /* XXX can't happen */
115  /*@=nullret@*/
116 
117  buf = strcpy(alloca(cdnl + 1), cleanDirName);
118  end = buf + cdnl;
119 
120  /* no need to pay attention to that extra little / at the end of dirName */
121  if (buf[1] && end[-1] == '/') {
122  end--;
123  *end = '\0';
124  }
125 
126  while (1) {
127 
128  /* as we're stating paths here, we want to follow symlinks */
129 
130  cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
131  if (cacheHit != NULL) {
132  fp.entry = cacheHit;
133  } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
134  size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
135  char * dn = xmalloc(nb);
136  struct fprintCacheEntry_s * newEntry = (void *)dn;
137 
138  /*@-usereleased@*/ /* LCL: contiguous malloc confusion */
139  dn += sizeof(*newEntry);
140  strcpy(dn, (*buf != '\0' ? buf : "/"));
141  newEntry->ino = sb.st_ino;
142  newEntry->dev = sb.st_dev;
143  newEntry->dirName = dn;
144  fp.entry = newEntry;
145 
146  /*@-kepttrans -dependenttrans @*/
147  htAddEntry(cache->ht, dn, fp.entry);
148  /*@=kepttrans =dependenttrans @*/
149  /*@=usereleased@*/
150  }
151 
152  if (fp.entry) {
153  fp.subDir = cleanDirName + (end - buf);
154  if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
155  fp.subDir++;
156  if (fp.subDir[0] == '\0' ||
157  /* XXX don't bother saving '/' as subdir */
158  (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
159  fp.subDir = NULL;
160  fp.baseName = baseName;
161  if (!scareMem && fp.subDir != NULL)
162  fp.subDir = xstrdup(fp.subDir);
163  /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
164  return fp;
165  /*@=compdef@*/
166  }
167 
168  /* stat of '/' just failed! */
169  if (end == buf + 1)
170  abort();
171 
172  end--;
173  while ((end > buf) && *end != '/') end--;
174  if (end == buf) /* back to stat'ing just '/' */
175  end++;
176 
177  *end = '\0';
178  }
179 
180  /*@notreached@*/
181 
182  /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
183  /*@-nullret@*/ return fp; /*@=nullret@*/ /* LCL: can't happen. */
184  /*@=compdef@*/
185 }
186 /*@=bounds@*/
187 
189  const char * baseName, int scareMem)
190 {
191  return doLookup(cache, dirName, baseName, scareMem);
192 }
193 
194 uint32_t fpHashFunction(uint32_t h, const void * data, /*@unused@*/ size_t size)
195 {
196  const fingerPrint * fp = data;
197  const char * chptr = fp->baseName;
198  unsigned char ch = 0;
199 
200 /*@-boundsread@*/
201  while (*chptr != '\0') ch ^= *chptr++;
202 /*@=boundsread@*/
203 
204  h |= ((unsigned)ch) << 24;
205  h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
206  h |= fp->entry->ino & 0xFFFF;
207 
208  return h;
209 }
210 
211 /*@-boundsread@*/
212 int fpEqual(const void * key1, const void * key2)
213 {
214  const fingerPrint *k1 = key1;
215  const fingerPrint *k2 = 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 /*@=boundsread@*/
230 
231 /*@-bounds@*/
232 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
233  const char ** baseNames, const uint_32 * dirIndexes,
234  int fileCount, fingerPrint * fpList)
235 {
236  int i;
237 
238  for (i = 0; i < fileCount; i++) {
239  /* If this is in the same directory as the last file, don't bother
240  redoing all of this work */
241  if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
242  fpList[i].entry = fpList[i - 1].entry;
243  fpList[i].subDir = fpList[i - 1].subDir;
244  fpList[i].baseName = baseNames[i];
245  } else {
246  fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
247  1);
248  }
249  }
250 }
251 /*@=bounds@*/
252 
253 #ifdef UNUSED
254 
261 static
262 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
263  /*@modifies h, cache, *fpList @*/;
264 {
266  HFD_t hfd = headerFreeData;
267  const char ** baseNames, ** dirNames;
268  rpmTagType bnt, dnt;
269  int_32 * dirIndexes;
270  int fileCount;
271  int xx;
272 
273  if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
274  return;
275 
276  xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
277  xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
278  fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
279  dirNames = hfd(dirNames, dnt);
280  baseNames = hfd(baseNames, bnt);
281 }
282 #endif