[Libguestfs] [PATCH v8 3/4] v2v: add function find_file_in_tar to utils

Tomáš Golembiovský tgolembi at redhat.com
Sat Feb 4 14:10:45 UTC 2017


The function looks up file in tar archive and returns a tuple containing
which at byte it starts and how long the file is.

Signed-off-by: Tomáš Golembiovský <tgolembi at redhat.com>
---
 v2v/utils.ml  | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 v2v/utils.mli |  7 +++++++
 2 files changed, 58 insertions(+)

diff --git a/v2v/utils.ml b/v2v/utils.ml
index 896e16004..111dc0ea9 100644
--- a/v2v/utils.ml
+++ b/v2v/utils.ml
@@ -111,3 +111,54 @@ let qemu_img_version () =
           line;
         0, 9
       )
+
+let find_file_in_tar tar filename =
+  let lines = external_command (sprintf "tar tRvf %s" (Filename.quote tar)) in
+  let rec loop lines =
+    match lines with
+    | [] -> raise Not_found
+    | line :: lines -> (
+      (* Lines have the form:
+        * block <offset>: <perms> <owner>/<group> <size> <mdate> <mtime> <file>
+        *)
+      let elems = Str.bounded_split (Str.regexp " +") line 8 in
+      if List.length elems = 8 && List.hd elems = "block" then (
+        let elems = Array.of_list elems in
+        let offset = elems.(1) in
+        let size = elems.(4) in
+        let fname = elems.(7) in
+
+        if fname <> filename then
+          loop lines
+        else (
+          let offset =
+            try
+              (* There should be a colon at the end *)
+              let i = String.rindex offset ':' in
+              if i == (String.length offset)-1 then
+                Int64.of_string (String.sub offset 0 i)
+              else
+                raise (Failure "colon at wrong position")
+            with Failure _ | Not_found ->
+              raise (Failure (sprintf "invalid offset returned by tar: %S"
+                offset)) in
+
+          let size =
+            try Int64.of_string size
+            with Failure _ ->
+              raise (Failure (sprintf
+                "invalid size returned by tar: %S" size)) in
+
+          (* Note: Offset is actualy block number and there is a single
+            * block with tar header at the beginning of the file. So skip
+            * the header and convert the block number to bytes before
+            * returning.
+            *)
+          (offset +^ 1L) *^ 512L, size
+        )
+      ) else
+        raise (Failure (sprintf
+          "failed to parse line returned by tar: %S" line))
+    )
+  in
+  loop lines
diff --git a/v2v/utils.mli b/v2v/utils.mli
index a7f8b6e84..9c92d93be 100644
--- a/v2v/utils.mli
+++ b/v2v/utils.mli
@@ -55,3 +55,10 @@ val qemu_img_version : unit -> int * int
 (** Returns version of qemu-img as a tuple (major, minor).
 
     In case of error (0,9) is returned. *)
+
+val find_file_in_tar : string -> string -> int64 * int64
+(** [find_file_in_tar tar filename] looks up file in [tar] archive and returns
+    a tuple containing at which byte it starts and how long the file is.
+
+    Function raises [Not_found] if there is no such file inside [tar] and
+    [Failure] if there is any error parsing the tar output. *)
-- 
2.11.0




More information about the Libguestfs mailing list