Main Page Modules Data Structures File List Data Fields Globals Related Pages

# rpmdb/fprint.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmdb.h>
    00008 #include <rpmmacro.h>   /* XXX for rpmCleanPath */
    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, hashFunctionString,
    00019                        hashEqualityString);
    00020     return fpc;
    00021 }
    00022
    00023 fingerPrintCache fpCacheFree(fingerPrintCache cache)
    00024 {
    00025     cache->ht = htFree(cache->ht);
    00026     free(cache);
    00027     return NULL;
    00028 }
    00029
    00036 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory(
    00037                             fingerPrintCache cache,
    00038                             const char * dirName)
    00039         /*@*/
    00040 {
    00041     const void ** data;
    00042
    00043     if (htGetEntry(cache->ht, dirName, &data, NULL, NULL))
    00044         return NULL;
    00045 /*@-boundsread@*/
    00046     return data[0];
    00047 /*@=boundsread@*/
    00048 }
    00049
    00058 /*@-bounds@*/ /* LCL: segfault */
    00059 static fingerPrint doLookup(fingerPrintCache cache,
    00060                 const char * dirName, const char * baseName, int scareMemory)
    00061         /*@modifies cache @*/
    00062 {
    00063     char dir[PATH_MAX];
    00064     const char * cleanDirName;
    00065     size_t cdnl;
    00066     char * end;             /* points to the '\0' at the end of "buf" */
    00067     fingerPrint fp;
    00068     struct stat sb;
    00069     char * buf;
    00070     const struct fprintCacheEntry_s * cacheHit;
    00071
    00072     /* assert(*dirName == '/' || !scareMemory); */
    00073
    00074     /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
    00075     cleanDirName = dirName;
    00076     cdnl = strlen(cleanDirName);
    00077
    00078     if (*cleanDirName == '/') {
    00079         /*@-branchstate@*/
    00080         if (!scareMemory)
    00081             cleanDirName =
    00082                 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
    00083         /*@=branchstate@*/
    00084     } else {
    00085         scareMemory = 0;        /* XXX causes memory leak */
    00086
    00087         /* Using realpath on the arg isn't correct if the arg is a symlink,
    00088          * especially if the symlink is a dangling link.  What we
    00089          * do instead is use realpath() on `.' and then append arg to
    00090          * the result.
    00091          */
    00092
    00093         /* if the current directory doesn't exist, we might fail.
    00094            oh well. likewise if it's too long.  */
    00095         dir[0] = '\0';
    00096         /*@-branchstate@*/
    00097         if (realpath(".", dir) != NULL) {
    00098             end = dir + strlen(dir);
    00099             if (end[-1] != '/') *end++ = '/';
    00100             end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
    00101             *end = '\0';
    00102             (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */
    00103             end = dir + strlen(dir);
    00104             if (end[-1] != '/') *end++ = '/';
    00105             *end = '\0';
    00106             cleanDirName = dir;
    00107             cdnl = end - dir;
    00108         }
    00109         /*@=branchstate@*/
    00110     }
    00111     fp.entry = NULL;
    00112     fp.subDir = NULL;
    00113     fp.baseName = NULL;
    00114     /*@-nullret@*/
    00115     if (cleanDirName == NULL) return fp;        /* XXX can't happen */
    00116     /*@=nullret@*/
    00117
    00118     buf = strcpy(alloca(cdnl + 1), cleanDirName);
    00119     end = buf + cdnl;
    00120
    00121     /* no need to pay attention to that extra little / at the end of dirName */
    00122     if (buf[1] && end[-1] == '/') {
    00123         end--;
    00124         *end = '\0';
    00125     }
    00126
    00127     while (1) {
    00128
    00129         /* as we're stating paths here, we want to follow symlinks */
    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             /*@-usereleased@*/  /* LCL: contiguous malloc confusion */
    00140             dn += sizeof(*newEntry);
    00141             strcpy(dn, (*buf != '\0' ? buf : "/"));
    00142             newEntry->ino = sb.st_ino;
    00143             newEntry->dev = sb.st_dev;
    00144             newEntry->dirName = dn;
    00145             fp.entry = newEntry;
    00146
    00147             /*@-kepttrans -dependenttrans @*/
    00148             htAddEntry(cache->ht, dn, fp.entry);
    00149             /*@=kepttrans =dependenttrans @*/
    00150             /*@=usereleased@*/
    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             /* XXX don't bother saving '/' as subdir */
    00159                (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
    00160                 fp.subDir = NULL;
    00161             fp.baseName = baseName;
    00162             if (!scareMemory && fp.subDir != NULL)
    00163                 fp.subDir = xstrdup(fp.subDir);
    00164         /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
    00165             return fp;
    00166         /*@=compdef@*/
    00167         }
    00168
    00169         /* stat of '/' just failed! */
    00170         if (end == buf + 1)
    00171             abort();
    00172
    00173         end--;
    00174         while ((end > buf) && *end != '/') end--;
    00175         if (end == buf)     /* back to stat'ing just '/' */
    00176             end++;
    00177
    00178         *end = '\0';
    00179     }
    00180
    00181     /*@notreached@*/
    00182
    00183     /*@-compdef@*/ /* FIX: fp.entry.{dirName,dev,ino} undef @*/
    00184     /*@-nullret@*/ return fp; /*@=nullret@*/    /* LCL: can't happen. */
    00185     /*@=compdef@*/
    00186 }
    00187 /*@=bounds@*/
    00188
    00189 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName,
    00190                         const char * baseName, int scareMemory)
    00191 {
    00192     return doLookup(cache, dirName, baseName, scareMemory);
    00193 }
    00194
    00195 unsigned int fpHashFunction(const void * key)
    00196 {
    00197     const fingerPrint * fp = key;
    00198     unsigned int hash = 0;
    00199     char ch;
    00200     const char * chptr;
    00201
    00202     ch = 0;
    00203     chptr = fp->baseName;
    00204 /*@-boundsread@*/
    00205     while (*chptr != '\0') ch ^= *chptr++;
    00206 /*@=boundsread@*/
    00207
    00208     hash |= ((unsigned)ch) << 24;
    00209     hash |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
    00210     hash |= fp->entry->ino & 0xFFFF;
    00211
    00212     return hash;
    00213 }
    00214
    00215 /*@-boundsread@*/
    00216 int fpEqual(const void * key1, const void * key2)
    00217 {
    00218     const fingerPrint *k1 = key1;
    00219     const fingerPrint *k2 = key2;
    00220
    00221     /* If the addresses are the same, so are the values. */
    00222     if (k1 == k2)
    00223         return 0;
    00224
    00225     /* Otherwise, compare fingerprints by value. */
    00226     /*@-nullpass@*/     /* LCL: whines about (*k2).subdir */
    00227     if (FP_EQUAL(*k1, *k2))
    00228         return 0;
    00229     /*@=nullpass@*/
    00230     return 1;
    00231
    00232 }
    00233 /*@=boundsread@*/
    00234
    00235 /*@-bounds@*/
    00236 void fpLookupList(fingerPrintCache cache, const char ** dirNames,
    00237                   const char ** baseNames, const int * dirIndexes,
    00238                   int fileCount, fingerPrint * fpList)
    00239 {
    00240     int i;
    00241
    00242     for (i = 0; i < fileCount; i++) {
    00243         /* If this is in the same directory as the last file, don't bother
    00244            redoing all of this work */
    00245         if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
    00246             fpList[i].entry = fpList[i - 1].entry;
    00247             fpList[i].subDir = fpList[i - 1].subDir;
    00248             fpList[i].baseName = baseNames[i];
    00249         } else {
    00250             fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
    00251                                  1);
    00252         }
    00253     }
    00254 }
    00255 /*@=bounds@*/
    00256
    00257 #ifdef  UNUSED
    00258
    00265 static
    00266 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
    00267         /*@modifies h, cache, *fpList @*/;
    00268 {
    00269     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00270     HFD_t hfd = headerFreeData;
    00271     const char ** baseNames, ** dirNames;
    00272     rpmTagType bnt, dnt;
    00273     int_32 * dirIndexes;
    00274     int fileCount;
    00275     int xx;
    00276
    00277     if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
    00278         return;
    00279
    00280     xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
    00281     xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
    00282     fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
    00283     dirNames = hfd(dirNames, dnt);
    00284     baseNames = hfd(baseNames, bnt);
    00285 }
    00286 #endif