00001
00005 #include "system.h"
00006
00007 #include <rpmmacro.h>
00008 #include <rpmdb.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 return data[0];
00045 }
00046
00055 static fingerPrint doLookup(fingerPrintCache cache,
00056 const char * dirName, const char * baseName, int scareMem)
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 if (!scareMem)
00076 cleanDirName =
00077 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
00078 } else {
00079 scareMem = 0;
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 dir[0] = '\0';
00090 if (realpath(".", dir) != NULL) {
00091 end = dir + strlen(dir);
00092 if (end[-1] != '/') *end++ = '/';
00093 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
00094 *end = '\0';
00095 (void)rpmCleanPath(dir);
00096 end = dir + strlen(dir);
00097 if (end[-1] != '/') *end++ = '/';
00098 *end = '\0';
00099 cleanDirName = dir;
00100 cdnl = end - dir;
00101 }
00102 }
00103 fp.entry = NULL;
00104 fp.subDir = NULL;
00105 fp.baseName = NULL;
00106
00107 if (cleanDirName == NULL) return fp;
00108
00109
00110 buf = strcpy(alloca(cdnl + 1), cleanDirName);
00111 end = buf + cdnl;
00112
00113
00114 if (buf[1] && end[-1] == '/') {
00115 end--;
00116 *end = '\0';
00117 }
00118
00119 while (1) {
00120
00121
00122
00123 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
00124 if (cacheHit != NULL) {
00125 fp.entry = cacheHit;
00126 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
00127 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
00128 char * dn = xmalloc(nb);
00129 struct fprintCacheEntry_s * newEntry = (void *)dn;
00130
00131
00132 dn += sizeof(*newEntry);
00133 strcpy(dn, (*buf != '\0' ? buf : "/"));
00134 newEntry->ino = sb.st_ino;
00135 newEntry->dev = sb.st_dev;
00136 newEntry->dirName = dn;
00137 fp.entry = newEntry;
00138
00139
00140 htAddEntry(cache->ht, dn, fp.entry);
00141
00142
00143 }
00144
00145 if (fp.entry) {
00146 fp.subDir = cleanDirName + (end - buf);
00147 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
00148 fp.subDir++;
00149 if (fp.subDir[0] == '\0' ||
00150
00151 (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
00152 fp.subDir = NULL;
00153 fp.baseName = baseName;
00154 if (!scareMem && fp.subDir != NULL)
00155 fp.subDir = xstrdup(fp.subDir);
00156
00157 return fp;
00158
00159 }
00160
00161
00162 if (end == buf + 1)
00163 abort();
00164
00165 end--;
00166 while ((end > buf) && *end != '/') end--;
00167 if (end == buf)
00168 end++;
00169
00170 *end = '\0';
00171 }
00172
00173
00174
00175
00176 return fp;
00177
00178 }
00179
00180 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName,
00181 const char * baseName, int scareMem)
00182 {
00183 return doLookup(cache, dirName, baseName, scareMem);
00184 }
00185
00186 uint32_t fpHashFunction(uint32_t h, const void * data, size_t size)
00187 {
00188 const fingerPrint * fp = data;
00189 const char * chptr = fp->baseName;
00190 unsigned char ch = '\0';
00191
00192 while (*chptr != '\0') ch ^= *chptr++;
00193
00194 h |= ((unsigned)ch) << 24;
00195 h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
00196 h |= fp->entry->ino & 0xFFFF;
00197
00198 return h;
00199 }
00200
00201 int fpEqual(const void * key1, const void * key2)
00202 {
00203 const fingerPrint *k1 = key1;
00204 const fingerPrint *k2 = key2;
00205
00206
00207 if (k1 == k2)
00208 return 0;
00209
00210
00211
00212 if (FP_EQUAL(*k1, *k2))
00213 return 0;
00214
00215 return 1;
00216
00217 }
00218
00219 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
00220 const char ** baseNames, const uint32_t * dirIndexes,
00221 uint32_t fileCount, fingerPrint * fpList)
00222 {
00223 unsigned i;
00224
00225 for (i = 0; i < (unsigned) fileCount; i++) {
00226
00227
00228 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
00229 fpList[i].entry = fpList[i - 1].entry;
00230 fpList[i].subDir = fpList[i - 1].subDir;
00231 fpList[i].baseName = baseNames[i];
00232 } else {
00233 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
00234 1);
00235 }
00236 }
00237 }
00238
00239 #ifdef UNUSED
00240
00247 static
00248 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
00249 ;
00250 {
00251 rpmTagData he_p = { .ptr = NULL };
00252 HE_s he_s = { .tag = 0, .t = 0, .p = &he_p, .c = 0, .freeData = 0 };
00253 HE_t he = &he_s;
00254 const char ** baseNames;
00255 const char ** dirNames;
00256 uint32_t * dirIndexes;
00257 rpmTagCount fileCount;
00258 int xx;
00259
00260 he->tag = RPMTAG_BASENAMES;
00261 xx = headerGet(h, he->tag, &he->t, he->p, &he->c);
00262 baseNames = he_p.argv;
00263 fileCount = he->c;
00264 if (!xx)
00265 return;
00266
00267 he->tag = RPMTAG_DIRNAMES;
00268 xx = headerGet(h, he, 0);
00269 dirNames = he_p.argv;
00270 he->tag = RPMTAG_DIRINDEXES;
00271 xx = headerGet(h, he, 0);
00272 dirIndexes = he_p.ui32p;
00273
00274 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
00275
00276 dirIndexes = _free(dirIndexes);
00277 dirNames = _free(dirNames);
00278 baseNames = _free(baseNames);
00279 }
00280 #endif