• 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 <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

Generated on Mon Nov 29 2010 05:18:46 for rpm by  doxygen 1.7.2