about summary refs log tree commit diff
path: root/src/libutil/hash.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2005-01-13T17·39+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2005-01-13T17·39+0000
commit7e8961f72056f53ccf78eba0ee8c240bc2310ab8 (patch)
treef4ae8ee014f3d86aa9ec1706d1aa9e83c2329a73 /src/libutil/hash.cc
parent73992371a3bc16b27b22e53d5f7ae600dea9cf60 (diff)
* Added SHA-1 support. `nix-hash' now has an option `--type sha1' to
  select SHA-1 hashing.

Diffstat (limited to 'src/libutil/hash.cc')
-rw-r--r--src/libutil/hash.cc87
1 files changed, 70 insertions, 17 deletions
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index 1a44c85341e4..46334ad820d7 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -2,17 +2,24 @@
 
 extern "C" {
 #include "md5.h"
+#include "sha1.h"
 }
 
 #include "hash.hh"
 #include "archive.hh"
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
 
 Hash::Hash(HashType type)
 {
     this->type = type;
     if (type == htMD5) hashSize = md5HashSize;
     else if (type == htSHA1) hashSize = sha1HashSize;
+    else throw Error("unknown hash type");
     memset(hash, 0, hashSize);
 }
 
@@ -85,44 +92,90 @@ bool isHash(const string & s)
 }
 
 
-Hash hashString(const string & s)
+struct Ctx
 {
-    Hash hash(htMD5);
-    md5_buffer(s.c_str(), s.length(), hash.hash);
+    md5_ctx md5;
+    sha_ctx sha1;
+};
+
+
+static void start(HashType ht, Ctx & ctx)
+{
+    if (ht == htMD5) md5_init_ctx(&ctx.md5);
+    else if (ht == htSHA1) sha_init(&ctx.sha1);
+}
+
+
+static void update(HashType ht, Ctx & ctx,
+    const unsigned char * bytes, unsigned int len)
+{
+    if (ht == htMD5) md5_process_bytes(bytes, len, &ctx.md5);
+    else if (ht == htSHA1) sha_update(&ctx.sha1, bytes, len);
+}
+
+
+static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
+{
+    if (ht == htMD5) md5_finish_ctx(&ctx.md5, hash);
+    else if (ht == htSHA1) {
+        sha_final(&ctx.sha1);
+        sha_digest(&ctx.sha1, hash);
+    }
+}
+
+
+Hash hashString(const string & s, HashType ht)
+{
+    Ctx ctx;
+    Hash hash(ht);
+    start(ht, ctx);
+    update(ht, ctx, (const unsigned char *) s.c_str(), s.length());
+    finish(ht, ctx, hash.hash);
     return hash;
 }
 
 
-Hash hashFile(const Path & path)
+Hash hashFile(const Path & path, HashType ht)
 {
-    Hash hash(htMD5);
-    FILE * file = fopen(path.c_str(), "rb");
-    if (!file)
-        throw SysError(format("file `%1%' does not exist") % path);
-    int err = md5_stream(file, hash.hash);
-    fclose(file);
-    if (err) throw SysError(format("cannot hash file `%1%'") % path);
+    Ctx ctx;
+    Hash hash(ht);
+    start(ht, ctx);
+
+    AutoCloseFD fd = open(path.c_str(), O_RDONLY);
+    if (fd == -1) throw SysError(format("opening file `%1%'") % path);
+
+    unsigned char buf[8192];
+    ssize_t n;
+    while ((n = read(fd, buf, sizeof(buf)))) {
+        checkInterrupt();
+        if (n == -1) throw SysError(format("reading file `%1%'") % path);
+        update(ht, ctx, buf, n);
+    }
+    
+    finish(ht, ctx, hash.hash);
     return hash;
 }
 
 
 struct HashSink : DumpSink
 {
-    struct md5_ctx ctx;
+    HashType ht;
+    Ctx ctx;
     virtual void operator ()
         (const unsigned char * data, unsigned int len)
     {
-        md5_process_bytes(data, len, &ctx);
+        update(ht, ctx, data, len);
     }
 };
 
 
-Hash hashPath(const Path & path)
+Hash hashPath(const Path & path, HashType ht)
 {
-    Hash hash(htMD5);
     HashSink sink;
-    md5_init_ctx(&sink.ctx);
+    sink.ht = ht;
+    Hash hash(ht);
+    start(ht, sink.ctx);
     dumpPath(path, sink);
-    md5_finish_ctx(&sink.ctx, hash.hash);
+    finish(ht, sink.ctx, hash.hash);
     return hash;
 }