mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Automated using this command: perl -pi.bak -e 's/(20[012][0-9])-20[12][01234]/$1-2025/g' `git ls-files`
133 lines
4.9 KiB
OCaml
133 lines
4.9 KiB
OCaml
(* Parse isoinfo or xorriso output.
|
|
* Copyright (C) 2009-2025 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.iter (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
|