rpm 5.3.12
|
00001 00005 #include "system.h" 00006 00007 #include <rpmiotypes.h> /* XXX rpmRC codes. */ 00008 #include <rpmio.h> /* XXX Realpath(). */ 00009 #include <rpmmacro.h> /* XXX for rpmCleanPath */ 00010 00011 #include <rpmtag.h> 00012 #include <rpmdb.h> 00013 00014 #define _FPRINT_INTERNAL 00015 #include "fprint.h" 00016 00017 #include "debug.h" 00018 00019 /*@access hashTable @*/ 00020 00021 fingerPrintCache fpCacheCreate(int sizeHint) 00022 { 00023 fingerPrintCache fpc; 00024 00025 fpc = xmalloc(sizeof(*fpc)); 00026 fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL); 00027 assert(fpc->ht != NULL); 00028 return fpc; 00029 } 00030 00031 fingerPrintCache fpCacheFree(fingerPrintCache cache) 00032 { 00033 cache->ht = htFree(cache->ht); 00034 free(cache); 00035 return NULL; 00036 } 00037 00044 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory( 00045 fingerPrintCache cache, 00046 const char * dirName) 00047 /*@*/ 00048 { 00049 const void ** data; 00050 00051 if (htGetEntry(cache->ht, dirName, &data, NULL, NULL)) 00052 return NULL; 00053 return data[0]; 00054 } 00055 00064 static fingerPrint doLookup(fingerPrintCache cache, 00065 const char * dirName, const char * baseName, int scareMem) 00066 /*@globals fileSystem, internalState @*/ 00067 /*@modifies cache, fileSystem, internalState @*/ 00068 { 00069 char dir[PATH_MAX]; 00070 const char * cleanDirName; 00071 size_t cdnl; 00072 char * end; /* points to the '\0' at the end of "buf" */ 00073 fingerPrint fp; 00074 struct stat sb; 00075 char * buf; 00076 const struct fprintCacheEntry_s * cacheHit; 00077 00078 /* assert(*dirName == '/' || !scareMem); */ 00079 00080 /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */ 00081 cleanDirName = dirName; 00082 cdnl = strlen(cleanDirName); 00083 00084 if (*cleanDirName == '/') { 00085 if (!scareMem) 00086 cleanDirName = 00087 rpmCleanPath(strcpy(alloca(cdnl+1), dirName)); 00088 } else { 00089 scareMem = 0; /* XXX causes memory leak */ 00090 00091 /* Using realpath on the arg isn't correct if the arg is a symlink, 00092 * especially if the symlink is a dangling link. What we 00093 * do instead is use realpath() on `.' and then append arg to 00094 * the result. 00095 */ 00096 00097 /* if the current directory doesn't exist, we might fail. 00098 oh well. likewise if it's too long. */ 00099 dir[0] = '\0'; 00100 if (Realpath(".", dir) != NULL) { 00101 end = dir + strlen(dir); 00102 if (end[-1] != '/') *end++ = '/'; 00103 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir)); 00104 *end = '\0'; 00105 (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */ 00106 end = dir + strlen(dir); 00107 if (end[-1] != '/') *end++ = '/'; 00108 *end = '\0'; 00109 cleanDirName = dir; 00110 cdnl = end - dir; 00111 } 00112 } 00113 fp.entry = NULL; 00114 fp.subDir = NULL; 00115 fp.baseName = NULL; 00116 /*@-nullret@*/ 00117 if (cleanDirName == NULL) return fp; /* XXX can't happen */ 00118 /*@=nullret@*/ 00119 00120 buf = strcpy(alloca(cdnl + 1), cleanDirName); 00121 end = buf + cdnl; 00122 00123 /* no need to pay attention to that extra little / at the end of dirName */ 00124 if (buf[1] && end[-1] == '/') { 00125 end--; 00126 *end = '\0'; 00127 } 00128 00129 while (1) { 00130 00131 /* as we're stating paths here, we want to follow symlinks */ 00132 00133 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/")); 00134 if (cacheHit != NULL) { 00135 fp.entry = cacheHit; 00136 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) { 00137 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1; 00138 char * dn = xmalloc(nb); 00139 struct fprintCacheEntry_s * newEntry = (void *)dn; 00140 00141 /*@-usereleased@*/ /* LCL: contiguous malloc confusion */ 00142 dn += sizeof(*newEntry); 00143 strcpy(dn, (*buf != '\0' ? buf : "/")); 00144 newEntry->ino = (ino_t)sb.st_ino; 00145 newEntry->dev = (dev_t)sb.st_dev; 00146 newEntry->dirName = dn; 00147 fp.entry = newEntry; 00148 00149 /*@-kepttrans -dependenttrans @*/ 00150 htAddEntry(cache->ht, dn, fp.entry); 00151 /*@=kepttrans =dependenttrans @*/ 00152 /*@=usereleased@*/ 00153 } 00154 00155 if (fp.entry) { 00156 fp.subDir = cleanDirName + (end - buf); 00157 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0') 00158 fp.subDir++; 00159 if (fp.subDir[0] == '\0' || 00160 /* XXX don't bother saving '/' as subdir */ 00161 (fp.subDir[0] == '/' && fp.subDir[1] == '\0')) 00162 fp.subDir = NULL; 00163 fp.baseName = baseName; 00164 if (!scareMem && fp.subDir != NULL) 00165 fp.subDir = xstrdup(fp.subDir); 00166 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/ 00167 return fp; 00168 /*@=compdef@*/ 00169 } 00170 00171 /* stat of '/' just failed! */ 00172 if (end == buf + 1) 00173 abort(); 00174 00175 end--; 00176 while ((end > buf) && *end != '/') end--; 00177 if (end == buf) /* back to stat'ing just '/' */ 00178 end++; 00179 00180 *end = '\0'; 00181 } 00182 00183 /*@notreached@*/ 00184 00185 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/ 00186 /*@-nullret@*/ return fp; /*@=nullret@*/ /* LCL: can't happen. */ 00187 /*@=compdef@*/ 00188 } 00189 00190 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName, 00191 const char * baseName, int scareMem) 00192 { 00193 return doLookup(cache, dirName, baseName, scareMem); 00194 } 00195 00196 rpmuint32_t fpHashFunction(rpmuint32_t h, const void * data, 00197 /*@unused@*/ size_t size) 00198 { 00199 const fingerPrint * fp = data; 00200 const char * chptr = fp->baseName; 00201 unsigned char ch = '\0'; 00202 00203 while (*chptr != '\0') ch ^= *chptr++; 00204 00205 h |= ((unsigned)ch) << 24; 00206 h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16; 00207 h |= fp->entry->ino & 0xFFFF; 00208 00209 return h; 00210 } 00211 00212 int fpEqual(const void * key1, const void * key2) 00213 { 00214 const fingerPrint *k1 = key1; 00215 const fingerPrint *k2 = key2; 00216 00217 /* If the addresses are the same, so are the values. */ 00218 if (k1 == k2) 00219 return 0; 00220 00221 /* Otherwise, compare fingerprints by value. */ 00222 /*@-nullpass@*/ /* LCL: whines about (*k2).subdir */ 00223 if (FP_EQUAL(*k1, *k2)) 00224 return 0; 00225 /*@=nullpass@*/ 00226 return 1; 00227 00228 } 00229 00230 void fpLookupList(fingerPrintCache cache, const char ** dirNames, 00231 const char ** baseNames, const rpmuint32_t * dirIndexes, 00232 rpmuint32_t fileCount, fingerPrint * fpList) 00233 { 00234 unsigned i; 00235 00236 for (i = 0; i < (unsigned) fileCount; i++) { 00237 /* If this is in the same directory as the last file, don't bother 00238 redoing all of this work */ 00239 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) { 00240 fpList[i].entry = fpList[i - 1].entry; 00241 fpList[i].subDir = fpList[i - 1].subDir; 00242 fpList[i].baseName = baseNames[i]; 00243 } else { 00244 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i], 00245 1); 00246 } 00247 } 00248 } 00249 00250 #ifdef NOTUSED 00251 00258 static 00259 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList) 00260 /*@modifies h, cache, *fpList @*/ 00261 { 00262 rpmTagData he_p = { .ptr = NULL }; 00263 HE_s he_s = { .tag = 0, .t = 0, .p = &he_p, .c = 0, .freeData = 0 }; 00264 HE_t he = &he_s; 00265 const char ** baseNames; 00266 const char ** dirNames; 00267 rpmuint32_t * dirIndexes; 00268 rpmTagCount fileCount; 00269 int xx; 00270 00271 he->tag = RPMTAG_BASENAMES; 00272 xx = headerGet(h, he, 0); 00273 baseNames = he_p.argv; 00274 fileCount = he->c; 00275 if (!xx) 00276 return; 00277 00278 he->tag = RPMTAG_DIRNAMES; 00279 xx = headerGet(h, he, 0); 00280 dirNames = he_p.argv; 00281 he->tag = RPMTAG_DIRINDEXES; 00282 xx = headerGet(h, he, 0); 00283 dirIndexes = he_p.ui32p; 00284 00285 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList); 00286 00287 dirIndexes = _free(dirIndexes); 00288 dirNames = _free(dirNames); 00289 baseNames = _free(baseNames); 00290 } 00291 #endif 00292 00293 /* XXX fpLookupSubdir should be moved to lib/rpmfi.c somewhen. */ 00294 #define _RPMFI_INTERNAL 00295 #include "rpmfi.h" 00296 #define _RPMTE_INTERNAL 00297 #include "rpmte.h" 00298 00299 void fpLookupSubdir(hashTable symlinks, hashTable fphash, fingerPrintCache fpc, 00300 void * _p, int filenr) 00301 { 00302 rpmte p = _p; 00303 rpmfi fi = p->fi; 00304 fingerPrint *const fps = fi->fps + filenr; 00305 00306 struct fingerPrint_s current_fp; 00307 fingerPrint * cfp = ¤t_fp; 00308 int symlinkcount = 0; 00309 00310 const char * s; 00311 const char * se; 00312 size_t ns; 00313 char * t; 00314 char * te; 00315 00316 struct rpmffi_s * ffi = xmalloc(sizeof(*ffi)); 00317 ffi->p = p; 00318 ffi->fileno = filenr; 00319 00320 restart: 00321 *cfp = *fps; 00322 if (cfp->subDir == NULL) 00323 goto exit; 00324 00325 s = cfp->baseName = te = xstrdup(cfp->subDir); 00326 ns = strlen(s); 00327 se = s + ns - 1; 00328 cfp->subDir = t = NULL; /* no subDir for now */ 00329 00330 /* Set baseName to the upper most dir */ 00331 while (*te != '/' && te < se) 00332 te++; 00333 *te = '\0'; 00334 00335 while (te < se) { 00336 struct rpmffi_s ** recs; 00337 int numRecs; 00338 int i; 00339 00340 recs = NULL; 00341 numRecs = 0; 00342 (void) htGetEntry(symlinks, cfp, &recs, &numRecs, NULL); 00343 00344 for (i = 0; i < numRecs; i++) { 00345 const char * flink; 00346 const char * link; 00347 int fx; 00348 00349 fx = recs[i]->fileno; 00350 fi = recs[i]->p->fi; 00351 flink = fi->flinks[fx]; 00352 if (!(flink && *flink != '\0')) 00353 continue; 00354 00355 /* Build a new (directory) fingerprint path. */ 00356 /* XXX Paths containing '%' will be macro expanded. */ 00357 if (*flink == '/') 00358 link = rpmGetPath(flink, "/", te+1, "/", NULL); 00359 else if (cfp->subDir == NULL) 00360 link = rpmGetPath(cfp->entry->dirName, "/", 00361 flink, "/", te+1, "/", NULL); 00362 else 00363 link = rpmGetPath(cfp->entry->dirName, "/", cfp->subDir, "/", 00364 flink, "/", te+1, "/", NULL); 00365 00366 #ifdef NOTNOW /* XXX avoid strlen on fast path */ 00367 assert(link[strlen(link)-1] == '/'); 00368 #endif 00369 00370 /* Find the new (directory) fingerprint starting point. */ 00371 *fps = fpLookup(fpc, link, fps->baseName, 0); 00372 link = _free(link); 00373 00374 s = _free(s); 00375 if (++symlinkcount > 50) 00376 goto exit; 00377 goto restart; 00378 } 00379 00380 if (cfp->subDir == NULL) 00381 cfp->subDir = s; 00382 else 00383 *t = '/'; 00384 t = te; 00385 cfp->baseName = t + 1; 00386 00387 /* Set baseName to the next lower dir. */ 00388 te++; 00389 while (*te != '\0' && *te != '/') 00390 te++; 00391 *te = '\0'; 00392 00393 } 00394 s = _free(s); 00395 00396 exit: 00397 htAddEntry(fphash, fps, ffi); 00398 return; 00399 }