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 #include <rpmlib.h>
00007 #include <rpmmacro.h>   /* XXX for rpmCleanPath */
00008 
00009 #include "fprint.h"
00010 #include "debug.h"
00011 
00012 fingerPrintCache fpCacheCreate(int sizeHint)
00013 {
00014     fingerPrintCache fpc;
00015 
00016     fpc = xmalloc(sizeof(*fpc));
00017     fpc->ht = htCreate(sizeHint * 2, 0, 1, hashFunctionString,
00018                        hashEqualityString);
00019     return fpc;
00020 }
00021 
00022 void fpCacheFree(fingerPrintCache cache)
00023 {
00024     htFree(cache->ht);
00025     free(cache);
00026 }
00027 
00034 static /*@null@*/ const struct fprintCacheEntry_s * cacheContainsDirectory(
00035                             fingerPrintCache cache,
00036                             const char * dirName)
00037         /*@*/
00038 {
00039     const void ** data;
00040 
00041     if (htGetEntry(cache->ht, dirName, &data, NULL, NULL))
00042         return NULL;
00043     return data[0];
00044 }
00045 
00054 static fingerPrint doLookup(fingerPrintCache cache,
00055                 const char * dirName, const char * baseName, int scareMemory)
00056         /*@modifies cache @*/
00057 {
00058     char dir[PATH_MAX];
00059     const char * cleanDirName;
00060     size_t cdnl;
00061     char * end;             /* points to the '\0' at the end of "buf" */
00062     fingerPrint fp;
00063     struct stat sb;
00064     char * buf;
00065     const struct fprintCacheEntry_s * cacheHit;
00066 
00067     /* assert(*dirName == '/' || !scareMemory); */
00068 
00069     /* XXX WATCHOUT: fp.subDir is set below from relocated dirName arg */
00070     cleanDirName = dirName;
00071     cdnl = strlen(cleanDirName);
00072 
00073     if (*cleanDirName == '/') {
00074         if (!scareMemory)
00075             cleanDirName =
00076                 rpmCleanPath(strcpy(alloca(cdnl+1), dirName));
00077     } else {
00078         scareMemory = 0;        /* XXX causes memory leak */
00079 
00080         /* Using realpath on the arg isn't correct if the arg is a symlink,
00081          * especially if the symlink is a dangling link.  What we 
00082          * do instead is use realpath() on `.' and then append arg to
00083          * the result.
00084          */
00085 
00086         /* if the current directory doesn't exist, we might fail. 
00087            oh well. likewise if it's too long.  */
00088         dir[0] = '\0';
00089         if ( /*@-unrecog@*/ realpath(".", dir) /*@=unrecog@*/ != NULL) {
00090             end = dir + strlen(dir);
00091             if (end[-1] != '/') *end++ = '/';
00092             end = stpncpy(end, cleanDirName, sizeof(dir) - (end - dir));
00093             *end = '\0';
00094             (void)rpmCleanPath(dir); /* XXX possible /../ from concatenation */
00095             end = dir + strlen(dir);
00096             if (end[-1] != '/') *end++ = '/';
00097             *end = '\0';
00098             cleanDirName = dir;
00099             cdnl = end - dir;
00100         }
00101     }
00102     fp.entry = NULL;
00103     fp.subDir = NULL;
00104     fp.baseName = NULL;
00105     /*@-nullret@*/
00106     if (cleanDirName == NULL) return fp;        /* XXX can't happen */
00107     /*@=nullret@*/
00108 
00109     buf = strcpy(alloca(cdnl + 1), cleanDirName);
00110     end = buf + cdnl;
00111 
00112     /* no need to pay attention to that extra little / at the end of dirName */
00113     if (buf[1] && end[-1] == '/') {
00114         end--;
00115         *end = '\0';
00116     }
00117 
00118     while (1) {
00119 
00120         /* as we're stating paths here, we want to follow symlinks */
00121 
00122         cacheHit = cacheContainsDirectory(cache, (*buf != '\0' ? buf : "/"));
00123         if (cacheHit != NULL) {
00124             fp.entry = cacheHit;
00125         } else if (!stat((*buf != '\0' ? buf : "/"), &sb)) {
00126             size_t nb = sizeof(*fp.entry) + (*buf != '\0' ? (end-buf) : 1) + 1;
00127             char * dn = xmalloc(nb);
00128             struct fprintCacheEntry_s * newEntry = (void *)dn;
00129 
00130             dn += sizeof(*newEntry);
00131             strcpy(dn, (*buf != '\0' ? buf : "/"));
00132             newEntry->ino = sb.st_ino;
00133             newEntry->dev = sb.st_dev;
00134             newEntry->isFake = 0;
00135             newEntry->dirName = dn;
00136             fp.entry = newEntry;
00137 
00138             /*@-kepttrans@*/
00139             htAddEntry(cache->ht, dn, fp.entry);
00140             /*@@kepttrans@*/
00141         }
00142 
00143         if (fp.entry) {
00144             fp.subDir = cleanDirName + (end - buf);
00145             if (fp.subDir[0] == '/' && fp.subDir[1] != '\0')
00146                 fp.subDir++;
00147             if (fp.subDir[0] == '\0' ||
00148             /* XXX don't bother saving '/' as subdir */
00149                (fp.subDir[0] == '/' && fp.subDir[1] == '\0'))
00150                 fp.subDir = NULL;
00151             fp.baseName = baseName;
00152             if (!scareMemory && fp.subDir != NULL)
00153                 fp.subDir = xstrdup(fp.subDir);
00154             return fp;
00155         }
00156 
00157         /* stat of '/' just failed! */
00158         if (end == buf + 1)
00159             abort();
00160 
00161         end--;
00162         while ((end > buf) && *end != '/') end--;
00163         if (end == buf)     /* back to stat'ing just '/' */
00164             end++;
00165 
00166         *end = '\0';
00167     }
00168 
00169     /*@notreached@*/
00170 
00171     /*@-nullret@*/ return fp; /*@=nullret@*/    /* LCL: can't happen. */
00172 }
00173 
00174 fingerPrint fpLookup(fingerPrintCache cache, const char * dirName, 
00175                         const char * baseName, int scareMemory)
00176 {
00177     return doLookup(cache, dirName, baseName, scareMemory);
00178 }
00179 
00180 unsigned int fpHashFunction(const void * key)
00181 {
00182     const fingerPrint * fp = key;
00183     unsigned int hash = 0;
00184     char ch;
00185     const char * chptr;
00186 
00187     ch = 0;
00188     chptr = fp->baseName;
00189     while (*chptr != '\0') ch ^= *chptr++;
00190 
00191     hash |= ((unsigned)ch) << 24;
00192     hash |= (((((unsigned)fp->entry->dev) >> 8) ^ fp->entry->dev) & 0xFF) << 16;
00193     hash |= fp->entry->ino & 0xFFFF;
00194     
00195     return hash;
00196 }
00197 
00198 int fpEqual(const void * key1, const void * key2)
00199 {
00200     const fingerPrint *k1 = key1;
00201     const fingerPrint *k2 = key2;
00202 
00203     /* If the addresses are the same, so are the values. */
00204     if (k1 == k2)
00205         return 0;
00206 
00207     /* Otherwise, compare fingerprints by value. */
00208     /*@-nullpass@*/     /* LCL: whines about (*k2).subdir */
00209     if (FP_EQUAL(*k1, *k2))
00210         return 0;
00211     /*@=nullpass@*/
00212     return 1;
00213 
00214 }
00215 
00216 void fpLookupList(fingerPrintCache cache, const char ** dirNames, 
00217                   const char ** baseNames, const int * dirIndexes, 
00218                   int fileCount, fingerPrint * fpList)
00219 {
00220     int i;
00221 
00222     for (i = 0; i < fileCount; i++) {
00223         /* If this is in the same directory as the last file, don't bother
00224            redoing all of this work */
00225         if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
00226             fpList[i].entry = fpList[i - 1].entry;
00227             fpList[i].subDir = fpList[i - 1].subDir;
00228             fpList[i].baseName = baseNames[i];
00229         } else {
00230             fpList[i] = doLookup(cache, dirNames[dirIndexes[i]], baseNames[i],
00231                                  1);
00232         }
00233     }
00234 }
00235 
00236 void fpLookupHeader(fingerPrintCache cache, Header h, fingerPrint * fpList)
00237 {
00238     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00239     HFD_t hfd = headerFreeData;
00240     const char ** baseNames, ** dirNames;
00241     rpmTagType bnt, dnt;
00242     int_32 * dirIndexes;
00243     int fileCount;
00244 
00245     if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
00246         return;
00247 
00248     (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
00249     (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00250     fpLookupList(cache, dirNames, baseNames, dirIndexes, fileCount, fpList);
00251     dirNames = hfd(dirNames, dnt);
00252     baseNames = hfd(baseNames, bnt);
00253 }

Generated at Thu Sep 6 11:25:43 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001