- Create the cache directly from the schema (installed) file.
[platform/upstream/libzypp.git] / zypp / Digest.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Digest.cc
10  *
11  * \todo replace by Blocxx
12  *
13 */
14
15 #include <cstdio> // snprintf
16 #include <openssl/evp.h>
17 #include <string>
18
19 #include <iostream>
20
21 #ifdef DIGEST_TESTSUITE
22 #include <fstream>
23 #endif
24
25 #include "zypp/Digest.h"
26
27 namespace zypp {
28
29     bool DigestReport::askUserToAcceptNoDigest( const zypp::Pathname &file )
30     { return true; }
31
32     bool DigestReport::askUserToAccepUnknownDigest( const Pathname &file, const std::string &name ) 
33     { return true; }
34
35     bool DigestReport::askUserToAcceptWrongDigest( const Pathname &file, const std::string &requested, const std::string &found ) 
36     { return true; }
37
38
39     // private data
40     class Digest::P
41     {
42         P(const P& p);
43         const P& operator=(const P& p);
44       public:
45         P();
46         ~P();
47     
48         EVP_MD_CTX mdctx;
49     
50         const EVP_MD *md;
51         unsigned char md_value[EVP_MAX_MD_SIZE];
52         unsigned md_len;
53     
54         bool initialized : 1;
55         bool finalized : 1;
56         static bool openssl_digests_added;
57     
58         std::string name;
59     
60         inline bool maybeInit();
61         inline void cleanup();
62     };
63     
64     
65     using namespace std;
66     
67     bool Digest::P::openssl_digests_added = false;
68     
69     Digest::P::P() :
70       md(NULL),
71       initialized(false),
72       finalized(false)
73     {
74     }
75     
76     Digest::P::~P()
77     {
78       cleanup();
79     }
80     
81     bool Digest::P::maybeInit()
82     {
83       if(!openssl_digests_added)
84       {
85         OpenSSL_add_all_digests();
86         openssl_digests_added = true;
87       }
88     
89       if(!initialized)
90       {
91         md = EVP_get_digestbyname(name.c_str());
92         if(!md)
93             return false;
94     
95         EVP_MD_CTX_init(&mdctx);
96     
97         if(!EVP_DigestInit_ex(&mdctx, md, NULL))
98             return false;
99     
100         md_len = 0;
101         ::memset(md_value, 0, sizeof(md_value));
102         initialized = true;
103       }
104     
105       return true;
106     }
107     
108     void Digest::P::cleanup()
109     {
110       if(initialized)
111       {
112         EVP_MD_CTX_cleanup(&mdctx);
113         initialized = false;
114       }
115     }
116     
117     Digest::Digest() : _dp(new P())
118     {
119     }
120     
121     Digest::~Digest()
122     {
123       delete _dp;
124     }
125     
126     bool Digest::create(const std::string& name)
127     {
128       if(name.empty()) return false;
129     
130       if(_dp->initialized)
131         _dp->cleanup();
132     
133       _dp->name = name;
134     
135       return _dp->maybeInit();
136     }
137     
138     const std::string& Digest::name()
139     {
140       return _dp->name;
141     }
142     
143     std::string Digest::digest()
144     {
145       if(!_dp->maybeInit())
146         return false;
147     
148       if(!_dp->finalized)
149       {
150         if(!EVP_DigestFinal_ex(&_dp->mdctx, _dp->md_value, &_dp->md_len))
151             return false;
152     
153         _dp->finalized = true;
154       }
155     
156       char mdtxt[_dp->md_len*2 + 1];
157       mdtxt[_dp->md_len*2] = '\0';
158     
159       for(unsigned i = 0; i < _dp->md_len; ++i)
160       {
161         ::snprintf(mdtxt + i*2, 3, "%02hhx", _dp->md_value[i]);
162       }
163     
164       return std::string(mdtxt);
165     }
166     
167     bool Digest::update(const char* bytes, size_t len)
168     {
169       if(!bytes)
170       {
171         return false;
172       }
173     
174       if(!_dp->maybeInit())
175         return false;
176     
177       if(_dp->finalized)
178       {
179         _dp->cleanup();
180         if(!_dp->maybeInit())
181             return false;
182     
183       }
184       if(!EVP_DigestUpdate(&_dp->mdctx, reinterpret_cast<const unsigned char*>(bytes), len))
185         return false;
186     
187       return true;
188     }
189     
190     std::string Digest::digest(const std::string& name, std::istream& is, size_t bufsize)
191     {
192       if(name.empty() || !is)
193         return string();
194     
195       char buf[bufsize];
196       size_t num = 0;
197     
198       Digest digest;
199       if(!digest.create(name))
200         return string();
201     
202       
203       while(is.good())
204       {
205         int readed;
206         is.read(buf, bufsize);
207         readed = is.gcount();
208         if(readed && !digest.update(buf, readed))
209             return string();
210       }
211     
212       return digest.digest();
213     }
214     
215 #ifdef DIGEST_TESTSUITE
216     int main(int argc, char *argv[])
217     {
218       bool openssl = false;
219       unsigned argpos = 1;
220     
221       if(argc > 1 && string(argv[argpos]) == "--openssl")
222       {
223         openssl = true;
224         ++argpos;
225       }
226     
227       if(argc - argpos < 2)
228       {
229         cerr << "Usage: " << argv[0] << " <DIGESTNAME> <FILE>" << endl;
230         return 1;
231       }
232     
233       const char* digestname = argv[argpos++];
234       const char* fn = argv[argpos++];
235     
236       ifstream file(fn);
237     
238       string digest = Digest::digest(digestname, file);
239     
240       if(openssl)
241         cout << digestname << "(" << fn << ")= " << digest << endl;
242       else
243         cout << digest << "  " << fn << endl;
244     
245       return 0;
246     }
247 #endif
248     
249 } // namespace zypp