Extend SHA256 support elsewhere
[jigdo.git] / src / mkimage.hh
1 /* $Id: mkimage.hh,v 1.3 2004/09/12 21:08:28 atterer Exp $ -*- C++ -*-
2   __   _
3   |_) /|  Copyright (C) 2001-2002  |  richard@
4   | \/¯|  Richard Atterer          |  atterer.org
5   ¯ '` ¯
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License, version 2. See
8   the file COPYING for details.
9
10 *//** @file
11
12   Create image from template / merge new files into image.tmp
13
14 */
15
16 #ifndef MKIMAGE_HH
17 #define MKIMAGE_HH
18
19 #include <config.h>
20
21 #include <iosfwd>
22 #include <queue>
23 #include <vector>
24 #include <typeinfo>
25
26 #include <bstream.hh>
27 #include <debug.hh>
28 #include <md5sum.hh>
29 #include <sha256sum.hh>
30 #include <scan.hh>
31 #include <serialize.hh>
32 //______________________________________________________________________
33
34 /** Errors thrown by the JigdoDesc code */
35 struct JigdoDescError : Error {
36   explicit JigdoDescError(const string& m) : Error(m) { }
37   explicit JigdoDescError(const char* m) : Error(m) { }
38 };
39
40 /** Entry in a DESC section of a jigdo template. This definition is
41     used both for an abstract base class and as a namespace for child
42     classes. */
43 class JigdoDesc {
44 public:
45   /** Types of entries in a description section */
46   enum Type {
47     OBSOLETE_IMAGE_INFO = 1,
48     UNMATCHED_DATA = 2,
49     OBSOLETE_MATCHED_FILE = 3,
50     OBSOLETE_WRITTEN_FILE = 4,
51     IMAGE_INFO_MD5 = 5,
52     MATCHED_FILE_MD5 = 6,
53     WRITTEN_FILE_MD5 = 7,
54     IMAGE_INFO_SHA256 = 8,
55     MATCHED_FILE_SHA256 = 9,
56     WRITTEN_FILE_SHA256 = 10
57   };
58   class ProgressReporter;
59   //____________________
60
61   virtual bool operator==(const JigdoDesc& x) const = 0;
62   inline bool operator!=(const JigdoDesc& x) const { return !(*this == x); }
63   virtual ~JigdoDesc() = 0;
64
65   /** Entry type of JigdoDesc child class */
66   virtual Type type() const = 0;
67   /** Output human-readable summary */
68   virtual ostream& put(ostream& s) const = 0;
69   /** Size of image area or whole image */
70   virtual uint64 size() const = 0;
71
72   /** There are no virtual templates, so this wouldn't work:<code>
73       template<class Iterator>
74       virtual Iterator serialize(Iterator i) const; </code> */
75   virtual size_t serialSizeOf() const = 0;
76
77   /** Check whether the file is a .template file, i.e. has the
78       appropriate ASCII header */
79   static bool isTemplate(bistream& file);
80   /** Assuming that a DESC section is at the end of a file, set the
81       file pointer to the start of the section, allowing you to call
82       read() immediately afterwards. */
83   static void seekFromEnd(bistream& file);
84   /** Create image file from template and files (via JigdoCache) */
85   static int makeImage(JigdoCache* cache, const string& imageFile,
86     const string& imageTmpFile, const string& templFile,
87     bistream* templ, const bool optForce,
88     ProgressReporter& pr = noReport, size_t readAmnt = 128U*1024,
89     const bool optMkImageCheck = true);
90   /** Return list of MD5sums of files that still need to be copied to
91       the image to complete it. Reads info from tmp file or (if
92       imageTmpFile.empty() or error opening tmp file) outputs complete
93       list from template. */
94   static int listMissingMD5(set<MD5>& result, const string& imageTmpFile,
95     const string& templFile, bistream* templ, ProgressReporter& reporter);
96   /** Return list of SHA256sums of files that still need to be copied to
97       the image to complete it. Reads info from tmp file or (if
98       imageTmpFile.empty() or error opening tmp file) outputs complete
99       list from template. */
100   static int listMissingSHA256(set<SHA256>& result, const string& imageTmpFile,
101     const string& templFile, bistream* templ, ProgressReporter& reporter);
102
103   class ImageInfoMD5;
104   class ImageInfoSHA256;
105   class UnmatchedData;
106   class MatchedFileMD5;
107   class MatchedFileSHA256;
108   class WrittenFileMD5;
109   class WrittenFileSHA256;
110
111 private:
112   static ProgressReporter noReport;
113 };
114
115 inline ostream& operator<<(ostream& s, JigdoDesc& jd) { return jd.put(s); }
116 //______________________________________________________________________
117
118 /** Information about the image file */
119 class JigdoDesc::ImageInfoMD5 : public JigdoDesc {
120 public:
121   inline ImageInfoMD5(uint64 s, const MD5& m, size_t b);
122   inline ImageInfoMD5(uint64 s, const MD5Sum& m, size_t b);
123   inline bool operator==(const JigdoDesc& x) const;
124   Type type() const { return IMAGE_INFO_MD5; }
125   uint64 size() const { return sizeVal; }
126   const MD5& md5() const { return md5Val; }
127   size_t blockLength() const { return blockLengthVal; }
128   // Default dtor, operator==
129   virtual ostream& put(ostream& s) const;
130
131   template<class Iterator>
132   inline Iterator serialize(Iterator i) const;
133   inline size_t serialSizeOf() const;
134
135 private:
136   uint64 sizeVal;
137   MD5 md5Val;
138   size_t blockLengthVal;
139 };
140 //________________________________________
141
142 /** Information about the image file */
143 class JigdoDesc::ImageInfoSHA256 : public JigdoDesc {
144 public:
145   inline ImageInfoSHA256(uint64 s, const SHA256& m, size_t b);
146   inline ImageInfoSHA256(uint64 s, const SHA256Sum& m, size_t b);
147   inline bool operator==(const JigdoDesc& x) const;
148   Type type() const { return IMAGE_INFO_SHA256; }
149   uint64 size() const { return sizeVal; }
150   const SHA256& sha256() const { return sha256Val; }
151   size_t blockLength() const { return blockLengthVal; }
152   // Default dtor, operator==
153   virtual ostream& put(ostream& s) const;
154
155   template<class Iterator>
156   inline Iterator serialize(Iterator i) const;
157   inline size_t serialSizeOf() const;
158
159 private:
160   uint64 sizeVal;
161   SHA256 sha256Val;
162   size_t blockLengthVal;
163 };
164 //________________________________________
165
166 /** Info about data that was not matched by any input file, i.e.
167     that is included in the template data verbatim */
168 class JigdoDesc::UnmatchedData : public JigdoDesc {
169 public:
170   UnmatchedData(uint64 o, uint64 s) : offsetVal(o), sizeVal(s) { }
171   inline bool operator==(const JigdoDesc& x) const;
172   Type type() const { return UNMATCHED_DATA; }
173   uint64 offset() const { return offsetVal; }
174   uint64 size() const { return sizeVal; }
175   void resize(uint64 s) { sizeVal = s; }
176   // Default dtor, operator==
177   virtual ostream& put(ostream& s) const;
178
179   template<class Iterator>
180   inline Iterator serialize(Iterator i) const;
181   inline size_t serialSizeOf() const;
182
183 private:
184   uint64 offsetVal; // Offset in image
185   uint64 sizeVal;
186 };
187 //________________________________________
188
189 /** Info about data that *was* matched by an input file */
190 class JigdoDesc::MatchedFileMD5 : public JigdoDesc {
191 public:
192   inline MatchedFileMD5(uint64 o, uint64 s, const RsyncSum64& r, const MD5& m);
193   inline MatchedFileMD5(uint64 o, uint64 s, const RsyncSum64& r,
194                      const MD5Sum& m);
195   inline bool operator==(const JigdoDesc& x) const;
196   Type type() const { return MATCHED_FILE_MD5; }
197   uint64 offset() const { return offsetVal; }
198   uint64 size() const { return sizeVal; }
199   const MD5& md5() const { return md5Val; }
200   const RsyncSum64& rsync() const { return rsyncVal; }
201   // Default dtor, operator==
202   virtual ostream& put(ostream& s) const;
203
204   template<class Iterator>
205   inline Iterator serialize(Iterator i) const;
206   inline size_t serialSizeOf() const;
207
208 private:
209   uint64 offsetVal; // Offset in image
210   uint64 sizeVal;
211   RsyncSum64 rsyncVal;
212   MD5 md5Val;
213 };
214 //________________________________________
215
216 /** Like MatchedFileMD5 - used only in .tmp files to express that the
217     file data was successfully written to the image. NB: Because this
218     derives from MatchedFileMD5 and because of the implementation of
219     JigdoDesc::operator==, MatchedFileMD5's and WrittenFileMD5's will
220     compare equal if their data fields are identical. */
221 class JigdoDesc::WrittenFileMD5 : public MatchedFileMD5 {
222 public:
223   WrittenFileMD5(uint64 o, uint64 s, const RsyncSum64& r, const MD5& m)
224     : MatchedFileMD5(o, s, r, m) { }
225   // Implicit cast to allow MatchedFileMD5 and WrittenFileMD5 to compare equal
226   inline bool operator==(const JigdoDesc& x) const;
227   Type type() const { return WRITTEN_FILE_MD5; }
228   virtual ostream& put(ostream& s) const;
229
230   template<class Iterator>
231   inline Iterator serialize(Iterator i) const;
232   inline size_t serialSizeOf() const;
233 };
234 //______________________________________________________________________
235
236 /** Info about data that *was* matched by an input file */
237 class JigdoDesc::MatchedFileSHA256 : public JigdoDesc {
238 public:
239   inline MatchedFileSHA256(uint64 o, uint64 s, const RsyncSum64& r, const SHA256& m);
240   inline MatchedFileSHA256(uint64 o, uint64 s, const RsyncSum64& r,
241                      const SHA256Sum& m);
242   inline bool operator==(const JigdoDesc& x) const;
243   Type type() const { return MATCHED_FILE_SHA256; }
244   uint64 offset() const { return offsetVal; }
245   uint64 size() const { return sizeVal; }
246   const SHA256& sha256() const { return sha256Val; }
247   const RsyncSum64& rsync() const { return rsyncVal; }
248   // Default dtor, operator==
249   virtual ostream& put(ostream& s) const;
250
251   template<class Iterator>
252   inline Iterator serialize(Iterator i) const;
253   inline size_t serialSizeOf() const;
254
255 private:
256   uint64 offsetVal; // Offset in image
257   uint64 sizeVal;
258   RsyncSum64 rsyncVal;
259   SHA256 sha256Val;
260 };
261 //________________________________________
262
263 /** Like MatchedFileSHA256 - used only in .tmp files to express that the
264     file data was successfully written to the image. NB: Because this
265     derives from MatchedFileSHA256 and because of the implementation of
266     JigdoDesc::operator==, MatchedFileSHA256's and WrittenFileSHA256's will
267     compare equal if their data fields are identical. */
268 class JigdoDesc::WrittenFileSHA256 : public MatchedFileSHA256 {
269 public:
270   WrittenFileSHA256(uint64 o, uint64 s, const RsyncSum64& r, const SHA256& m)
271     : MatchedFileSHA256(o, s, r, m) { }
272   // Implicit cast to allow MatchedFileSHA256 and WrittenFileSHA256 to compare equal
273   inline bool operator==(const JigdoDesc& x) const;
274   Type type() const { return WRITTEN_FILE_SHA256; }
275   virtual ostream& put(ostream& s) const;
276
277   template<class Iterator>
278   inline Iterator serialize(Iterator i) const;
279   inline size_t serialSizeOf() const;
280 };
281 //______________________________________________________________________
282
283 /** Class allowing JigdoDesc to convey information back to the caller.
284     The default versions of the methods do nothing at all (except for
285     error(), which prints the error to cerr) - you need to supply an
286     object of a derived class to functions to get called back. */
287 class JigdoDesc::ProgressReporter {
288 public:
289   virtual ~ProgressReporter() { }
290   /** General-purpose error reporting. */
291   virtual void error(const string& message);
292   /** Like error(), but for purely informational messages. */
293   virtual void info(const string& message);
294   /** Called when the output image (or a temporary file) is being
295       written to. It holds that written==imgOff and
296       totalToWrite==imgSize, *except* when additional files are merged
297       into an already existing temporary file.
298       @param written Number of bytes written so far
299       @param totalToWrite Value of 'written' at end of write operation
300       @param imgOff Current offset in image
301       @param imgSize Total size of output image */
302   virtual void writingImage(uint64 written, uint64 totalToWrite,
303                             uint64 imgOff, uint64 imgSize);
304 };
305 //______________________________________________________________________
306
307 /** Container for JidoDesc objects. Is mostly a vector<JidoDesc*>, but
308     deletes elements when destroyed. However, when removing elements,
309     resizing the JigdoDescVec etc., the elements are *not* deleted
310     automatically. */
311 class JigdoDescVec : public vector<JigdoDesc*> {
312 public:
313   JigdoDescVec() : vector<JigdoDesc*>() { }
314   inline ~JigdoDescVec();
315
316   /** Read JigdoDescs from a template file into *this. *this is
317       clear()ed first. File pointer must be at start of first entry;
318       the "DESC" must have been read already. If error is thrown,
319       position of file pointer is undefined. A type 1 (IMAGE_INFO_MD5)
320       will end up at this->back(). */
321   bistream& get(bistream& file);
322
323   /** Write a DESC section to a binary stream. Note that there should
324       not be two contiguous Unmatched regions - this is not checked.
325       Similarly, the length of the ImageInfo* part must match the
326       accumulated lengths of the other parts. */
327   bostream& put(bostream& file, MD5Sum* md = 0, SHA256Sum* sd = 0, int checksumChoice = 0) const;
328
329   /** List contents of a JigdoDescVec to a stream in human-readable format. */
330   void list(ostream& s) throw();
331 private:
332   // Disallow copying (too inefficient). Use swap() instead.
333   inline JigdoDescVec& operator=(const JigdoDescVec&);
334 };
335
336 inline void swap(JigdoDescVec& x, JigdoDescVec& y) { x.swap(y); }
337
338 //======================================================================
339
340 JigdoDesc::ImageInfoMD5::ImageInfoMD5(uint64 s, const MD5& m, size_t b)
341   : sizeVal(s), md5Val(m), blockLengthVal(b) { }
342 JigdoDesc::ImageInfoMD5::ImageInfoMD5(uint64 s, const MD5Sum& m, size_t b)
343   : sizeVal(s), md5Val(m), blockLengthVal(b) { }
344 JigdoDesc::ImageInfoSHA256::ImageInfoSHA256(uint64 s, const SHA256& m, size_t b)
345   : sizeVal(s), sha256Val(m), blockLengthVal(b) { }
346 JigdoDesc::ImageInfoSHA256::ImageInfoSHA256(uint64 s, const SHA256Sum& m, size_t b)
347   : sizeVal(s), sha256Val(m), blockLengthVal(b) { }
348
349 JigdoDesc::MatchedFileMD5::MatchedFileMD5(uint64 o, uint64 s, const RsyncSum64& r,
350                                     const MD5& m)
351   : offsetVal(o), sizeVal(s), rsyncVal(r), md5Val(m) { }
352 JigdoDesc::MatchedFileSHA256::MatchedFileSHA256(uint64 o, uint64 s, const RsyncSum64& r,
353                                     const SHA256& m)
354   : offsetVal(o), sizeVal(s), rsyncVal(r), sha256Val(m) { }
355 JigdoDesc::MatchedFileMD5::MatchedFileMD5(uint64 o, uint64 s, const RsyncSum64& r,
356                                     const MD5Sum& m)
357   : offsetVal(o), sizeVal(s), rsyncVal(r), md5Val(m) { }
358 JigdoDesc::MatchedFileSHA256::MatchedFileSHA256(uint64 o, uint64 s, const RsyncSum64& r,
359                                     const SHA256Sum& m)
360   : offsetVal(o), sizeVal(s), rsyncVal(r), sha256Val(m) { }
361
362 //________________________________________
363
364 bool JigdoDesc::ImageInfoMD5::operator==(const JigdoDesc& x) const {
365   const ImageInfoMD5* i = dynamic_cast<const ImageInfoMD5*>(&x);
366   if (i == 0) return false;
367   else return size() == i->size() && md5() == i->md5();
368 }
369
370 bool JigdoDesc::ImageInfoSHA256::operator==(const JigdoDesc& x) const {
371   const ImageInfoSHA256* i = dynamic_cast<const ImageInfoSHA256*>(&x);
372   if (i == 0) return false;
373   else return size() == i->size() && sha256() == i->sha256();
374 }
375
376 bool JigdoDesc::UnmatchedData::operator==(const JigdoDesc& x) const {
377   const UnmatchedData* u = dynamic_cast<const UnmatchedData*>(&x);
378   if (u == 0) return false;
379   else return size() == u->size();
380 }
381
382 bool JigdoDesc::MatchedFileMD5::operator==(const JigdoDesc& x) const {
383   const MatchedFileMD5* m = dynamic_cast<const MatchedFileMD5*>(&x);
384   if (m == 0) return false;
385   else return offset() == m->offset() && size() == m->size()
386               && md5() == m->md5();
387 }
388
389 bool JigdoDesc::MatchedFileSHA256::operator==(const JigdoDesc& x) const {
390   const MatchedFileSHA256* m = dynamic_cast<const MatchedFileSHA256*>(&x);
391   if (m == 0) return false;
392   else return offset() == m->offset() && size() == m->size()
393               && sha256() == m->sha256();
394 }
395
396 bool JigdoDesc::WrittenFileMD5::operator==(const JigdoDesc& x) const {
397   // NB MatchedFileMD5 and WrittenFileMD5 considered equal!
398   const MatchedFileMD5* m = dynamic_cast<const MatchedFileMD5*>(&x);
399   if (m == 0) return false;
400   else return offset() == m->offset() && size() == m->size()
401               && md5() == m->md5();
402 }
403
404 bool JigdoDesc::WrittenFileSHA256::operator==(const JigdoDesc& x) const {
405   // NB MatchedFileSHA256 and WrittenFileSHA256 considered equal!
406   const MatchedFileSHA256* m = dynamic_cast<const MatchedFileSHA256*>(&x);
407   if (m == 0) return false;
408   else return offset() == m->offset() && size() == m->size()
409               && sha256() == m->sha256();
410 }
411 //________________________________________
412
413 inline bistream& operator>>(bistream& s, JigdoDescVec& v) {
414   return v.get(s);
415 }
416
417 inline bostream& operator<<(bostream& s, JigdoDescVec& v) {
418   return v.put(s);
419 }
420
421 JigdoDescVec::~JigdoDescVec() {
422   for (iterator i = begin(), e = end(); i != e; ++i) delete *i;
423 }
424 //________________________________________
425
426 template<class Iterator>
427 Iterator JigdoDesc::ImageInfoMD5::serialize(Iterator i) const {
428   i = serialize1(IMAGE_INFO_MD5, i);
429   i = serialize6(size(), i);
430   i = ::serialize(md5(), i);
431   i = serialize4(blockLength(), i);
432   return i;
433 }
434 size_t JigdoDesc::ImageInfoMD5::serialSizeOf() const { return 1 + 6 + 16 + 4; }
435
436 template<class Iterator>
437 Iterator JigdoDesc::ImageInfoSHA256::serialize(Iterator i) const {
438   i = serialize1(IMAGE_INFO_SHA256, i);
439   i = serialize6(size(), i);
440   i = ::serialize(sha256(), i);
441   i = serialize4(blockLength(), i);
442   return i;
443 }
444 size_t JigdoDesc::ImageInfoSHA256::serialSizeOf() const { return 1 + 6 + 32 + 4; }
445
446 template<class Iterator>
447 Iterator JigdoDesc::UnmatchedData::serialize(Iterator i) const {
448   i = serialize1(UNMATCHED_DATA, i);
449   i = serialize6(size(), i);
450   return i;
451 }
452 size_t JigdoDesc::UnmatchedData::serialSizeOf() const { return 1 + 6; }
453
454 template<class Iterator>
455 Iterator JigdoDesc::MatchedFileMD5::serialize(Iterator i) const {
456   i = serialize1(MATCHED_FILE_MD5, i);
457   i = serialize6(size(), i);
458   i = ::serialize(rsync(), i);
459   i = ::serialize(md5(), i);
460   return i;
461 }
462 size_t JigdoDesc::MatchedFileMD5::serialSizeOf() const { return 1 + 6 + 8 + 16;}
463
464 template<class Iterator>
465 Iterator JigdoDesc::MatchedFileSHA256::serialize(Iterator i) const {
466   i = serialize1(MATCHED_FILE_SHA256, i);
467   i = serialize6(size(), i);
468   i = ::serialize(rsync(), i);
469   i = ::serialize(sha256(), i);
470   return i;
471 }
472 size_t JigdoDesc::MatchedFileSHA256::serialSizeOf() const { return 1 + 6 + 8 + 32;}
473
474 template<class Iterator>
475 Iterator JigdoDesc::WrittenFileMD5::serialize(Iterator i) const {
476   i = serialize1(WRITTEN_FILE_MD5, i);
477   i = serialize6(size(), i);
478   i = ::serialize(rsync(), i);
479   i = ::serialize(md5(), i);
480   return i;
481 }
482 size_t JigdoDesc::WrittenFileMD5::serialSizeOf() const { return 1 + 6 + 8 + 16;}
483
484 template<class Iterator>
485 Iterator JigdoDesc::WrittenFileSHA256::serialize(Iterator i) const {
486   i = serialize1(WRITTEN_FILE_SHA256, i);
487   i = serialize6(size(), i);
488   i = ::serialize(rsync(), i);
489   i = ::serialize(sha256(), i);
490   return i;
491 }
492 size_t JigdoDesc::WrittenFileSHA256::serialSizeOf() const { return 1 + 6 + 8 + 32;}
493
494
495 #endif