rpm 5.2.1
|
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 #include "fprint.h" 00015 #include "debug.h" 00016 00017 /*@access hashTable @*/ 00018 00019 fingerPrintCache fpCacheCreate(int sizeHint) 00020 { 00021 fingerPrintCache fpc; 00022 00023 fpc = xmalloc(sizeof(*fpc)); 00024 fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL); 00025 assert(fpc->ht != NULL); 00026 return fpc; 00027 } 00028 00029 fingerPrintCache fpCacheFree(fingerPrintCache cache) 00030 { 00031 cache->ht = htFree(cache->ht); 00032 free(cache); 00033 return NULL; 00034 } 00035 00042 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory( 00043 fingerPrintCache cache, 00044 const char * dirName) 00045 /*@*/ 00046 { 00047 const void ** data; 00048 00049 if (htGetEntry(cache->ht, dirName, &data, NULL, NULL)) 00050 return NULL; 00051 return data[0]; 00052 } 00053 00062 static fingerPrint doLookup(fingerPrintCache cache, 00063 const char * dirName, const char * baseName, int scareMem) 00064 /*@globals fileSystem, internalState @*/ 00065 /*@modifies cache, fileSystem, internalState @*/ 00066 { 00067 char dir[PATH_MAX]; 00068 const char * cleanDirName; 00069 size_t cdnl; 00070 char * end; /* points to the '\0' at the end of "buf" */ 00071 fingerPrint fp; 00072 struct stat sb; 00073 char * buf; 00074 const struct fprintCacheEntry_s * cacheHit; 00075 00076 /* assert(*dirName == '/' || !scareMem); */ 00077 00078 /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */ 00079 cleanDirName = dirName; 00080 cdnl = strlen(cleanDirName); 00081 00082 if (*cleanDirName == '/') { 00083 if (!scareMem) 00084 cleanDirName = 00085 rpmCleanPath(strcpy(alloca(cdnl+1), dirName)); 00086 } else { 00087 scareMem = 0; /* XXX causes memory leak */ 00088 00089 /* Using realpath on the arg isn't correct if the arg is a symlink, 00090 * especially if the symlink is a dangling link. What we 00091 * do instead is use realpath() on `.' and then append arg to 00092 * the result. 00093 */ 00094 00095 /* if the current directory doesn't exist, we might fail. 00096 oh well. likewise if it's too long. */ 00097 dir[0] = '\0'; 00098 if (Realpath(".", dir) != NULL) { 00099 end = dir + strlen(dir); 00100 if (end[-1] != '/') *end++ = '/'; 00101 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir)); 00102 *end = '\0'; 00103 (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */ 00104 end = dir + strlen(dir); 00105 if (end[-1] != '/') *end++ = '/'; 00106 *end = '\0'; 00107 cleanDirName = dir; 00108 cdnl = end - dir; 00109 } 00110 } 00111 fp.entry = NULL; 00112 fp.subDir = NULL; 00113 fp.baseName = NULL; 00114 /*@-nullret@*/ 00115 if (cleanDirName == NULL) return fp; /* XXX can't happen */ 00116 /*@=nullret@*/ 00117 00118 buf = strcpy(alloca(cdnl + 1), cleanDirName); 00119 end = buf + cdnl; 00120 00121 /* no need to pay attention to that extra little / at the end of dirName */ 00122 if (buf[1] && end[-1] == '/') { 00123 end--; 00124 *end = '\0'; 00125 } 00126 00127 while (1) { 00128 00129 /* as we're stating paths here, we want to follow symlinks */ 00130 00131 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/")); 00132 if (cacheHit != NULL) { 00133 fp.entry = cacheHit; 00134 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) { 00135 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1; 00136 char * dn = xmalloc(nb); 00137 struct fprintCacheEntry_s * newEntry = (void *)dn; 00138 00139 /*@-usereleased@*/ /* LCL: contiguous malloc confusion */ 00140 dn += sizeof(*newEntry); 00141 strcpy(dn, (*buf != '\0' ? buf : "/")); 00142 newEntry->ino = (ino_t)sb.st_ino; 00143 newEntry->dev = (dev_t)sb.st_dev; 00144 newEntry->dirName = dn; 00145 fp.entry = newEntry; 00146 00147 /*@-kepttrans -dependenttrans @*/ 00148 htAddEntry(cache->ht, dn, fp.entry); 00149 /*@=kepttrans =dependenttrans @*/ 00150 /*@=usereleased@*/ 00151 } 00152 00153 if (fp.entry) { 00154 fp.subDir = cleanDirName + (end - buf); 00155 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0') 00156 fp.subDir++; 00157 if (fp.subDir[0] == '\0' || 00158 /* XXX don't bother saving '/' as subdir */ 00159 (fp.subDir[0] == '/' && fp.subDir[1] == '\0')) 00160 fp.subDir = NULL; 00161 fp.baseName = baseName; 00162 if (!scareMem && fp.subDir != NULL) 00163 fp.subDir = xstrdup(fp.subDir); 00164 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/ 00165 return fp; 00166 /*@=compdef@*/ 00167 } 00168 00169 /* stat of '/' just failed! */ 00170 if (end == buf + 1) 00171 abort(); 00172 00173 end--; 00174 while ((end > buf) && *end != '/') end--; 00175 if (end == buf) /* back to stat'ing just '/' */ 00176 end++; 00177 00178 *end = '\0'; 00179 } 00180 00181 /*@notreached@*/ 00182 00183 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/ 00184 /*@-nullret@*/ return fp; /*@=nullret@*/ /* LCL: can't happen. */ 00185 /*@=compdef@*/ 00186 } 00187 00188 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName, 00189 const char * baseName, int scareMem) 00190 { 00191 return doLookup(cache, dirName, baseName, scareMem); 00192 } 00193 00194 rpmuint32_t fpHashFunction(rpmuint32_t h, const void * data, 00195 /*@unused@*/ size_t size) 00196 { 00197 const fingerPrint * fp = data; 00198 const char * chptr = fp->baseName; 00199 unsigned char ch = '\0'; 00200 00201 while (*chptr != '\0') ch ^= *chptr++; 00202 00203 h |= ((unsigned)ch) << 24; 00204 h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16; 00205 h |= fp->entry->ino & 0xFFFF; 00206 00207 return h; 00208 } 00209 00210 int fpEqual(const void * key1, const void * key2) 00211 { 00212 const fingerPrint *k1 = key1; 00213 const fingerPrint *k2 = key2; 00214 00215 /* If the addresses are the same, so are the values. */ 00216 if (k1 == k2) 00217 return 0; 00218 00219 /* Otherwise, compare fingerprints by value. */ 00220 /*@-nullpass@*/ /* LCL: whines about (*k2).subdir */ 00221 if (FP_EQUAL(*k1, *k2)) 00222 return 0; 00223 /*@=nullpass@*/ 00224 return 1; 00225 00226 } 00227 00228 void fpLookupList(fingerPrintCache cache, const char ** dirNames, 00229 const char ** baseNames, const rpmuint32_t * dirIndexes, 00230 rpmuint32_t fileCount, fingerPrint * fpList) 00231 { 00232 unsigned i; 00233 00234 for (i = 0; i < (unsigned) fileCount; i++) { 00235 /* If this is in the same directory as the last file, don't bother 00236 redoing all of this work */ 00237 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) { 00238 fpList[i].entry = fpList[i - 1].entry; 00239 fpList[i].subDir = fpList[i - 1].subDir; 00240 fpList[i].baseName = baseNames[i]; 00241 } else { 00242 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i], 00243 1); 00244 } 00245 } 00246 } 00247 00248 #ifdef NOTUSED 00249 00256 static 00257 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList) 00258 /*@modifies h, cache, *fpList @*/ 00259 { 00260 rpmTagData he_p = { .ptr = NULL }; 00261 HE_s he_s = { .tag = 0, .t = 0, .p = &he_p, .c = 0, .freeData = 0 }; 00262 HE_t he = &he_s; 00263 const char ** baseNames; 00264 const char ** dirNames; 00265 rpmuint32_t * dirIndexes; 00266 rpmTagCount fileCount; 00267 int xx; 00268 00269 he->tag = RPMTAG_BASENAMES; 00270 xx = headerGet(h, he->tag, &he->t, he->p, &he->c); 00271 baseNames = he_p.argv; 00272 fileCount = he->c; 00273 if (!xx) 00274 return; 00275 00276 he->tag = RPMTAG_DIRNAMES; 00277 xx = headerGet(h, he, 0); 00278 dirNames = he_p.argv; 00279 he->tag = RPMTAG_DIRINDEXES; 00280 xx = headerGet(h, he, 0); 00281 dirIndexes = he_p.ui32p; 00282 00283 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList); 00284 00285 dirIndexes = _free(dirIndexes); 00286 dirNames = _free(dirNames); 00287 baseNames = _free(baseNames); 00288 } 00289 #endif