-
Notifications
You must be signed in to change notification settings - Fork 3
/
digest.lisp
119 lines (95 loc) · 3.75 KB
/
digest.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#+xcvb (module (:depends-on ("pkgdcl")))
(in-package :xcvb)
#|
If/when ironclad provides tth, we should use that.
Until then, let's rely on the external utility tthsum.
|#
(defparameter +base32-characters+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
(defun tthsum-for-files (files)
(loop :for file :in files
:for p = (probe-file file)
:collect (when p
(output-tthsum (tthsum-file p)))))
(defun ensure-tthsum-present ()
(values))
#| ;; Implementation from before we were using ironclad
(defun tthsum-for-files (files)
(when files
(let* ((truefiles
(loop :for file :in files :collect
(or (probe-file file) (error "File ~A does not exist" file))))
(namestrings (mapcar #'namestring truefiles))
(lines (run-program (cons "tthsum" namestrings) :output :lines)))
(unless lines
(error "Couldn't extract TTH digest for given files. Is the tthsum utility installed?"))
(unless (list-of-length-p (length files) lines)
(error "tthsum output has wrong number of lines"))
(loop :for file :in files
:for namestring :in namestrings
:for line :in lines
:for len = (length line)
:collect
(progn
(unless (and (= len (+ 41 (length namestring)))
(string= line " " :start1 39 :end1 41)
(string= line namestring :start1 41)
(loop :repeat 39 :for c :across line
:always (find c +base32-characters+)))
(error "unexpected tthsum output line ~S for file ~S" line file))
(subseq line 0 39))))))
(defun has-tthsum-p ()
(let ((s (ignore-errors
(run-program
'("tthsum" #-windows "/dev/null" #+windows "NUL")
:output :string))))
(and (>= (length s) 41)
(string= s "LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ" :end1 39))))
(defun ensure-tthsum-present ()
(unless (has-tthsum-p)
(errexit 2 "~&XCVB's master mode (enabled by default) requires the tthsum utility.
If you are using Debian or Ubuntu, you can install it with:
sudo apt-get install tthsum
If you are unable to install this utility, you may disable XCVB's master mode
by passing option --no-master to xcvb make-makefile.
The XCVB master mode is what allows you to load into a running image
new or updated FASLs that you build with XCVB.~%")))
|#
(defun tthsum-for-files-or-nil (specs)
(let* ((files (remove nil specs))
(tthsums (tthsum-for-files files)))
(loop :for spec :in specs
:collect (when spec (pop tthsums)))))
(defun tthsum-for-file (file)
(car (tthsum-for-files (list file))))
(defun output-tthsum (sum &optional s)
(with-output (s)
(princ (tthsum-to-string sum) s)))
(defun tthsum-to-string (sum)
;; beware: a base-string, not a simple-string, so not simply readable
(subseq (binascii:encode sum :base32) 0 39))
(defun tthsum-from-string (string)
(binascii:decode string :base32))
(defun tthsum-string (string)
(tthsum-sequence (babel:string-to-octets string :encoding :utf-8)))
(defun tthsum-sequence (sequence)
(ironclad:digest-sequence :tree-hash sequence))
(defun tthsum-file (file)
(ironclad:digest-file :tree-hash file))
(defun tthsum-stream (stream)
(ironclad:digest-stream :tree-hash stream))
(defun tthsum-object (object)
(tthsum-string
(with-safe-io-syntax ()
(write-to-string object
:readably nil :pretty nil))))
(defgeneric digest (x))
(defmethod digest ((x string))
(tthsum-string x))
(defmethod digest ((x vector))
(unless (typep x '(simple-array (unsigned-byte 8) (*)))
(error "Can only digest ub8 vectors and strings"))
(tthsum-sequence x))
(defmethod digest ((x pathname))
(tthsum-file x))
(defmethod digest ((x cons))
(tthsum-object x))