@@ -18,60 +18,64 @@ let () = Printexc.record_backtrace true
18
18
19
19
let ( / ) = Filename. concat
20
20
21
- let stream_of_fd fd =
22
- let buf = Bytes. create 0x1000 in
23
- fun () -> match Unix. read fd buf 0 (Bytes. length buf) with
24
- | 0 -> None
25
- | len ->
26
- let str = Bytes. sub_string buf 0 len in
27
- Some str
28
- | exception End_of_file -> None
21
+ let contents_of_path path =
22
+ let fd = ref `None in
23
+ let buf = Bytes. create 0x100 in
24
+ let rec dispenser () = match ! fd with
25
+ | `Closed -> Tar. return (Ok None )
26
+ | `None ->
27
+ let fd' = Unix. openfile path Unix. [ O_RDONLY ; O_CLOEXEC ] 0o644 in
28
+ fd := `Active fd';
29
+ dispenser ()
30
+ | `Active fd' ->
31
+ match Unix. read fd' buf 0 (Bytes. length buf) with
32
+ | 0 | exception End_of_file ->
33
+ Unix. close fd'; fd := `Closed ; Tar. return (Ok None )
34
+ | len ->
35
+ let str = Bytes. sub_string buf 0 len in
36
+ Tar. return (Ok (Some str)) in
37
+ dispenser
29
38
30
- let always x = fun _ -> x
31
-
32
- (*
33
- let create_tarball directory oc =
39
+ let create_tarball directory fd =
34
40
let files = Sys. readdir directory in
35
41
let os = match Sys. os_type with
36
42
| "Win32" -> Gz. NTFS (* XXX(dinosaure): true? *)
37
43
| "Unix" | "Cygwin" | _ -> Gz. Unix in
38
44
let mtime = Unix. gettimeofday () in
39
- let out_channel = Tar_gz.of_out_channel ~level:4 ~mtime:(Int32.of_float mtime) os oc in
40
45
let hdr = Tar.Header. make ~file_mode: 0o755
41
- ~mod_time:(Int64.of_float mtime) (Filename.concat directory "") 0L in
42
- (match Tar_gz.write_block ~level:Tar.Header.Ustar hdr out_channel (always None) with
43
- | Ok () -> ()
44
- | Error `Msg msg -> Format.eprintf "Error %s writing block\n%!" msg);
45
- Array.iter begin fun filename ->
46
- let fd = Unix.openfile (directory / filename) Unix.[ O_RDONLY; O_CLOEXEC ] 0o644 in
47
- let stat = Unix.LargeFile.lstat (directory / filename) in
48
- match stat.st_kind with
49
- | Unix.S_REG ->
50
- let stream = stream_of_fd fd in
51
- let file_mode = if stat.Unix.LargeFile.st_perm land 0o111 <> 0 then 0o755 else 0o644 in
52
- let mod_time = Int64.of_float stat.Unix.LargeFile.st_mtime in
53
- let user_id = stat.Unix.LargeFile.st_uid in
54
- let group_id = stat.Unix.LargeFile.st_gid in
55
- let hdr = Tar.Header.make
46
+ ~mod_time: (Int64. of_float mtime) (Filename. concat directory " " ) 0L in
47
+ let entries = Array. fold_left begin fun acc filename ->
48
+ let stat = Unix.LargeFile. stat (directory / filename) in
49
+ match stat.st_kind with
50
+ | Unix. S_REG ->
51
+ let file_mode = if stat.st_perm land 0o111 <> 0 then 0o755 else 0o644 in
52
+ let mod_time = Int64. of_float stat.Unix.LargeFile. st_mtime in
53
+ let user_id = stat.st_uid in
54
+ let group_id = stat.st_gid in
55
+ let level = Some Tar.Header. Ustar in
56
+ let hdr = Tar.Header. make
56
57
~file_mode ~mod_time ~user_id ~group_id
57
- (directory / filename) stat.Unix.LargeFile.st_size in
58
- (match Tar_gz.write_block ~level:Tar.Header.Ustar hdr out_channel stream with
59
- | Ok () -> ()
60
- | Error `Msg msg -> Format.eprintf "Error %s writing block\n%!" msg);
61
- Unix.close fd ;
62
- | _ ->
63
- Format.eprintf "Skipping non-regular file %s\n" (Filename.concat directory filename)
64
- end files ;
65
- Tar_gz.write_end out_channel
58
+ (directory / filename) stat.st_size in
59
+ (level, hdr, contents_of_path (directory / filename)) :: acc
60
+ | _ -> acc end [] files in
61
+ let entries = List. to_seq entries in
62
+ let entries = Seq. to_dispenser entries in
63
+ let entries () = Tar. return (Ok (entries () )) in
64
+ let t = Tar. out ~level: Tar.Header. Ustar hdr entries in
65
+ let t = Tar_gz. out_gzipped ~level: 4 ~mtime: (Int32. of_float mtime) os t in
66
+ match Tar_unix. run t fd with
67
+ | Ok () -> ()
68
+ | Error err ->
69
+ Format. eprintf " %s: %a\n %!" Sys. executable_name Tar_unix. pp_error err
66
70
67
71
let make directory oc =
68
- let oc, oc_close, _gz = match oc with
69
- | None -> stdout, ignore, false
72
+ let fd, fd_close = match oc with
73
+ | None -> Unix. stdout, ignore
70
74
| Some filename ->
71
- let oc = open_out filename in
72
- oc , (fun () -> close_out oc), Filename.extension filename = ".gz" in
73
- create_tarball directory oc ; oc_close ()
74
- *)
75
+ let fd = Unix. openfile filename Unix. [ O_TRUNC ; O_CREAT ; O_WRONLY ; O_CLOEXEC ] 0o644 in
76
+ fd , (fun () -> Unix. close fd) in
77
+ Fun. protect ~finally: fd_close @@ fun () ->
78
+ create_tarball directory fd
75
79
76
80
let sizes = [| " B" ; " KiB" ; " MiB" ; " GiB" ; " TiB" ; " PiB" ; " EiB" ; " ZiB" ; " YiB" |]
77
81
@@ -89,46 +93,31 @@ let list filename =
89
93
hdr.Tar.Header. file_name
90
94
(Tar.Header.Link. to_string hdr.link_indicator)
91
95
(bytes_to_size ~decimals: 2 ) hdr.Tar.Header. file_size ;
92
- (*
93
- (* Alternatively:
94
- let padding = Tar.Header.compute_zero_padding_length hdr in
95
- let data = Int64.to_int hdr.Tar.Header.file_size in
96
- let to_skip = data + padding in *)
97
- Tar_gz.skip ic to_skip ;
98
- go global ()
99
- | Error `Eof -> ()
100
- | Error `Fatal e ->
101
- Format.eprintf "Error listing archive: %a\n%!" Tar.pp_error e;
102
- exit 2
103
- *)
104
96
let open Tar in
105
- let to_skip = Header. (Int64. to_int (to_sectors hdr) * length) in
106
- let * _ = seek to_skip in
97
+ let * _ = seek (Int64. to_int hdr.Tar.Header. file_size) in
107
98
return (Ok () )
108
99
in
109
100
let fd = Unix. openfile filename [ Unix. O_RDONLY ] 0 in
110
- match Tar_unix. run (Tar_gz. gzipped (Tar. fold go () )) fd with
101
+ match Tar_unix. run (Tar_gz. in_gzipped (Tar. fold go () )) fd with
111
102
| Ok () -> ()
112
103
| Error (`Unix _ ) ->
113
104
Format. eprintf " Some UNIX error occurred.\n %!"
114
105
| Error (`Msg e ) ->
115
106
Format. eprintf " Some error: %s.\n %!" e
116
- | Error `Unexpected_end_of_file ->
107
+ | Error ( `Unexpected_end_of_file | `Eof ) ->
117
108
Format. eprintf " Unexpected end of file.\n %!"
118
- | Error `Eof | Error ` Gz _ ->
119
- Format. eprintf " Some fatal error occurred.\n %!"
109
+ | Error `Gz err ->
110
+ Format. eprintf " Some Gzip error occurred: %s .\n %!" err
120
111
| Error (`Fatal _ ) ->
121
112
Format. eprintf " Some fatal error occurred.\n %!"
122
113
123
114
let () = match Sys. argv with
124
115
| [| _; " list" ; filename; |] when Sys. file_exists filename ->
125
116
list filename
126
- (*
127
117
| [| _; directory |] when Sys. is_directory directory ->
128
118
make directory None
129
119
| [| _; directory; output |] when Sys. is_directory directory ->
130
120
make directory (Some output)
131
- *)
132
121
| _ ->
133
122
let cmd = Filename. basename Sys. argv.(0 ) in
134
123
Format. eprintf " %s <directory> [<filename.tar.gz>]\n %s list <filename.tar.gz>\n " cmd cmd
0 commit comments