22 |
open Unix |
open Unix |
23 |
open Printf2 |
open Printf2 |
24 |
|
|
25 |
|
|
26 |
let zero = Int64.zero |
let zero = Int64.zero |
27 |
let one = Int64.one |
let one = Int64.one |
28 |
let (++) = Int64.add |
let (++) = Int64.add |
35 |
|
|
36 |
let announce = ref "" |
let announce = ref "" |
37 |
let torrent_filename = ref "" |
let torrent_filename = ref "" |
38 |
|
let torrent_comment = ref "" |
39 |
|
let torrent_private = ref 0 |
40 |
|
|
41 |
let check_tracker () = |
let check_tracker () = |
42 |
if !announce = "" then begin |
if !announce = "" then begin |
43 |
Printf.printf "You must specify the tracker url with -tracker <url>"; |
Printf.printf "You must specify the tracker url with -tracker <url>\n"; |
|
print_newline (); |
|
44 |
exit 2; |
exit 2; |
45 |
end |
end |
46 |
|
|
47 |
let check_torrent () = |
let check_torrent () = |
48 |
if !torrent_filename = "" then begin |
if !torrent_filename = "" then begin |
49 |
Printf.printf "You must specify the .torrent filename with -torrent <filename>"; |
Printf.printf "You must specify the .torrent filename with -torrent <filename>\n"; |
|
print_newline (); |
|
50 |
exit 2; |
exit 2; |
51 |
end |
end |
52 |
|
|
53 |
let _ = |
let _ = |
54 |
Arg.parse [ |
Arg.parse [ |
55 |
"-tracker", Arg.String ((:=) announce), |
"-tracker", Arg.String ((:=) announce), |
56 |
"<url> : set the tracker to put in the torrent file"; |
"<url> : set the tracker to put in the torrent file"; |
57 |
"-torrent", Arg.String ((:=) torrent_filename), |
"-torrent", Arg.String ((:=) torrent_filename), |
58 |
"<filename.torrent> : the .torrent file to use"; |
"<filename.torrent> : the .torrent file to use"; |
59 |
|
"-comment", Arg.String ((:=) torrent_comment), |
60 |
|
"\"<string>\" : some comments on the torrent"; |
61 |
|
"-private", Arg.Int ((:=) torrent_private), |
62 |
|
"<0|1> : set the private flag"; |
63 |
|
|
64 |
"-change", Arg.Unit (fun _ -> |
"-change", Arg.Unit (fun _ -> |
65 |
check_tracker (); |
check_tracker (); |
66 |
check_torrent (); |
check_torrent (); |
67 |
let s = File.to_string !torrent_filename in |
let s = File.to_string !torrent_filename in |
68 |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
69 |
let torrent = { torrent with BTTypes.torrent_announce = !announce } in |
let torrent = { torrent with |
70 |
|
BTTypes.torrent_announce = !announce; |
71 |
|
BTTypes.torrent_modified_by = Printf.sprintf "MLdonkey/%s" Autoconf.current_version } in |
72 |
let torrent_id, encoded = BTTorrent.encode_torrent torrent in |
let torrent_id, encoded = BTTorrent.encode_torrent torrent in |
73 |
let s = Bencode.encode encoded in |
let s = Bencode.encode encoded in |
74 |
File.from_string !torrent_filename s; |
File.from_string !torrent_filename s; |
75 |
Printf.printf "Torrent file of %s modified" (Sha1.to_string torrent_id); |
Printf.printf "Torrent file of %s modified\n" (Sha1.to_string torrent_id); |
|
print_newline (); |
|
76 |
), ": change the tracker inside a .torrent file"; |
), ": change the tracker inside a .torrent file"; |
77 |
|
|
78 |
"-print", Arg.Unit (fun filename -> |
"-print", Arg.Unit (fun filename -> |
79 |
check_torrent (); |
check_torrent (); |
80 |
let s = File.to_string !torrent_filename in |
let s = File.to_string !torrent_filename in |
81 |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
82 |
Printf.printf "Torrent name: %s\n" torrent.torrent_name; |
Printf.printf "Torrent name: %s\n" torrent.torrent_name; |
83 |
|
Printf.printf " comment: %s\n" torrent.torrent_comment; |
84 |
|
Printf.printf " created by: %s\n" torrent.torrent_created_by; |
85 |
|
Printf.printf " creation date: %s\n" (Date.to_string (Int64.to_float |
86 |
|
torrent.torrent_creation_date)); |
87 |
|
Printf.printf " modified by: %s\n" torrent.torrent_modified_by; |
88 |
Printf.printf " length: %Ld\n" torrent.torrent_length; |
Printf.printf " length: %Ld\n" torrent.torrent_length; |
89 |
|
Printf.printf " encoding: %s\n" torrent.torrent_encoding; |
90 |
Printf.printf " tracker: %s\n" torrent.torrent_announce; |
Printf.printf " tracker: %s\n" torrent.torrent_announce; |
91 |
|
Printf.printf " private: %s\n" (Int64.to_string torrent.torrent_private); |
92 |
Printf.printf " piece size: %Ld\n" torrent.torrent_piece_size; |
Printf.printf " piece size: %Ld\n" torrent.torrent_piece_size; |
93 |
Printf.printf " Pieces: %d\n" (Array.length torrent.torrent_pieces); |
Printf.printf " Pieces: %d\n" (Array.length torrent.torrent_pieces); |
94 |
Array.iteri (fun i s -> |
Array.iteri (fun i s -> |
100 |
Printf.printf " %10Ld : %s\n" len s |
Printf.printf " %10Ld : %s\n" len s |
101 |
) torrent.torrent_files; |
) torrent.torrent_files; |
102 |
end; |
end; |
|
print_newline (); |
|
103 |
), "<filename.torrent>: change the tracker inside a .torrent file"; |
), "<filename.torrent>: change the tracker inside a .torrent file"; |
104 |
|
|
105 |
"-create", Arg.String (fun filename -> |
"-create", Arg.String (fun filename -> |
106 |
check_tracker (); |
check_tracker (); |
107 |
check_torrent (); |
check_torrent (); |
108 |
BTTorrent.generate_torrent !announce !torrent_filename filename; |
BTTorrent.generate_torrent !announce !torrent_filename !torrent_comment |
109 |
Printf.printf "Torrent file generated"; |
(Int64.of_int !torrent_private) filename; |
110 |
print_newline (); |
Printf.printf "Torrent file generated\n"; |
111 |
)," <filename> : compute hashes of filenames and generate a .torrent file"; |
)," <filename> : compute hashes of filename(s) (can be a directory) and generate a .torrent file"; |
112 |
|
|
113 |
"-split", Arg.String (fun filename -> |
"-split", Arg.String (fun filename -> |
114 |
check_torrent (); |
check_torrent (); |
115 |
|
|
116 |
let s = File.to_string !torrent_filename in |
let s = File.to_string !torrent_filename in |
117 |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
118 |
|
|
119 |
let base_dir_name = |
let base_dir_name = |
120 |
String.sub !torrent_filename 0 ((String.length !torrent_filename) - 8) |
String.sub !torrent_filename 0 ((String.length !torrent_filename) - 8) |
121 |
in |
in |
122 |
|
|
123 |
let bt_fd = Unix32.create_ro filename in |
let bt_fd = Unix32.create_ro filename in |
124 |
let rec iter begin_pos list = |
let rec iter begin_pos list = |
125 |
match list with |
match list with |
132 |
lprintf "Copying %Ld %Ld to 0\n" |
lprintf "Copying %Ld %Ld to 0\n" |
133 |
begin_pos (end_pos -- begin_pos); |
begin_pos (end_pos -- begin_pos); |
134 |
let fd = Unix32.create_rw filename in |
let fd = Unix32.create_rw filename in |
135 |
Unix32.copy_chunk bt_fd fd begin_pos zero |
Unix32.copy_chunk bt_fd fd begin_pos zero |
136 |
(Int64.to_int (end_pos -- begin_pos)); |
(Int64.to_int (end_pos -- begin_pos)); |
137 |
Unix32.close fd; |
Unix32.close fd; |
138 |
|
|
139 |
iter end_pos tail |
iter end_pos tail |
140 |
in |
in |
141 |
iter zero torrent.torrent_files; |
iter zero torrent.torrent_files; |
142 |
Unix32.close bt_fd; |
Unix32.close bt_fd; |
143 |
|
|
144 |
), "<filename> : split a file corresponding to a .torrent file"; |
), "<filename> : split a file corresponding to a .torrent file"; |
145 |
|
|
146 |
"-check", Arg.String (fun filename -> |
"-check", Arg.String (fun filename -> |
147 |
check_torrent (); |
check_torrent (); |
148 |
let s = File.to_string !torrent_filename in |
let s = File.to_string !torrent_filename in |
149 |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
let torrent_id, torrent = BTTorrent.decode_torrent s in |
150 |
|
|
151 |
if torrent.torrent_name <> Filename.basename filename then begin |
if torrent.torrent_name <> Filename.basename filename then begin |
152 |
Printf.printf "WARNING: %s <> %s" |
Printf.printf "WARNING: %s <> %s\n" |
153 |
torrent.torrent_name (Filename.basename filename); |
torrent.torrent_name (Filename.basename filename); |
|
print_newline (); |
|
154 |
end; |
end; |
155 |
let t = if torrent.torrent_files <> [] then |
let t = if torrent.torrent_files <> [] then |
156 |
Unix32.create_multifile filename Unix32.ro_flag 0o666 |
Unix32.create_multifile filename Unix32.ro_flag 0o666 |
157 |
torrent.torrent_files |
torrent.torrent_files |
158 |
else Unix32.create_ro filename |
else Unix32.create_ro filename |
159 |
in |
in |
160 |
|
|
161 |
let length = Unix32.getsize64 t false in |
let length = Unix32.getsize64 t false in |
162 |
|
|
163 |
if torrent.torrent_length <> length then begin |
if torrent.torrent_length <> length then begin |
164 |
Printf.printf "ERROR: computed size %Ld <> torrent size %Ld" |
Printf.printf "ERROR: computed size %Ld <> torrent size %Ld\n" |
165 |
length torrent.torrent_length; |
length torrent.torrent_length; |
|
print_newline (); |
|
166 |
exit 2; |
exit 2; |
167 |
end; |
end; |
168 |
|
|
169 |
let chunk_size = torrent.torrent_piece_size in |
let chunk_size = torrent.torrent_piece_size in |
170 |
let npieces = 1+ Int64.to_int ((length -- one) // chunk_size) in |
let npieces = 1+ Int64.to_int ((length -- one) // chunk_size) in |
171 |
|
|
172 |
if Array.length torrent.torrent_pieces <> npieces then begin |
if Array.length torrent.torrent_pieces <> npieces then begin |
173 |
Printf.printf "ERROR: computed npieces %d <> torrent npieces %d" |
Printf.printf "ERROR: computed npieces %d <> torrent npieces %d\n" |
174 |
npieces (Array.length torrent.torrent_pieces); |
npieces (Array.length torrent.torrent_pieces); |
|
print_newline (); |
|
175 |
exit 2; |
exit 2; |
176 |
|
|
177 |
end; |
end; |
178 |
|
|
179 |
for i = 0 to npieces - 1 do |
for i = 0 to npieces - 1 do |
180 |
let begin_pos = chunk_size ** i in |
let begin_pos = chunk_size ** i in |
181 |
|
|
182 |
let end_pos = begin_pos ++ chunk_size in |
let end_pos = begin_pos ++ chunk_size in |
183 |
let end_pos = |
let end_pos = |
184 |
if end_pos > length then length else end_pos in |
if end_pos > length then length else end_pos in |
185 |
|
|
186 |
let sha1 = Sha1.digest_subfile t |
let sha1 = Sha1.digest_subfile t |
187 |
begin_pos (end_pos -- begin_pos) in |
begin_pos (end_pos -- begin_pos) in |
188 |
if torrent.torrent_pieces.(i) <> sha1 then begin |
if torrent.torrent_pieces.(i) <> sha1 then begin |
189 |
Printf.printf "WARNING: piece %d (%Ld-%Ld) has SHA1 %s instead of %s" |
Printf.printf "WARNING: piece %d (%Ld-%Ld) has SHA1 %s instead of %s\n" |
190 |
i begin_pos end_pos |
i begin_pos end_pos |
191 |
(Sha1.to_string sha1) |
(Sha1.to_string sha1) |
192 |
(Sha1.to_string torrent.torrent_pieces.(i)); |
(Sha1.to_string torrent.torrent_pieces.(i)); |
|
print_newline (); |
|
193 |
end |
end |
194 |
done; |
done; |
195 |
|
|
196 |
Printf.printf "Torrent file verified !!!"; |
Printf.printf "Torrent file verified !!!\n"; |
|
print_newline (); |
|
197 |
|
|
198 |
), " <filename> : check that <filename> is well encoded by a .torrent"; |
), " <filename> : check that <filename> is well encoded by a .torrent"; |
199 |
] |
] |
200 |
(fun s -> |
(fun s -> |
201 |
Printf.printf "Don't know what to do with %s\n" s; |
Printf.printf "Don't know what to do with %s\n" s; |
202 |
Printf.printf "Use --help to get some help"; |
Printf.printf "Use --help to get some help\n"; |
|
print_newline (); |
|
203 |
exit 2; |
exit 2; |
204 |
) |
) |
|
": manipulate .torrent files"; |
|
|
|
|
|
|
|
205 |
|
("make_torrent : manipulate .torrent files\n\n" ^ |
206 |
|
"Quick Howto:\n" ^ |
207 |
|
"- create a new torrent:\n" ^ |
208 |
|
"make_torrent -tracker http://ip:port/announce -torrent file.torrent " ^ |
209 |
|
"-comment \"www.mldonkey.net\" -create file\n\n" ^ |
210 |
|
"- change the tracker of a torrent file:\n" ^ |
211 |
|
"make_torrent -tracker http://ip:port/tracker -torrent myfile.torrent -change\n\n" ^ |
212 |
|
"- print the infos of a torrent file:\n" ^ |
213 |
|
"make_torrent -torrent myfile.torrent -print\n\n\n" ^ |
214 |
|
"All Options:"); |