Ensure metadata file is written prior to calculating checksum.
[cumulus.git] / hash.cc
1 /* Cumulus: Smart Filesystem Backup to Dumb Servers
2  *
3  * Copyright (C) 2012  Michael Vrable <vrable@cs.hmc.edu>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <map>
23 #include <string>
24
25 #include "hash.h"
26
27 using std::map;
28 using std::string;
29
30 static string default_algorithm;
31 static map<string, Hash *(*)()> hash_registry;
32
33 void Hash::Register(const std::string& name, Hash *(*constructor)())
34 {
35     printf("Registered hash algorithm %s\n", name.c_str());
36     hash_registry.insert(make_pair(name, constructor));
37 }
38
39 Hash *Hash::New()
40 {
41     return New(default_algorithm);
42 }
43
44 Hash *Hash::New(const std::string& name)
45 {
46     Hash *(*constructor)() = hash_registry[name];
47     if (!constructor)
48         return NULL;
49     else
50         return constructor();
51 }
52
53 std::string Hash::hash_file(const char *filename)
54 {
55     string result;
56     Hash *hash = Hash::New();
57     if (hash->update_from_file(filename))
58         result = hash->digest_str();
59
60     delete hash;
61     return result;
62 }
63
64 bool Hash::update_from_file(const char *filename)
65 {
66     FILE *f = fopen(filename, "rb");
67     if (f == NULL)
68         return false;
69
70     while (!feof(f)) {
71         char buf[4096];
72         size_t bytes = fread(buf, 1, sizeof(buf), f);
73
74         if (ferror(f)) {
75             fclose(f);
76             return false;
77         }
78
79         update(buf, bytes);
80     }
81
82     fclose(f);
83     return true;
84 }
85
86 const uint8_t *Hash::digest()
87 {
88     if (!digest_bytes) {
89         digest_bytes = finalize();
90     }
91
92     return digest_bytes;
93 }
94
95 string Hash::digest_str()
96 {
97     const uint8_t *raw_digest = digest();
98     size_t len = digest_size();
99     char hexbuf[len*2 + 1];
100
101     hexbuf[0] = '\0';
102     for (size_t i = 0; i < len; i++) {
103         snprintf(&hexbuf[2*i], 3, "%02x", raw_digest[i]);
104     }
105
106     return name() + "=" + hexbuf;
107 }
108
109 void sha1_register();
110 void sha256_register();
111
112 void hash_init()
113 {
114     sha1_register();
115     sha256_register();
116     default_algorithm = "sha224";
117 }