- Main Page
- Related Pages
- Modules
- Data Structures
- Files

# rpmdb/fprint.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmmacro.h>   /* XXX for rpmCleanPath */
    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 /*@null@*/ 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         /*@modifies cache @*/
    00058 {
    00059     char dir[PATH_MAX];
    00060     const char * cleanDirName;
    00061     size_t cdnl;
    00062     char * end;             /* points to the '\0' at the end of "buf" */
    00063     fingerPrint fp;
    00064     struct stat sb;
    00065     char * buf;
    00066     const struct fprintCacheEntry_s * cacheHit;
    00067
    00068     /* assert(*dirName == '/' || !scareMem); */
    00069
    00070     /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
    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;   /* XXX causes memory leak */
    00080
    00081         /* Using realpath on the arg isn't correct if the arg is a symlink,
    00082          * especially if the symlink is a dangling link.  What we
    00083          * do instead is use realpath() on `.' and then append arg to
    00084          * the result.
    00085          */
    00086
    00087         /* if the current directory doesn't exist, we might fail.
    00088            oh well. likewise if it's too long.  */
    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); /* XXX possible /../ from concatenation */
    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     /*@-nullret@*/
    00107     if (cleanDirName == NULL) return fp;        /* XXX can't happen */
    00108     /*@=nullret@*/
    00109
    00110     buf = strcpy(alloca(cdnl + 1), cleanDirName);
    00111     end = buf + cdnl;
    00112
    00113     /* no need to pay attention to that extra little / at the end of dirName */
    00114     if (buf[1] && end[-1] == '/') {
    00115         end--;
    00116         *end = '\0';
    00117     }
    00118
    00119     while (1) {
    00120
    00121         /* as we're stating paths here, we want to follow symlinks */
    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             /*@-usereleased@*/  /* LCL: contiguous malloc confusion */
    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             /*@-kepttrans -dependenttrans @*/
    00140             htAddEntry(cache->ht, dn, fp.entry);
    00141             /*@=kepttrans =dependenttrans @*/
    00142             /*@=usereleased@*/
    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             /* XXX don't bother saving '/' as subdir */
    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         /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
    00157             return fp;
    00158         /*@=compdef@*/
    00159         }
    00160
    00161         /* stat of '/' just failed! */
    00162         if (end == buf + 1)
    00163             abort();
    00164
    00165         end--;
    00166         while ((end > buf) && *end != '/') end--;
    00167         if (end == buf)     /* back to stat'ing just '/' */
    00168             end++;
    00169
    00170         *end = '\0';
    00171     }
    00172
    00173     /*@notreached@*/
    00174
    00175     /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
    00176     /*@-nullret@*/ return fp; /*@=nullret@*/    /* LCL: can't happen. */
    00177     /*@=compdef@*/
    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, /*@unused@*/ 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     /* If the addresses are the same, so are the values. */
    00207     if (k1 == k2)
    00208         return 0;
    00209
    00210     /* Otherwise, compare fingerprints by value. */
    00211     /*@-nullpass@*/     /* LCL: whines about (*k2).subdir */
    00212     if (FP_EQUAL(*k1, *k2))
    00213         return 0;
    00214     /*@=nullpass@*/
    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         /* If this is in the same directory as the last file, don't bother
    00227            redoing all of this work */
    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         /*@modifies h, cache, *fpList @*/;
    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