LTP GCOV extension - code coverage report
Current view: directory - src/libstore - references.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 81
Code covered: 90.1 % Executed lines: 73

       1                 : #include "references.hh"
       2                 : #include "hash.hh"
       3                 : #include "util.hh"
       4                 : 
       5                 : #include <cerrno>
       6                 : #include <cstring>
       7                 : #include <cstdlib>
       8                 : #include <map>
       9                 : 
      10                 : #include <sys/types.h>
      11                 : #include <sys/stat.h>
      12                 : #include <unistd.h>
      13                 : #include <dirent.h>
      14                 : #include <fcntl.h>
      15                 : 
      16                 : 
      17                 : namespace nix {
      18                 : 
      19                 : 
      20                 : static unsigned int refLength = 32; /* characters */
      21                 : 
      22                 : 
      23                 : static void search(size_t len, const unsigned char * s,
      24             369 :     StringSet & ids, StringSet & seen)
      25                 : {
      26                 :     static bool initialised = false;
      27                 :     static bool isBase32[256];
      28             369 :     if (!initialised) {
      29              58 :         for (unsigned int i = 0; i < 256; ++i) isBase32[i] = false;
      30            1914 :         for (unsigned int i = 0; i < base32Chars.size(); ++i)
      31            1856 :             isBase32[(unsigned char) base32Chars[i]] = true;
      32              58 :         initialised = true;
      33                 :     }
      34                 :     
      35            1129 :     for (unsigned int i = 0; i + refLength <= len; ) {
      36                 :         int j;
      37            1363 :         bool match = true;
      38           29109 :         for (j = refLength - 1; j >= 0; --j)
      39           28349 :             if (!isBase32[(unsigned char) s[i + j]]) {
      40             603 :                 i += j + 1;
      41             603 :                 match = false;
      42             603 :                 break;
      43                 :             }
      44            1363 :         if (!match) continue;
      45             760 :         string ref((const char *) s + i, refLength);
      46            1520 :         if (ids.find(ref) != ids.end()) {
      47              85 :             debug(format("found reference to `%1%' at offset `%2%'")
      48                 :                   % ref % i);
      49              85 :             seen.insert(ref);
      50              85 :             ids.erase(ref);
      51                 :         }
      52             760 :         ++i;
      53                 :     }
      54             369 : }
      55                 : 
      56                 : 
      57                 : void checkPath(const string & path,
      58             301 :     StringSet & ids, StringSet & seen)
      59                 : {
      60             301 :     checkInterrupt();
      61                 :     
      62             301 :     debug(format("checking `%1%'") % path);
      63                 : 
      64                 :     struct stat st;
      65             301 :     if (lstat(path.c_str(), &st))
      66               0 :         throw SysError(format("getting attributes of path `%1%'") % path);
      67                 : 
      68             301 :     if (S_ISDIR(st.st_mode)) {
      69             124 :         Strings names = readDirectory(path);
      70             316 :         for (Strings::iterator i = names.begin(); i != names.end(); i++) {
      71             192 :             search(i->size(), (const unsigned char *) i->c_str(), ids, seen);
      72             192 :             checkPath(path + "/" + *i, ids, seen);
      73             124 :         }
      74                 :     }
      75                 : 
      76             177 :     else if (S_ISREG(st.st_mode)) {
      77                 :         
      78              86 :         AutoCloseFD fd = open(path.c_str(), O_RDONLY);
      79              86 :         if (fd == -1) throw SysError(format("opening file `%1%'") % path);
      80                 : 
      81              86 :         size_t bufSize = 1024 * 1024;
      82              86 :         assert(refLength <= bufSize);
      83              86 :         unsigned char * buf = new unsigned char[bufSize];
      84                 : 
      85              86 :         size_t left = st.st_size;
      86              86 :         bool firstBlock = true;
      87                 :         
      88             258 :         while (left > 0) {
      89              86 :             checkInterrupt();
      90                 :             
      91              86 :             size_t read = left > bufSize ? bufSize : left;
      92              86 :             size_t copiedBytes = 0;
      93                 : 
      94              86 :             if (!firstBlock) {
      95                 :                 /* Move the last (refLength - 1) bytes from the last
      96                 :                    block to the start of the buffer to deal with
      97                 :                    references that cross block boundaries. */
      98               0 :                 copiedBytes = refLength - 1;
      99               0 :                 if (read + copiedBytes > bufSize)
     100               0 :                     read -= copiedBytes;
     101               0 :                 memcpy(buf, buf + (bufSize - copiedBytes), copiedBytes);
     102                 :             }
     103              86 :             firstBlock = false;
     104                 : 
     105              86 :             readFull(fd, buf + copiedBytes, read);
     106              86 :             left -= read;
     107                 : 
     108              86 :             search(copiedBytes + read, buf, ids, seen);
     109                 :         }
     110                 :         
     111              86 :         delete[] buf; /* !!! autodelete */
     112                 :     }
     113                 :     
     114              91 :     else if (S_ISLNK(st.st_mode)) {
     115              91 :         string target = readLink(path);
     116              91 :         search(target.size(), (const unsigned char *) target.c_str(), ids, seen);
     117                 :     }
     118                 :     
     119               0 :     else throw Error(format("unknown file type: %1%") % path);
     120             301 : }
     121                 : 
     122                 : 
     123             109 : PathSet scanForReferences(const string & path, const PathSet & paths)
     124                 : {
     125             109 :     std::map<string, Path> backMap;
     126             109 :     StringSet ids;
     127             109 :     StringSet seen;
     128                 : 
     129                 :     /* For efficiency (and a higher hit rate), just search for the
     130                 :        hash part of the file name.  (This assumes that all references
     131                 :        have the form `HASH-bla'). */
     132             448 :     for (PathSet::const_iterator i = paths.begin(); i != paths.end(); i++) {
     133             339 :         string baseName = baseNameOf(*i);
     134             339 :         string::size_type pos = baseName.find('-');
     135             339 :         if (pos == string::npos)
     136               0 :             throw Error(format("bad reference `%1%'") % *i);
     137             339 :         string s = string(baseName, 0, pos);
     138             339 :         assert(s.size() == refLength);
     139             339 :         assert(backMap.find(s) == backMap.end());
     140                 :         // parseHash(htSHA256, s);
     141             339 :         ids.insert(s);
     142             339 :         backMap[s] = *i;
     143                 :     }
     144                 : 
     145             109 :     checkPath(path, ids, seen);
     146                 : 
     147             109 :     PathSet found;
     148             194 :     for (StringSet::iterator i = seen.begin(); i != seen.end(); i++) {
     149              85 :         std::map<string, Path>::iterator j;
     150              85 :         if ((j = backMap.find(*i)) == backMap.end()) abort();
     151              85 :         found.insert(j->second);
     152                 :     }
     153                 : 
     154             109 :     return found;
     155                 : }
     156                 : 
     157               0 :  
     158                 : }

Generated by: LTP GCOV extension version 1.6