00001
00005 #include "system.h"
00006
00007 #include <rpmdb.h>
00008 #include <rpmmacro.h>
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 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
00045 return data[0];
00046
00047 }
00048
00057
00058 static fingerPrint doLookup(fingerPrintCache cache,
00059 const char * dirName, const char * baseName, int scareMem)
00060
00061 {
00062 char dir[PATH_MAX];
00063 const char * cleanDirName;
00064 size_t cdnl;
00065 char * end;
00066 fingerPrint fp;
00067 struct stat sb;
00068 char * buf;
00069 const struct fprintCacheEntry_s * cacheHit;
00070
00071
00072
00073
00074 cleanDirName = dirName;
00075 cdnl = strlen(cleanDirName);
00076
00077 if (*cleanDirName == '/') {
00078
00079 if (!scareMem)
00080 cleanDirName =
00081 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
00082
00083 } else {
00084 scareMem = 0;
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 dir[0] = '\0';
00095
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);
00102 end = dir + strlen(dir);
00103 if (end[-1] != '/') *end++ = '/';
00104 *end = '\0';
00105 cleanDirName = dir;
00106 cdnl = end - dir;
00107 }
00108
00109 }
00110 fp.entry = NULL;
00111 fp.subDir = NULL;
00112 fp.baseName = NULL;
00113
00114 if (cleanDirName == NULL) return fp;
00115
00116
00117 buf = strcpy(alloca(cdnl + 1), cleanDirName);
00118 end = buf + cdnl;
00119
00120
00121 if (buf[1] && end[-1] == '/') {
00122 end--;
00123 *end = '\0';
00124 }
00125
00126 while (1) {
00127
00128
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
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
00147 htAddEntry(cache->ht, dn, fp.entry);
00148
00149
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
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
00164 return fp;
00165
00166 }
00167
00168
00169 if (end == buf + 1)
00170 abort();
00171
00172 end--;
00173 while ((end > buf) && *end != '/') end--;
00174 if (end == buf)
00175 end++;
00176
00177 *end = '\0';
00178 }
00179
00180
00181
00182
00183 return fp;
00184
00185 }
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 uint32_t fpHashFunction(uint32_t h, const void * data, size_t size)
00195 {
00196 const fingerPrint * fp = data;
00197 const char * chptr = fp->baseName;
00198 unsigned char ch = 0;
00199
00200
00201 while (*chptr != '\0') ch ^= *chptr++;
00202
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
00212 int fpEqual(const void * key1, const void * key2)
00213 {
00214 const fingerPrint *k1 = key1;
00215 const fingerPrint *k2 = key2;
00216
00217
00218 if (k1 == k2)
00219 return 0;
00220
00221
00222
00223 if (FP_EQUAL(*k1, *k2))
00224 return 0;
00225
00226 return 1;
00227
00228 }
00229
00230
00231
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
00240
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
00252
00253 #ifdef UNUSED
00254
00261 static
00262 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
00263 ;
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