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