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

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2