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
let sizeof_pointer = 4
let inline_struct_chunk = 0x01
let file_chunk = 0x01
let ctz_chunk = 0x02
let name n id = Tag.({
valid = true;
type3 = (Tag.LFS_TYPE_NAME, file_chunk);
id;
length = String.length n;
}, Cstruct.of_string n)
let create_inline id contents = Tag.({
valid = true;
type3 = (Tag.LFS_TYPE_STRUCT, inline_struct_chunk);
id;
length = (Cstruct.length contents);
})
let create_ctz id ~pointer ~file_size =
let cs = Cstruct.create (4 * 2) in
Cstruct.LE.set_uint32 cs 0 pointer;
Cstruct.LE.set_uint32 cs 4 file_size;
Tag.({
valid = true;
type3 = (Tag.LFS_TYPE_STRUCT, ctz_chunk);
id;
length = (Cstruct.length cs);
}, cs)
let ctz_of_cstruct cs =
if Cstruct.length cs < 8 then None
else Some Cstruct.LE.(get_uint32 cs 0, get_uint32 cs 4)
let write_inline n id contents =
[name n id; (create_inline id contents), contents; ]
let n_pointers = function
| 0 -> 0
| 1 -> 1
| n ->
let log2 = Float.log (float_of_int n) /. Float.log (float_of_int 2) in
if Float.is_integer log2 then
Float.to_int log2
else 1
let of_block index cs =
let sizeof_pointer = 4 in
let pointer_count = n_pointers index in
let pointers = List.init pointer_count (fun n ->
Cstruct.LE.get_uint32 cs (sizeof_pointer * n)
) in
let sizeof_data = (Cstruct.length cs) - (sizeof_pointer * pointer_count) in
(pointers, Cstruct.sub cs (pointer_count * sizeof_pointer) sizeof_data)
let last_block_index ~file_size ~block_size =
if file_size <= block_size then 0 else begin
let popcount_arg = (file_size / (block_size - (2 * sizeof_pointer))) - 1 |> Int32.of_int in
let numerator = file_size - (sizeof_pointer * (Bitwise.popcount popcount_arg)) + 2 in
numerator / (block_size - 2 * sizeof_pointer)
end