rpm
4.5
|
00001 00005 #include "system.h" 00006 00007 #include <rpmdb.h> 00008 #include <rpmmacro.h> /* XXX for rpmCleanPath */ 00009 00010 #include "fprint.h" 00011 #include "debug.h" 00012 00013 fingerPrintCache fpCacheCreate(int sizeHint) 00014 { 00015 fingerPrintCache fpc; 00016 00017 fpc = xmalloc(sizeof(*fpc)); 00018 fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL); 00019 return fpc; 00020 } 00021 00022 fingerPrintCache fpCacheFree(fingerPrintCache cache) 00023 { 00024 cache->ht = htFree(cache->ht); 00025 free(cache); 00026 return NULL; 00027 } 00028 00035 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory( 00036 fingerPrintCache cache, 00037 const char * dirName) 00038 /*@*/ 00039 { 00040 const void ** data; 00041 00042 if (htGetEntry(cache->ht, dirName, &data, NULL, NULL)) 00043 return NULL; 00044 /*@-boundsread@*/ 00045 return data[0]; 00046 /*@=boundsread@*/ 00047 } 00048 00057 /*@-bounds@*/ /* LCL: segfault */ 00058 static fingerPrint doLookup(fingerPrintCache cache, 00059 const char * dirName, const char * baseName, int scareMem) 00060 /*@modifies cache @*/ 00061 { 00062 char dir[PATH_MAX]; 00063 const char * cleanDirName; 00064 size_t cdnl; 00065 char * end; /* points to the '\0' at the end of "buf" */ 00066 fingerPrint fp; 00067 struct stat sb; 00068 char * buf; 00069 const struct fprintCacheEntry_s * cacheHit; 00070 00071 /* assert(*dirName == '/' || !scareMem); */ 00072 00073 /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */ 00074 cleanDirName = dirName; 00075 cdnl = strlen(cleanDirName); 00076 00077 if (*cleanDirName == '/') { 00078 /*@-branchstate@*/ 00079 if (!scareMem) 00080 cleanDirName = 00081 rpmCleanPath(strcpy(alloca(cdnl+1), dirName)); 00082 /*@=branchstate@*/ 00083 } else { 00084 scareMem = 0; /* XXX causes memory leak */ 00085 00086 /* Using realpath on the arg isn't correct if the arg is a symlink, 00087 * especially if the symlink is a dangling link. What we 00088 * do instead is use realpath() on `.' and then append arg to 00089 * the result. 00090 */ 00091 00092 /* if the current directory doesn't exist, we might fail. 00093 oh well. likewise if it's too long. */ 00094 dir[0] = '\0'; 00095 /*@-branchstate@*/ 00096 if (realpath(".", dir) != NULL) { 00097 end = dir + strlen(dir); 00098 if (end[-1] != '/') *end++ = '/'; 00099 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir)); 00100 *end = '\0'; 00101 (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */ 00102 end = dir + strlen(dir); 00103 if (end[-1] != '/') *end++ = '/'; 00104 *end = '\0'; 00105 cleanDirName = dir; 00106 cdnl = end - dir; 00107 } 00108 /*@=branchstate@*/ 00109 } 00110 fp.entry = NULL; 00111 fp.subDir = NULL; 00112 fp.baseName = NULL; 00113 /*@-nullret@*/ 00114 if (cleanDirName == NULL) return fp; /* XXX can't happen */ 00115 /*@=nullret@*/ 00116 00117 buf = strcpy(alloca(cdnl + 1), cleanDirName); 00118 end = buf + cdnl; 00119 00120 /* no need to pay attention to that extra little / at the end of dirName */ 00121 if (buf[1] && end[-1] == '/') { 00122 end--; 00123 *end = '\0'; 00124 } 00125 00126 while (1) { 00127 00128 /* as we're stating paths here, we want to follow symlinks */ 00129 00130 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/")); 00131 if (cacheHit != NULL) { 00132 fp.entry = cacheHit; 00133 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) { 00134 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1; 00135 char * dn = xmalloc(nb); 00136 struct fprintCacheEntry_s * newEntry = (void *)dn; 00137 00138 /*@-usereleased@*/ /* LCL: contiguous malloc confusion */ 00139 dn += sizeof(*newEntry); 00140 strcpy(dn, (*buf != '\0' ? buf : "/")); 00141 newEntry->ino = sb.st_ino; 00142 newEntry->dev = sb.st_dev; 00143 newEntry->dirName = dn; 00144 fp.entry = newEntry; 00145 00146 /*@-kepttrans -dependenttrans @*/ 00147 htAddEntry(cache->ht, dn, fp.entry); 00148 /*@=kepttrans =dependenttrans @*/ 00149 /*@=usereleased@*/ 00150 } 00151 00152 if (fp.entry) { 00153 fp.subDir = cleanDirName + (end - buf); 00154 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0') 00155 fp.subDir++; 00156 if (fp.subDir[0] == '\0' || 00157 /* XXX don't bother saving '/' as subdir */ 00158 (fp.subDir[0] == '/' && fp.subDir[1] == '\0')) 00159 fp.subDir = NULL; 00160 fp.baseName = baseName; 00161 if (!scareMem && fp.subDir != NULL) 00162 fp.subDir = xstrdup(fp.subDir); 00163 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/ 00164 return fp; 00165 /*@=compdef@*/ 00166 } 00167 00168 /* stat of '/' just failed! */ 00169 if (end == buf + 1) 00170 abort(); 00171 00172 end--; 00173 while ((end > buf) && *end != '/') end--; 00174 if (end == buf) /* back to stat'ing just '/' */ 00175 end++; 00176 00177 *end = '\0'; 00178 } 00179 00180 /*@notreached@*/ 00181 00182 /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/ 00183 /*@-nullret@*/ return fp; /*@=nullret@*/ /* LCL: can't happen. */ 00184 /*@=compdef@*/ 00185 } 00186 /*@=bounds@*/ 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 uint32_t fpHashFunction(uint32_t h, const void * data, /*@unused@*/ size_t size) 00195 { 00196 const fingerPrint * fp = data; 00197 const char * chptr = fp->baseName; 00198 unsigned char ch = 0; 00199 00200 /*@-boundsread@*/ 00201 while (*chptr != '\0') ch ^= *chptr++; 00202 /*@=boundsread@*/ 00203 00204 h |= ((unsigned)ch) << 24; 00205 h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16; 00206 h |= fp->entry->ino & 0xFFFF; 00207 00208 return h; 00209 } 00210 00211 /*@-boundsread@*/ 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 /*@=boundsread@*/ 00230 00231 /*@-bounds@*/ 00232 void fpLookupList(fingerPrintCache cache, const char ** dirNames, 00233 const char ** baseNames, const uint_32 * dirIndexes, 00234 int fileCount, fingerPrint * fpList) 00235 { 00236 int i; 00237 00238 for (i = 0; i < fileCount; i++) { 00239 /* If this is in the same directory as the last file, don't bother 00240 redoing all of this work */ 00241 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) { 00242 fpList[i].entry = fpList[i - 1].entry; 00243 fpList[i].subDir = fpList[i - 1].subDir; 00244 fpList[i].baseName = baseNames[i]; 00245 } else { 00246 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i], 00247 1); 00248 } 00249 } 00250 } 00251 /*@=bounds@*/ 00252 00253 #ifdef UNUSED 00254 00261 static 00262 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList) 00263 /*@modifies h, cache, *fpList @*/; 00264 { 00265 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 00266 HFD_t hfd = headerFreeData; 00267 const char ** baseNames, ** dirNames; 00268 rpmTagType bnt, dnt; 00269 int_32 * dirIndexes; 00270 int fileCount; 00271 int xx; 00272 00273 if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount)) 00274 return; 00275 00276 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL); 00277 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL); 00278 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList); 00279 dirNames = hfd(dirNames, dnt); 00280 baseNames = hfd(baseNames, bnt); 00281 } 00282 #endif