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, hashFunctionString,
00019 hashEqualityString);
00020 return fpc;
00021 }
00022
00023 void fpCacheFree(fingerPrintCache cache)
00024 {
00025 htFree(cache->ht);
00026 free(cache);
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 return data[0];
00045 }
00046
00055 static fingerPrint doLookup(fingerPrintCache cache,
00056 const char * dirName, const char * baseName, int scareMemory)
00057
00058 {
00059 char dir[PATH_MAX];
00060 const char * cleanDirName;
00061 size_t cdnl;
00062 char * end;
00063 fingerPrint fp;
00064 struct stat sb;
00065 char * buf;
00066 const struct fprintCacheEntry_s * cacheHit;
00067
00068
00069
00070
00071 cleanDirName = dirName;
00072 cdnl = strlen(cleanDirName);
00073
00074 if (*cleanDirName == '/') {
00075
00076 if (!scareMemory)
00077 cleanDirName =
00078 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
00079
00080 } else {
00081 scareMemory = 0;
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 dir[0] = '\0';
00092
00093 if (realpath(".", dir) != NULL) {
00094 end = dir + strlen(dir);
00095 if (end[-1] != '/') *end++ = '/';
00096 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
00097 *end = '\0';
00098 (void)rpmCleanPath(dir);
00099 end = dir + strlen(dir);
00100 if (end[-1] != '/') *end++ = '/';
00101 *end = '\0';
00102 cleanDirName = dir;
00103 cdnl = end - dir;
00104 }
00105
00106 }
00107 fp.entry = NULL;
00108 fp.subDir = NULL;
00109 fp.baseName = NULL;
00110
00111 if (cleanDirName == NULL) return fp;
00112
00113
00114 buf = strcpy(alloca(cdnl + 1), cleanDirName);
00115 end = buf + cdnl;
00116
00117
00118 if (buf[1] && end[-1] == '/') {
00119 end--;
00120 *end = '\0';
00121 }
00122
00123 while (1) {
00124
00125
00126
00127 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
00128 if (cacheHit != NULL) {
00129 fp.entry = cacheHit;
00130 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
00131 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
00132 char * dn = xmalloc(nb);
00133 struct fprintCacheEntry_s * newEntry = (void *)dn;
00134
00135
00136 dn += sizeof(*newEntry);
00137 strcpy(dn, (*buf != '\0' ? buf : "/"));
00138 newEntry->ino = sb.st_ino;
00139 newEntry->dev = sb.st_dev;
00140 newEntry->isFake = 0;
00141 newEntry->dirName = dn;
00142 fp.entry = newEntry;
00143
00144
00145 htAddEntry(cache->ht, dn, fp.entry);
00146
00147
00148 }
00149
00150 if (fp.entry) {
00151 fp.subDir = cleanDirName + (end - buf);
00152 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
00153 fp.subDir++;
00154 if (fp.subDir[0] == '\0' ||
00155
00156 (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
00157 fp.subDir = NULL;
00158 fp.baseName = baseName;
00159 if (!scareMemory && fp.subDir != NULL)
00160 fp.subDir = xstrdup(fp.subDir);
00161
00162 return fp;
00163
00164 }
00165
00166
00167 if (end == buf + 1)
00168 abort();
00169
00170 end--;
00171 while ((end > buf) && *end != '/') end--;
00172 if (end == buf)
00173 end++;
00174
00175 *end = '\0';
00176 }
00177
00178
00179
00180
00181 return fp;
00182
00183 }
00184
00185 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName,
00186 const char * baseName, int scareMemory)
00187 {
00188 return doLookup(cache, dirName, baseName, scareMemory);
00189 }
00190
00191 unsigned int fpHashFunction(const void * key)
00192 {
00193 const fingerPrint * fp = key;
00194 unsigned int hash = 0;
00195 char ch;
00196 const char * chptr;
00197
00198 ch = 0;
00199 chptr = fp->baseName;
00200 while (*chptr != '\0') ch ^= *chptr++;
00201
00202 hash |= ((unsigned)ch) << 24;
00203 hash |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
00204 hash |= fp->entry->ino & 0xFFFF;
00205
00206 return hash;
00207 }
00208
00209 int fpEqual(const void * key1, const void * key2)
00210 {
00211 const fingerPrint *k1 = key1;
00212 const fingerPrint *k2 = key2;
00213
00214
00215 if (k1 == k2)
00216 return 0;
00217
00218
00219
00220 if (FP_EQUAL(*k1, *k2))
00221 return 0;
00222
00223 return 1;
00224
00225 }
00226
00227 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
00228 const char ** baseNames, const int * dirIndexes,
00229 int fileCount, fingerPrint * fpList)
00230 {
00231 int i;
00232
00233 for (i = 0; i < fileCount; i++) {
00234
00235
00236 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
00237 fpList[i].entry = fpList[i - 1].entry;
00238 fpList[i].subDir = fpList[i - 1].subDir;
00239 fpList[i].baseName = baseNames[i];
00240 } else {
00241 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
00242 1);
00243 }
00244 }
00245 }
00246
00247 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
00248 {
00249 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00250 HFD_t hfd = headerFreeData;
00251 const char ** baseNames, ** dirNames;
00252 rpmTagType bnt, dnt;
00253 int_32 * dirIndexes;
00254 int fileCount;
00255 int xx;
00256
00257 if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
00258 return;
00259
00260 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
00261 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00262 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
00263 dirNames = hfd(dirNames, dnt);
00264 baseNames = hfd(baseNames, bnt);
00265 }