forked from Incubaid/rsync-demo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signature.ml
129 lines (113 loc) · 3.37 KB
/
signature.ml
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
open Hash
open Unix
module Signature = functor (W:WEAK) -> functor (S:STRONG) -> struct
type block_signature = {weak:int; strong:S.t; index:int}
let compare_weak ba bb = compare ba.weak bb.weak
let compare_index ba bb = compare ba.index bb.index
let bs_strong bs = bs.strong
let bs_index bs = bs.index
type t = {len:int; bs: int; blocks: block_signature array;}
let block_size t = t.bs
let length t = Array.length t.blocks
let optimal fn =
let stat = Unix.stat fn in
let size = stat.st_size in
let rc = int_of_float (2. *. sqrt (float size)) in (* thumb *)
let r = if rc < 32 then 32 else rc in
r
let lookup_weak t w =
let rec find min max =
let mid = (min + max) / 2 in
let block = t.blocks.(mid) in
let weak = block.weak in
if w = weak then Some block
else if min > max then None
else if w > weak then find (mid+1) max
else find min (mid -1)
in
let len = length t in
find 0 (len -1)
let create fn bs =
let ic = open_in fn in
let len = in_channel_length ic in
let buf = String.create bs in
let read_block size index =
let () = really_input ic buf 0 size in
let a = W.from buf 0 size in
let weak = W.digest a in
let strong = S.substring buf 0 size in
{weak;strong;index}
in
let rec read_blocks acc todo i =
if todo >= bs then
let block = read_block bs i in
read_blocks (block :: acc) (todo - bs) (i+1)
else
let block = read_block todo i in
List.rev (block :: acc)
in
let blocks_l = read_blocks [] len 0 in
let blocks = Array.of_list blocks_l in
let () = close_in ic in
Array.sort compare_weak blocks;
{len;bs;blocks;}
let output_signature oc t =
Io.write_int oc t.len;
Io.write_int oc t.bs;
Io.write_int oc (length t);
let i = ref 0 in
let one block =
Io.write_int oc block.weak;
S.write oc block.strong;
assert (block.index = !i);
(* i is skipped: in order because sorted *)
incr i
in
Array.sort compare_index t.blocks;
Array.iter one t.blocks;
Array.sort compare_weak t.blocks
let input_signature ic =
let len = Io.read_int ic in
let bs = Io.read_int ic in
let nblocks = Io.read_int ic in
let rec loop acc index =
if index = nblocks then List.rev acc
else
let weak = Io.read_int ic in
let strong = S.read ic in
let b = {weak;strong;index} in
loop (b :: acc) (index + 1) in
let blocks_l = loop [] 0 in
let blocks = Array.of_list blocks_l in
let r = {len;bs;blocks} in
Array.sort compare_weak r.blocks;
r
let to_file t fn =
let oc = open_out fn in
let () = output_signature oc t in
close_out oc
let from_file fn =
let ic = open_in fn in
let s = input_signature ic in
close_in ic;
s
let equals t1 t2 =
let so_far =
t1.len = t2.len &&
t1.bs = t2.bs in
let size1 = Array.length t1.blocks in
let size2 = Array.length t2.blocks in
let rec loop i acc =
if i = size1 then acc
else
begin
let bs1 = t1.blocks.(i)
and bs2 = t2.blocks.(i) in
let acc' = acc && bs1 = bs2
and i' = i+1 in
loop i' acc'
end
in
let r = so_far && size1 = size2 && loop 0 true in
r
end