00001
00005 #include "system.h"
00006
00007 #include <rpmiotypes.h>
00008 #include <rpmio.h>
00009 #include <rpmmacro.h>
00010
00011 #include <rpmtag.h>
00012 #include <rpmdb.h>
00013
00014 #include "fprint.h"
00015 #include "debug.h"
00016
00017
00018
00019 fingerPrintCache fpCacheCreate(int sizeHint)
00020 {
00021 fingerPrintCache fpc;
00022
00023 fpc = xmalloc(sizeof(*fpc));
00024 fpc->ht = htCreate(sizeHint * 2, 0, 1, NULL, NULL);
00025 assert(fpc->ht != NULL);
00026 return fpc;
00027 }
00028
00029 fingerPrintCache fpCacheFree(fingerPrintCache cache)
00030 {
00031 cache->ht = htFree(cache->ht);
00032 free(cache);
00033 return NULL;
00034 }
00035
00042 static const struct fprintCacheEntry_s * cacheContainsDirectory(
00043 fingerPrintCache cache,
00044 const char * dirName)
00045
00046 {
00047 const void ** data;
00048
00049 if (htGetEntry(cache->ht, dirName, &data, NULL, NULL))
00050 return NULL;
00051 return data[0];
00052 }
00053
00062 static fingerPrint doLookup(fingerPrintCache cache,
00063 const char * dirName, const char * baseName, int scareMem)
00064
00065
00066 {
00067 char dir[PATH_MAX];
00068 const char * cleanDirName;
00069 size_t cdnl;
00070 char * end;
00071 fingerPrint fp;
00072 struct stat sb;
00073 char * buf;
00074 const struct fprintCacheEntry_s * cacheHit;
00075
00076
00077
00078
00079 cleanDirName = dirName;
00080 cdnl = strlen(cleanDirName);
00081
00082 if (*cleanDirName == '/') {
00083 if (!scareMem)
00084 cleanDirName =
00085 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
00086 } else {
00087 scareMem = 0;
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 dir[0] = '\0';
00098 if (Realpath(".", dir) != NULL) {
00099 end = dir + strlen(dir);
00100 if (end[-1] != '/') *end++ = '/';
00101 end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
00102 *end = '\0';
00103 (void)rpmCleanPath(dir);
00104 end = dir + strlen(dir);
00105 if (end[-1] != '/') *end++ = '/';
00106 *end = '\0';
00107 cleanDirName = dir;
00108 cdnl = end - dir;
00109 }
00110 }
00111 fp.entry = NULL;
00112 fp.subDir = NULL;
00113 fp.baseName = NULL;
00114
00115 if (cleanDirName == NULL) return fp;
00116
00117
00118 buf = strcpy(alloca(cdnl + 1), cleanDirName);
00119 end = buf + cdnl;
00120
00121
00122 if (buf[1] && end[-1] == '/') {
00123 end--;
00124 *end = '\0';
00125 }
00126
00127 while (1) {
00128
00129
00130
00131 cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
00132 if (cacheHit != NULL) {
00133 fp.entry = cacheHit;
00134 } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
00135 size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
00136 char * dn = xmalloc(nb);
00137 struct fprintCacheEntry_s * newEntry = (void *)dn;
00138
00139
00140 dn += sizeof(*newEntry);
00141 strcpy(dn, (*buf != '\0' ? buf : "/"));
00142 newEntry->ino = (ino_t)sb.st_ino;
00143 newEntry->dev = (dev_t)sb.st_dev;
00144 newEntry->dirName = dn;
00145 fp.entry = newEntry;
00146
00147
00148 htAddEntry(cache->ht, dn, fp.entry);
00149
00150
00151 }
00152
00153 if (fp.entry) {
00154 fp.subDir = cleanDirName + (end - buf);
00155 if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
00156 fp.subDir++;
00157 if (fp.subDir[0] == '\0' ||
00158
00159 (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
00160 fp.subDir = NULL;
00161 fp.baseName = baseName;
00162 if (!scareMem && fp.subDir != NULL)
00163 fp.subDir = xstrdup(fp.subDir);
00164
00165 return fp;
00166
00167 }
00168
00169
00170 if (end == buf + 1)
00171 abort();
00172
00173 end--;
00174 while ((end > buf) && *end != '/') end--;
00175 if (end == buf)
00176 end++;
00177
00178 *end = '\0';
00179 }
00180
00181
00182
00183
00184 return fp;
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 rpmuint32_t fpHashFunction(rpmuint32_t h, const void * data,
00195 size_t size)
00196 {
00197 const fingerPrint * fp = data;
00198 const char * chptr = fp->baseName;
00199 unsigned char ch = '\0';
00200
00201 while (*chptr != '\0') ch ^= *chptr++;
00202
00203 h |= ((unsigned)ch) << 24;
00204 h |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
00205 h |= fp->entry->ino & 0xFFFF;
00206
00207 return h;
00208 }
00209
00210 int fpEqual(const void * key1, const void * key2)
00211 {
00212 const fingerPrint *k1 = key1;
00213 const fingerPrint *k2 = key2;
00214
00215
00216 if (k1 == k2)
00217 return 0;
00218
00219
00220
00221 if (FP_EQUAL(*k1, *k2))
00222 return 0;
00223
00224 return 1;
00225
00226 }
00227
00228 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
00229 const char ** baseNames, const rpmuint32_t * dirIndexes,
00230 rpmuint32_t fileCount, fingerPrint * fpList)
00231 {
00232 unsigned i;
00233
00234 for (i = 0; i < (unsigned) fileCount; i++) {
00235
00236
00237 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
00238 fpList[i].entry = fpList[i - 1].entry;
00239 fpList[i].subDir = fpList[i - 1].subDir;
00240 fpList[i].baseName = baseNames[i];
00241 } else {
00242 fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
00243 1);
00244 }
00245 }
00246 }
00247
00248 #ifdef NOTUSED
00249
00256 static
00257 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
00258
00259 {
00260 rpmTagData he_p = { .ptr = NULL };
00261 HE_s he_s = { .tag = 0, .t = 0, .p = &he_p, .c = 0, .freeData = 0 };
00262 HE_t he = &he_s;
00263 const char ** baseNames;
00264 const char ** dirNames;
00265 rpmuint32_t * dirIndexes;
00266 rpmTagCount fileCount;
00267 int xx;
00268
00269 he->tag = RPMTAG_BASENAMES;
00270 xx = headerGet(h, he->tag, &he->t, he->p, &he->c);
00271 baseNames = he_p.argv;
00272 fileCount = he->c;
00273 if (!xx)
00274 return;
00275
00276 he->tag = RPMTAG_DIRNAMES;
00277 xx = headerGet(h, he, 0);
00278 dirNames = he_p.argv;
00279 he->tag = RPMTAG_DIRINDEXES;
00280 xx = headerGet(h, he, 0);
00281 dirIndexes = he_p.ui32p;
00282
00283 fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
00284
00285 dirIndexes = _free(dirIndexes);
00286 dirNames = _free(dirNames);
00287 baseNames = _free(baseNames);
00288 }
00289 #endif