rpm 5.2.1

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