LTP GCOV extension - code coverage report
Current view: directory - src/libutil - hash.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 163
Code covered: 87.7 % Executed lines: 143

       1                 : #include "config.h"
       2                 : 
       3                 : #include <iostream>
       4                 : #include <cstring>
       5                 : 
       6                 : #ifdef HAVE_OPENSSL
       7                 : #include <openssl/md5.h>
       8                 : #include <openssl/sha.h>
       9                 : #else
      10                 : extern "C" {
      11                 : #include "md5.h"
      12                 : #include "sha1.h"
      13                 : #include "sha256.h"
      14                 : }
      15                 : #endif
      16                 : 
      17                 : #include "hash.hh"
      18                 : #include "archive.hh"
      19                 : #include "util.hh"
      20                 : 
      21                 : #include <sys/types.h>
      22                 : #include <sys/stat.h>
      23                 : #include <fcntl.h>
      24                 : 
      25                 : 
      26                 : namespace nix {
      27                 : 
      28                 : 
      29           33285 : Hash::Hash()
      30                 : {
      31           33285 :     type = htUnknown;
      32           33285 :     hashSize = 0;
      33           33285 :     memset(hash, 0, maxHashSize);
      34           33285 : }
      35                 : 
      36                 : 
      37           12392 : Hash::Hash(HashType type)
      38                 : {
      39           12392 :     this->type = type;
      40           12392 :     if (type == htMD5) hashSize = md5HashSize;
      41           12354 :     else if (type == htSHA1) hashSize = sha1HashSize;
      42           12322 :     else if (type == htSHA256) hashSize = sha256HashSize;
      43               0 :     else throw Error("unknown hash type");
      44           12392 :     assert(hashSize <= maxHashSize);
      45           12392 :     memset(hash, 0, maxHashSize);
      46           12392 : }
      47                 : 
      48                 : 
      49              79 : bool Hash::operator == (const Hash & h2) const
      50                 : {
      51              79 :     if (hashSize != h2.hashSize) return false;
      52            2503 :     for (unsigned int i = 0; i < hashSize; i++)
      53            2425 :         if (hash[i] != h2.hash[i]) return false;
      54              78 :     return true;
      55                 : }
      56                 : 
      57                 : 
      58              79 : bool Hash::operator != (const Hash & h2) const
      59                 : {
      60              79 :     return !(*this == h2);
      61                 : }
      62                 : 
      63                 : 
      64               0 : bool Hash::operator < (const Hash & h) const
      65                 : {
      66               0 :     for (unsigned int i = 0; i < hashSize; i++) {
      67               0 :         if (hash[i] < h.hash[i]) return true;
      68               0 :         if (hash[i] > h.hash[i]) return false;
      69                 :     }
      70               0 :     return false;
      71                 : }
      72                 : 
      73                 : 
      74            1151 : const string base16Chars = "0123456789abcdef";
      75                 : 
      76                 : 
      77            6156 : string printHash(const Hash & hash)
      78                 : {
      79            6156 :     char buf[hash.hashSize * 2];
      80          202692 :     for (unsigned int i = 0; i < hash.hashSize; i++) {
      81          196536 :         buf[i * 2] = base16Chars[hash.hash[i] >> 4];
      82          196536 :         buf[i * 2 + 1] = base16Chars[hash.hash[i] & 0x0f];
      83                 :     }
      84            6156 :     return string(buf, hash.hashSize * 2);
      85                 : }
      86                 : 
      87                 :     
      88            5498 : Hash parseHash(HashType ht, const string & s)
      89                 : {
      90            5498 :     Hash hash(ht);
      91            5498 :     if (s.length() != hash.hashSize * 2)
      92               0 :         throw Error(format("invalid hash `%1%'") % s);
      93          181198 :     for (unsigned int i = 0; i < hash.hashSize; i++) {
      94          175700 :         string s2(s, i * 2, 2);
      95          175700 :         if (!isxdigit(s2[0]) || !isxdigit(s2[1])) 
      96               0 :             throw Error(format("invalid hash `%1%'") % s);
      97          175700 :         std::istringstream str(s2);
      98                 :         int n;
      99          175700 :         str >> std::hex >> n;
     100          175700 :         hash.hash[i] = n;
     101                 :     }
     102                 :     return hash;
     103                 : }
     104                 : 
     105                 : 
     106           21528 : static unsigned char divMod(unsigned char * bytes, unsigned char y)
     107                 : {
     108           21528 :     unsigned int borrow = 0;
     109                 : 
     110           21528 :     int pos = Hash::maxHashSize - 1;
     111           21528 :     while (pos >= 0 && !bytes[pos]) --pos;
     112                 : 
     113          262593 :     for ( ; pos >= 0; --pos) {
     114          241065 :         unsigned int s = bytes[pos] + (borrow << 8);
     115          241065 :         unsigned int d = s / y;
     116          241065 :         borrow = s % y;
     117          241065 :         bytes[pos] = d;
     118                 :     }
     119                 : 
     120           21528 :     return borrow;
     121                 : }
     122                 : 
     123                 : 
     124             652 : unsigned int hashLength32(const Hash & hash)
     125                 : {
     126             652 :     return (hash.hashSize * 8 - 1) / 5 + 1;
     127                 : }
     128                 : 
     129                 : 
     130                 : // omitted: E O U T
     131            1704 : const string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
     132                 : 
     133                 : 
     134             649 : string printHash32(const Hash & hash)
     135                 : {
     136             649 :     Hash hash2(hash);
     137             649 :     unsigned int len = hashLength32(hash);
     138                 : 
     139             649 :     const char * chars = base32Chars.c_str();
     140                 :     
     141             649 :     string s(len, '0');
     142                 : 
     143             649 :     int pos = len - 1;
     144           22826 :     while (pos >= 0) {
     145           21528 :         unsigned char digit = divMod(hash2.hash, 32);
     146           21528 :         s[pos--] = chars[digit];
     147                 :     }
     148                 : 
     149           21417 :     for (unsigned int i = 0; i < hash2.maxHashSize; ++i)
     150           20768 :         assert(hash2.hash[i] == 0);
     151                 : 
     152               0 :     return s;
     153                 : }
     154                 : 
     155                 : 
     156             792 : static bool mul(unsigned char * bytes, unsigned char y, int maxSize)
     157                 : {
     158             792 :     unsigned char carry = 0;
     159                 : 
     160           25368 :     for (int pos = 0; pos < maxSize; ++pos) {
     161           24576 :         unsigned int m = bytes[pos] * y + carry;
     162           24576 :         bytes[pos] = m & 0xff;
     163           24576 :         carry = m >> 8;
     164                 :     }
     165                 : 
     166             792 :     return carry;
     167                 : }
     168                 : 
     169                 : 
     170             792 : static bool add(unsigned char * bytes, unsigned char y, int maxSize)
     171                 : {
     172             792 :     unsigned char carry = y;
     173                 : 
     174             792 :     for (int pos = 0; pos < maxSize; ++pos) {
     175             792 :         unsigned int m = bytes[pos] + carry;
     176             792 :         bytes[pos] = m & 0xff;
     177             792 :         carry = m >> 8;
     178             792 :         if (carry == 0) break;
     179                 :     }
     180                 : 
     181             792 :     return carry;
     182                 : }
     183                 : 
     184                 : 
     185              16 : Hash parseHash32(HashType ht, const string & s)
     186                 : {
     187              16 :     Hash hash(ht);
     188                 : 
     189              16 :     const char * chars = base32Chars.c_str();
     190                 : 
     191             808 :     for (unsigned int i = 0; i < s.length(); ++i) {
     192             792 :         char c = s[i];
     193                 :         unsigned char digit;
     194           12727 :         for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
     195           12727 :             if (chars[digit] == c) break;
     196             792 :         if (digit >= 32)
     197               0 :             throw Error(format("invalid base-32 hash `%1%'") % s);
     198             792 :         if (mul(hash.hash, 32, hash.hashSize) ||
     199                 :             add(hash.hash, digit, hash.hashSize))
     200               0 :             throw Error(format("base-32 hash `%1%' is too large") % s);
     201                 :     }
     202                 : 
     203                 :     return hash;
     204                 : }
     205                 : 
     206                 : 
     207               0 : bool isHash(const string & s)
     208                 : {
     209               0 :     if (s.length() != 32) return false;
     210               0 :     for (int i = 0; i < 32; i++) {
     211               0 :         char c = s[i];
     212               0 :         if (!((c >= '0' && c <= '9') ||
     213                 :               (c >= 'a' && c <= 'f')))
     214               0 :             return false;
     215                 :     }
     216               0 :     return true;
     217                 : }
     218                 : 
     219                 : 
     220                 : union Ctx
     221                 : {
     222                 :     MD5_CTX md5;
     223                 :     SHA_CTX sha1;
     224                 :     SHA256_CTX sha256;
     225                 : };
     226                 : 
     227                 : 
     228            6859 : static void start(HashType ht, Ctx & ctx)
     229                 : {
     230            6859 :     if (ht == htMD5) MD5_Init(&ctx.md5);
     231            6840 :     else if (ht == htSHA1) SHA1_Init(&ctx.sha1);
     232            6818 :     else if (ht == htSHA256) SHA256_Init(&ctx.sha256);
     233            6859 : }
     234                 : 
     235                 : 
     236                 : static void update(HashType ht, Ctx & ctx,
     237          111155 :     const unsigned char * bytes, unsigned int len)
     238                 : {
     239          111155 :     if (ht == htMD5) MD5_Update(&ctx.md5, bytes, len);
     240          110700 :     else if (ht == htSHA1) SHA1_Update(&ctx.sha1, bytes, len);
     241          110563 :     else if (ht == htSHA256) SHA256_Update(&ctx.sha256, bytes, len);
     242          111155 : }
     243                 : 
     244                 : 
     245            6854 : static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
     246                 : {
     247            6854 :     if (ht == htMD5) MD5_Final(hash, &ctx.md5);
     248            6835 :     else if (ht == htSHA1) SHA1_Final(hash, &ctx.sha1);
     249            6813 :     else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256);
     250            6854 : }
     251                 : 
     252                 : 
     253            1235 : Hash hashString(HashType ht, const string & s)
     254                 : {
     255                 :     Ctx ctx;
     256            1235 :     Hash hash(ht);
     257            1235 :     start(ht, ctx);
     258            1235 :     update(ht, ctx, (const unsigned char *) s.c_str(), s.length());
     259            1235 :     finish(ht, ctx, hash.hash);
     260                 :     return hash;
     261                 : }
     262                 : 
     263                 : 
     264              69 : Hash hashFile(HashType ht, const Path & path)
     265                 : {
     266                 :     Ctx ctx;
     267              69 :     Hash hash(ht);
     268              69 :     start(ht, ctx);
     269                 : 
     270              69 :     AutoCloseFD fd = open(path.c_str(), O_RDONLY);
     271              69 :     if (fd == -1) throw SysError(format("opening file `%1%'") % path);
     272                 : 
     273                 :     unsigned char buf[8192];
     274                 :     ssize_t n;
     275             206 :     while ((n = read(fd, buf, sizeof(buf)))) {
     276              68 :         checkInterrupt();
     277              68 :         if (n == -1) throw SysError(format("reading file `%1%'") % path);
     278              68 :         update(ht, ctx, buf, n);
     279                 :     }
     280                 :     
     281              69 :     finish(ht, ctx, hash.hash);
     282              69 :     return hash;
     283                 : }
     284                 : 
     285                 : 
     286            5555 : HashSink::HashSink(HashType ht) : ht(ht)
     287                 : {
     288            5555 :     ctx = new Ctx;
     289            5555 :     start(ht, *ctx);
     290            5555 : }
     291                 :     
     292            5555 : HashSink::~HashSink()
     293                 : {
     294            5555 :     delete ctx;
     295            5555 : }
     296                 : 
     297                 : void HashSink::operator ()
     298          109852 :     (const unsigned char * data, unsigned int len)
     299                 : {
     300          109852 :     update(ht, *ctx, data, len);
     301          109852 : }
     302                 : 
     303            5550 : Hash HashSink::finish()
     304                 : {
     305            5550 :     Hash hash(ht);
     306            5550 :     nix::finish(ht, *ctx, hash.hash);
     307                 :     return hash;
     308                 : }
     309                 : 
     310                 : 
     311            5545 : Hash hashPath(HashType ht, const Path & path, PathFilter & filter)
     312                 : {
     313            5545 :     HashSink sink(ht);
     314            5545 :     dumpPath(path, sink, filter);
     315            5545 :     return sink.finish();
     316                 : }
     317                 : 
     318                 : 
     319             592 : Hash compressHash(const Hash & hash, unsigned int newSize)
     320                 : {
     321             592 :     Hash h;
     322             592 :     h.hashSize = newSize;
     323           19536 :     for (unsigned int i = 0; i < hash.hashSize; ++i)
     324           18944 :         h.hash[i % newSize] ^= hash.hash[i];
     325                 :     return h;
     326                 : }
     327                 : 
     328                 : 
     329            5582 : HashType parseHashType(const string & s)
     330                 : {
     331            5582 :     if (s == "md5") return htMD5;
     332            5559 :     else if (s == "sha1") return htSHA1;
     333            5550 :     else if (s == "sha256") return htSHA256;
     334               0 :     else return htUnknown;
     335                 : }
     336                 : 
     337               0 :  
     338            1106 : }

Generated by: LTP GCOV extension version 1.6