rpm 5.2.1

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

- File List
- Globals

rpmdb/fprint.c
Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmiotypes.h> /* XXX rpmRC codes. */
    00008 #include <rpmio.h>      /* XXX Realpath(). */
    00009 #include <rpmmacro.h>   /* XXX for rpmCleanPath */
    00010
    00011 #include <rpmtag.h>
    00012 #include <rpmdb.h>
    00013
    00014 #include "fprint.h"
    00015 #include "debug.h"
    00016
    00017 /*@access hashTable @*/
    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 /*@null@*/ 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         /*@globals fileSystem, internalState @*/
    00065         /*@modifies cache, fileSystem, internalState @*/
    00066 {
    00067     char dir[PATH_MAX];
    00068     const char * cleanDirName;
    00069     size_t cdnl;
    00070     char * end;             /* points to the '\0' at the end of "buf" */
    00071     fingerPrint fp;
    00072     struct stat sb;
    00073     char * buf;
    00074     const struct fprintCacheEntry_s * cacheHit;
    00075
    00076     /* assert(*dirName == '/' || !scareMem); */
    00077
    00078     /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
    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;   /* XXX causes memory leak */
    00088
    00089         /* Using realpath on the arg isn't correct if the arg is a symlink,
    00090          * especially if the symlink is a dangling link.  What we
    00091          * do instead is use realpath() on `.' and then append arg to
    00092          * the result.
    00093          */
    00094
    00095         /* if the current directory doesn't exist, we might fail.
    00096            oh well. likewise if it's too long.  */
    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); /* XXX possible /../ from concatenation */
    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     /*@-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 = (ino_t)sb.st_ino;
    00143             newEntry->dev = (dev_t)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 (!scareMem && 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
    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                 /*@unused@*/ 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     /* If the addresses are the same, so are the values. */
    00216     if (k1 == k2)
    00217         return 0;
    00218
    00219     /* Otherwise, compare fingerprints by value. */
    00220     /*@-nullpass@*/     /* LCL: whines about (*k2).subdir */
    00221     if (FP_EQUAL(*k1, *k2))
    00222         return 0;
    00223     /*@=nullpass@*/
    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         /* If this is in the same directory as the last file, don't bother
    00236            redoing all of this work */
    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         /*@modifies h, cache, *fpList @*/
    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