56 |
|
|
57 |
*) |
*) |
58 |
|
|
59 |
|
|
60 |
let chunk_size = Int64.of_int (256 * 1024) |
let chunk_size = Int64.of_int (256 * 1024) |
61 |
|
|
62 |
let decode_torrent s = |
let decode_torrent s = |
63 |
if !verbose_msg_servers then lprintf ".torrent file loaded\n"; |
if !verbose_msg_servers then lprintf_nl "[BT]: .torrent file loaded\n"; |
64 |
(* lprintf "Loaded: %s\n" (String.escaped s); *) |
(* lprintf "Loaded: %s\n" (String.escaped s); *) |
65 |
let v = Bencode.decode s in |
let v = Bencode.decode s in |
66 |
(* lprintf "Decoded file: %s\n" (Bencode.print v); *) |
(* lprintf "Decoded file: %s\n" (Bencode.print v); *) |
67 |
|
|
68 |
|
|
69 |
let announce = ref "" in |
let announce = ref "" in |
70 |
let file_info = ref (List []) in |
let file_info = ref (List []) in |
71 |
let file_name = ref "" in |
let file_name = ref "" in |
73 |
let file_pieces = ref "" in |
let file_pieces = ref "" in |
74 |
let length = ref zero in |
let length = ref zero in |
75 |
let file_files = ref [] in |
let file_files = ref [] in |
76 |
|
|
77 |
let parse_files files = |
let parse_files files = |
78 |
let current_pos = ref zero in |
let current_pos = ref zero in |
79 |
List.iter (fun v -> |
List.iter (fun v -> |
86 |
List.iter (fun (key, value) -> |
List.iter (fun (key, value) -> |
87 |
match key, value with |
match key, value with |
88 |
String "path", List path -> |
String "path", List path -> |
89 |
current_file := |
current_file := |
90 |
Filepath.path_to_string '/' |
Filepath.path_to_string '/' |
91 |
(List.map (fun v -> |
(List.map (fun v -> |
92 |
match v with |
match v with |
93 |
String s -> s |
String s -> s |
94 |
| _ -> assert false |
| _ -> assert false |
95 |
) path) |
) path) |
96 |
|
|
97 |
| String "length", Int n -> |
| String "length", Int n -> |
98 |
length := !length ++ n; |
length := !length ++ n; |
99 |
current_length := n; |
current_length := n; |
100 |
length_set := true |
length_set := true |
101 |
|
|
102 |
| String key, _ -> |
| String key, _ -> |
103 |
if !verbose_msg_servers then lprintf "other field [%s] in files\n" key |
if !verbose_msg_servers then lprintf "other field [%s] in files\n" key |
104 |
| _ -> |
| _ -> |
105 |
lprintf "other field in files\n" |
lprintf_nl "[BT]: other field in files\n" |
106 |
) list; |
) list; |
107 |
|
|
108 |
assert (!length_set); |
assert (!length_set); |
109 |
assert (!current_file <> ""); |
assert (!current_file <> ""); |
110 |
file_files := (!current_file, !current_length) :: !file_files; |
file_files := (!current_file, !current_length) :: !file_files; |
111 |
current_pos := !current_pos ++ !current_length |
current_pos := !current_pos ++ !current_length |
112 |
|
|
113 |
| _ -> assert false |
| _ -> assert false |
114 |
) files; |
) files; |
115 |
in |
in |
116 |
|
|
117 |
begin |
begin |
118 |
match v with |
match v with |
119 |
Dictionary list -> |
Dictionary list -> |
120 |
List.iter (fun (key, value) -> |
List.iter (fun (key, value) -> |
121 |
match key, value with |
match key, value with |
122 |
String "announce", String tracker_url -> |
String "announce", String tracker_url -> |
123 |
announce := tracker_url |
announce := tracker_url |
124 |
| String "info", ((Dictionary list) as info) -> |
| String "info", ((Dictionary list) as info) -> |
127 |
List.iter (fun (key, value) -> |
List.iter (fun (key, value) -> |
128 |
match key, value with |
match key, value with |
129 |
| String "files", List files -> |
| String "files", List files -> |
130 |
parse_files files |
parse_files files |
131 |
| String "length", Int n -> |
| String "length", Int n -> |
132 |
length := n |
length := n |
133 |
| String "name", String name -> |
| String "name", String name -> |
134 |
file_name := name |
file_name := name |
140 |
if !verbose_msg_servers then lprintf "other field [%s] in info\n" key |
if !verbose_msg_servers then lprintf "other field [%s] in info\n" key |
141 |
| _ -> |
| _ -> |
142 |
lprintf "other field in info\n" |
lprintf "other field in info\n" |
143 |
) list |
) list |
144 |
| String key, _ -> |
| String key, _ -> |
145 |
if !verbose_msg_servers then lprintf "other field [%s] after info\n" key |
if !verbose_msg_servers then lprintf "other field [%s] after info\n" key |
146 |
| _ -> |
| _ -> |
147 |
lprintf "other field after info\n" |
lprintf "other field after info\n" |
148 |
) list |
) list |
149 |
| _ -> assert false |
| _ -> assert false |
150 |
end; |
end; |
151 |
|
|
152 |
assert (!announce <> ""); |
assert (!announce <> ""); |
153 |
assert (!file_name <> ""); |
assert (!file_name <> ""); |
154 |
assert (!file_piece_size <> zero); |
assert (!file_piece_size <> zero); |
155 |
assert (!file_pieces <> ""); |
assert (!file_pieces <> ""); |
156 |
|
|
157 |
assert (!file_info = Bencode.decode (Bencode.encode !file_info)); |
assert (!file_info = Bencode.decode (Bencode.encode !file_info)); |
158 |
|
|
159 |
let file_id = Sha1.string (Bencode.encode !file_info) in |
let file_id = Sha1.string (Bencode.encode !file_info) in |
160 |
let npieces = |
let npieces = |
161 |
1+ Int64.to_int ((!length -- one) // !file_piece_size) |
1+ Int64.to_int ((!length -- one) // !file_piece_size) |
170 |
(* if !file_files <> [] && not (String2.check_suffix !file_name ".torrent") then |
(* if !file_files <> [] && not (String2.check_suffix !file_name ".torrent") then |
171 |
file_name := !file_name ^ ".torrent";*) |
file_name := !file_name ^ ".torrent";*) |
172 |
file_files := List.rev !file_files; |
file_files := List.rev !file_files; |
173 |
|
|
174 |
file_id, { |
file_id, { |
175 |
torrent_name = !file_name; |
torrent_name = !file_name; |
176 |
torrent_length = !length; |
torrent_length = !length; |
179 |
torrent_files = !file_files; |
torrent_files = !file_files; |
180 |
torrent_pieces = pieces; |
torrent_pieces = pieces; |
181 |
} |
} |
182 |
|
|
183 |
let encode_torrent torrent = |
let encode_torrent torrent = |
184 |
|
|
185 |
let npieces = Array.length torrent.torrent_pieces in |
let npieces = Array.length torrent.torrent_pieces in |
186 |
let pieces = String.create (20 * npieces) in |
let pieces = String.create (20 * npieces) in |
187 |
for i = 0 to npieces - 1 do |
for i = 0 to npieces - 1 do |
191 |
|
|
192 |
let encode_file (filename, size) = |
let encode_file (filename, size) = |
193 |
Dictionary [ |
Dictionary [ |
194 |
String "path", List (List.map |
String "path", List (List.map |
195 |
(fun s -> String s)(Filepath.string_to_path '/' filename)); |
(fun s -> String s)(Filepath.string_to_path '/' filename)); |
196 |
String "length", Int size; |
String "length", Int size; |
197 |
] |
] |
198 |
in |
in |
199 |
|
|
200 |
let files = |
let files = |
201 |
match torrent.torrent_files with |
match torrent.torrent_files with |
202 |
[] -> |
[] -> |
203 |
String "length", Int torrent.torrent_length |
String "length", Int torrent.torrent_length |
204 |
| _ -> |
| _ -> |
205 |
String "files", |
String "files", |
206 |
List (List.map encode_file torrent.torrent_files) |
List (List.map encode_file torrent.torrent_files) |
207 |
in |
in |
208 |
|
|
209 |
let info = |
let info = |
210 |
Dictionary [ |
Dictionary [ |
211 |
files; |
files; |
214 |
String "pieces", String pieces; |
String "pieces", String pieces; |
215 |
] |
] |
216 |
in |
in |
217 |
|
|
218 |
let info_encoded = Bencode.encode info in |
let info_encoded = Bencode.encode info in |
219 |
let file_id = Sha1.string info_encoded in |
let file_id = Sha1.string info_encoded in |
220 |
file_id, |
file_id, |
222 |
String "announce", String torrent.torrent_announce; |
String "announce", String torrent.torrent_announce; |
223 |
String "info", info; |
String "info", info; |
224 |
] |
] |
225 |
|
|
226 |
let make_torrent announce filename = |
let make_torrent announce filename = |
227 |
let basename = Filename.basename filename in |
let basename = Filename.basename filename in |
228 |
let files, t = |
let files, t = |
229 |
if Unix2.is_directory filename then |
if Unix2.is_directory filename then |
230 |
let rec iter_directory list dirname = |
let rec iter_directory list dirname = |
231 |
let files = Unix2.list_directory (Filename.concat filename dirname) in |
let files = Unix2.list_directory (Filename.concat filename dirname) in |
232 |
iter_files list dirname files |
iter_files list dirname files |
233 |
|
|
234 |
and iter_files list dirname files = |
and iter_files list dirname files = |
235 |
match files with |
match files with |
236 |
[] -> list |
[] -> list |
251 |
else |
else |
252 |
[], Unix32.create_ro filename |
[], Unix32.create_ro filename |
253 |
in |
in |
254 |
|
|
255 |
Unix32.flush_fd t; |
Unix32.flush_fd t; |
256 |
let length = Unix32.getsize64 t false in |
let length = Unix32.getsize64 t false in |
257 |
let npieces = 1+ Int64.to_int ((length -- one) // chunk_size) in |
let npieces = 1+ Int64.to_int ((length -- one) // chunk_size) in |
258 |
let pieces = Array.create npieces Sha1.null in |
let pieces = Array.create npieces Sha1.null in |
259 |
for i = 0 to npieces - 1 do |
for i = 0 to npieces - 1 do |
260 |
let begin_pos = chunk_size *.. i in |
let begin_pos = chunk_size *.. i in |
261 |
|
|
262 |
let end_pos = begin_pos ++ chunk_size in |
let end_pos = begin_pos ++ chunk_size in |
263 |
let end_pos = |
let end_pos = |
264 |
if end_pos > length then length else end_pos in |
if end_pos > length then length else end_pos in |
265 |
|
|
266 |
let sha1 = Sha1.digest_subfile t |
let sha1 = Sha1.digest_subfile t |
267 |
begin_pos (end_pos -- begin_pos) in |
begin_pos (end_pos -- begin_pos) in |
268 |
pieces.(i) <- sha1 |
pieces.(i) <- sha1 |
269 |
done; |
done; |
270 |
|
|
271 |
{ |
{ |
272 |
torrent_name = basename; |
torrent_name = basename; |
273 |
torrent_length = length; |
torrent_length = length; |