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