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

Generated on Wed Dec 28 16:55:10 2016 for rpm by  doxygen 1.4.4