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
120
121
122
123
124
125
126
127
128
129
130
131
open OpamCompat
type kind = [ `MD5 | `SHA256 | `SHA512 ]
let default_kind = `MD5
type t = kind * string
let kind = fst
let contents = snd
let log msg = OpamConsole.log "HASH" msg
let pfx_sep_char = '='
let pfx_sep_str = String.make 1 pfx_sep_char
let string_of_kind = function
| `MD5 -> "md5"
| `SHA256 -> "sha256"
| `SHA512 -> "sha512"
let kind_of_string s = match String.lowercase_ascii s with
| "md5" -> `MD5
| "sha256" -> `SHA256
| "sha512" -> `SHA512
| _ -> invalid_arg "OpamHash.kind_of_string"
let is_hex_str len s =
String.length s = len &&
try
String.iter (function
| '0'..'9' | 'A'..'F' | 'a'..'f' -> ()
| _ -> raise Exit)
s;
true
with Exit -> false
let len = function
| `MD5 -> 32
| `SHA256 -> 64
| `SHA512 -> 128
let valid kind = is_hex_str (len kind)
let make kind s =
if valid kind s then kind, String.lowercase_ascii s
else invalid_arg ("OpamHash.make_"^string_of_kind kind)
let md5 = make `MD5
let sha256 = make `SHA256
let sha512 = make `SHA512
let of_string_opt s =
try
let kind, s =
match OpamStd.String.cut_at s pfx_sep_char with
| None -> `MD5, s
| Some (skind, s) -> kind_of_string skind, s
in
if valid kind s then Some (kind, String.lowercase_ascii s)
else None
with Invalid_argument _ -> None
let of_string s =
match of_string_opt s with
| Some h -> h
| None -> invalid_arg "OpamHash.of_string"
let to_string (kind,s) =
String.concat pfx_sep_str [string_of_kind kind; s]
let to_json s = `String (to_string s)
let to_path (kind,s) =
[string_of_kind kind; String.sub s 0 2; s]
let compute ?(kind=default_kind) file = match kind with
| `MD5 -> md5 (Digest.to_hex (Digest.file file))
| (`SHA256 | `SHA512) as kind ->
let sha =
if not OpamCoreConfig.(!r.use_openssl) then
OpamSHA.hash kind file
else
try
match
OpamSystem.read_command_output ["openssl"; string_of_kind kind; file]
with
| [l] ->
let len = len kind in
String.sub l (String.length l - len) len
| _ ->
log "openssl error, use internal sha library";
OpamSHA.hash kind file
with OpamSystem.Command_not_found _ | OpamSystem.Process_error _ ->
log "openssl not found, use internal sha library";
OpamSHA.hash kind file
in
make kind sha
let compute_from_string ?(kind=default_kind) str = match kind with
| `MD5 -> md5 (Digest.to_hex (Digest.string str))
| (`SHA256 | `SHA512) as kind ->
make kind (OpamSHA.hash_bytes kind (Bytes.of_string str))
let check_file f (kind, _ as h) = compute ~kind f = h
let mismatch f (kind, _ as h) =
let hf = compute ~kind f in
if hf = h then None else Some hf
module O = struct
type _t = t
type t = _t
let to_string = to_string
let to_json = to_json
let compare = compare
end
module Set = OpamStd.Set.Make(O)
module Map = OpamStd.Map.Make(O)