-
Notifications
You must be signed in to change notification settings - Fork 163
/
isoinfo.ml
132 lines (116 loc) · 4.94 KB
/
isoinfo.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
130
131
132
(* Parse isoinfo or xorriso output.
* Copyright (C) 2009-2021 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
open Printf
open Unix
open Std_utils
include Structs
(* We treat ISO "strA" and "strD" formats the same way, simply
* discarding any trailing spaces.
*)
let iso_parse_strA str =
let len = String.length str in
let rec loop len =
if len > 0 && str.[len-1] = ' ' then loop (len-1) else len
in
let len = loop len in
String.sub str 0 len
let iso_parse_strD = iso_parse_strA
(* These always parse the intX_LSB (little endian) version. *)
let iso_parse_int16 s = s |> int_of_le16 |> Int64.to_int32
let iso_parse_int32 s = s |> int_of_le32 |> Int64.to_int32
(* Parse ISO dec-datetime to a Unix time_t. *)
let iso_parse_datetime str =
if String.sub str 0 16 = "0000000000000000" then -1_L
else (
let tm_year = int_of_string (String.sub str 0 4) in
let tm_mon = int_of_string (String.sub str 4 2) in
let tm_mday = int_of_string (String.sub str 6 2) in
let tm_hour = int_of_string (String.sub str 8 2) in
let tm_min = int_of_string (String.sub str 10 2) in
let tm_sec = int_of_string (String.sub str 12 2) in
(* Adjust fields. *)
let tm_year = tm_year - 1900 in
let tm_mon = tm_mon - 1 in
(* Convert to time_t in UTC timezone. *)
let tm = { tm_sec; tm_min; tm_hour; tm_mday; tm_mon; tm_year;
tm_wday = -1; tm_yday = -1; tm_isdst = false } in
let old_TZ = try Some (getenv "TZ") with Not_found -> None in
putenv "TZ" "UTC";
let r = Int64.of_float (fst (mktime tm)) in
Option.may (putenv "TZ") old_TZ;
(* The final byte is a time zone offset from GMT.
*
* The documentation of this at
* https://wiki.osdev.org/ISO_9660#The_Primary_Volume_Descriptor
* is wrong. See the ECMA 119 documentation for a correct
* description.
*
* For a disk image which we know was created
* in BST (GMT+1), this contains 0x4, ie. 4 * 15 mins ahead.
* We have to subtract this from the gmtime above.
*)
let tz = Char.code str.[16] in
let tz = if tz >= 128 then tz - 256 else tz in
r -^ (Int64.of_int (tz * 15 * 60))
)
let isoinfo_device dev =
let r, pvd =
with_openfile dev [O_RDONLY] 0 (
fun fd ->
ignore (lseek fd 32768 SEEK_SET);
let pvd = Bytes.create 2048 in
let r = read fd pvd 0 2048 in
r, Bytes.to_string pvd
) in
let sub = String.sub pvd in
(* Check that it looks like an ISO9660 Primary Volume Descriptor.
* https://wiki.osdev.org/ISO_9660#The_Primary_Volume_Descriptor
*)
if r <> 2048 || pvd.[0] <> '\001' || sub 1 5 <> "CD001" then
failwithf "%s: not an ISO file or CD-ROM" dev;
(* Parse out the PVD fields. *)
let iso_system_id = sub 8 32 |> iso_parse_strA in
let iso_volume_id = sub 40 32 |> iso_parse_strA in
let iso_volume_space_size = sub 80 4 |> iso_parse_int32 in
let iso_volume_set_size = sub 120 2 |> iso_parse_int16 in
let iso_volume_sequence_number = sub 124 2 |> iso_parse_int16 in
let iso_logical_block_size = sub 128 2 |> iso_parse_int16 in
let iso_volume_set_id = sub 190 128 |> iso_parse_strD in
let iso_publisher_id = sub 318 128 |> iso_parse_strA in
let iso_data_preparer_id = sub 446 128 |> iso_parse_strA in
let iso_application_id = sub 574 128 |> iso_parse_strA in
let iso_copyright_file_id = sub 702 37 |> iso_parse_strD in
let iso_abstract_file_id = sub 739 37 |> iso_parse_strD in
let iso_bibliographic_file_id = sub 776 37 |> iso_parse_strD in
let iso_volume_creation_t = sub 813 17 |> iso_parse_datetime in
let iso_volume_modification_t = sub 830 17 |> iso_parse_datetime in
let iso_volume_expiration_t = sub 847 17 |> iso_parse_datetime in
let iso_volume_effective_t = sub 864 17 |> iso_parse_datetime in
(* Return the struct. *)
{
iso_system_id; iso_volume_id; iso_volume_space_size;
iso_volume_set_size; iso_volume_sequence_number;
iso_logical_block_size; iso_volume_set_id; iso_publisher_id;
iso_data_preparer_id; iso_application_id; iso_copyright_file_id;
iso_abstract_file_id; iso_bibliographic_file_id;
iso_volume_creation_t; iso_volume_modification_t;
iso_volume_expiration_t; iso_volume_effective_t;
}
let isoinfo file =
let chroot = Chroot.create ~name:(sprintf "isoinfo: %s" file) () in
Chroot.f chroot isoinfo_device file