Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

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

Generated at Mon May 21 08:53:39 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001