1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 open CommonComplexOptions
41 let log_prefix = "[dcSh]"
44 lprintf_nl2
log_prefix fmt
46 (* Share files tabs *)
47 let rec buf_tabs buf n
=
49 Buffer.add_char buf '
\t'
;
53 (* Create list of shared files *)
55 let buf = Buffer.create
1000 in
56 let rec iter ntabs node
=
57 let dirname = node
.shared_dirname
in
59 if dirname = "" then ntabs else begin
62 Printf.bprintf
buf "%s\r\n" dir;
66 List.iter (fun dcsh
->
68 let fname = Filename2.basename dcsh
.dc_shared_codedname
in
69 Printf.bprintf
buf "%s|%Ld\r\n" fname dcsh
.dc_shared_size
71 List.iter (fun (_
, node
) ->
75 iter 0 dc_shared_tree
;
78 (* Create mylist of shared files in xml-format *)
79 let make_xml_mylist () =
80 let buf = Buffer.create
1000 in
81 Printf.bprintf
buf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\r\n";
82 Printf.bprintf
buf "<FileListing Version=\"1\" CID=\"1,0,2,3,4,5,6\" Base=\"/\" Generator=\"MLDC-%s\">\r\n" Autoconf.current_version
;
83 let rec iter ntabs node
=
84 let dirname = node
.shared_dirname
in
86 if dirname = "" then ntabs else begin
89 (* Escape some special XML characters that may appear in the dirname *)
90 let dir = Str.global_replace
(Str.regexp
"'") "'" dir in
91 let dir = Str.global_replace
(Str.regexp
"&") "&" dir in
92 Printf.bprintf
buf "<Directory Name=\"%s\">\r\n" dir;
96 List.iter (fun dcsh
->
98 let fname = Filename2.basename dcsh
.dc_shared_codedname
in
99 (* Escape some special XML characters that may appear in the filename *)
100 let fname = Str.global_replace
(Str.regexp
"'") "'" fname in
101 let fname = Str.global_replace
(Str.regexp
"&") "&" fname in
102 Printf.bprintf
buf "<File Name=\"%s\" Size=\"%Ld\" TTH=\"%s\"/>\r\n" fname
103 dcsh
.dc_shared_size dcsh
.dc_shared_tiger_root
105 List.iter (fun (_
, node
) ->
108 Printf.bprintf
buf "</Directory>\r\n"
111 iter 0 dc_shared_tree
;
112 Printf.bprintf
buf "</FileListing>";
115 let file_to_che3_to_string filename
=
116 let buf = Buffer.create
8192 in
117 let file_fd = Unix32.create_ro filename
in
118 let flen = Unix32.getsize64
file_fd in
123 let rem = Int64.sub
flen pos
in (* *)
124 if rem > Int64.of_int
slen then slen else Int64.to_int
rem
126 let npos = Int64.add pos
(Int64.of_int
rlen) in
127 let str = String.create
slen in
128 Unix32.read file_fd pos
str 0 rlen;
129 Buffer.add_string
buf str;
130 if npos < flen then read npos
133 Unix32.close
file_fd;
134 Che3.decompress
(Buffer.contents
buf)
136 if !verbose_unexpected_messages
then
137 lprintf_nl "Exception (%s) in (file_to_che3_to_string)" (Printexc2.to_string e
);
140 (* Compress string to Che3 and write to file *)
141 let string_to_che3_to_file str filename
=
143 let s = Che3.compress
(Charset.convert
Charset.UTF_8
Charset.CP1252
str) in
145 (*let str = String.create slen in*)
146 let slen = String.length
s in
147 let file_fd = Unix32.create_rw filename
in
150 if (pos
+ wlen) > slen then slen-pos
153 let npos = pos
+ len in
154 Unix32.write file_fd (Int64.of_int pos
) s pos
len;
155 if npos < slen then write npos
158 Unix32.close
file_fd;
161 if !verbose_unexpected_messages
then
162 lprintf_nl "Exception (%s) in (string_to_che3_to_file)" (Printexc2.to_string e
) )
164 (* Open bz2 file and return opened data in buffer *)
165 let file_to_bz2_to_buffer filename
=
166 let buf = Buffer.create
8192 in
167 let ic = Bzip2.open_in filename
in
169 (*let rec getchar () =
170 ignore (Bzip2.input_char ic);
174 let rec decompress () =
175 let str = String.create
4096 in
176 let n = Bzip2.input
ic str 0 (String.length
str) in
179 (*let ss = (String.sub str 0 n) in*)
180 Buffer.add_string
buf (String.sub
str 0 n);
181 (*lprintf_nl "(%s)" ss;*)
187 (*lprintf_nl "Size of bz2 buffer: %d" (Buffer.length buf);*)
191 if !verbose_unexpected_messages
then
192 lprintf_nl "Exception (%s) in (file_to_bz2_to_buffer)" (Printexc2.to_string e
);
196 (* Compress buffer to bz2 and save to file *)
197 let buffer_to_bz2_to_file buf filename
=
200 (*let str = String.create slen in*)
201 let blen = Buffer.length
buf in
202 let oc = Bzip2.open_out filename
in
203 let rec compress pos
=
205 if (pos
+ slen) > blen then blen-pos
208 let npos = pos
+ len in
209 let str = Buffer.sub
buf pos
len in
210 Bzip2.output
oc str 0 len;
211 if npos < blen then compress npos
216 if !verbose_unexpected_messages
then
217 lprintf_nl "Exception (%s) in (buffer_to_bz2_to_file)" (Printexc2.to_string e
) )
219 (* Create xml and mylist filelist *)
220 let create_filelist () =
221 buffer_to_bz2_to_file (make_xml_mylist () ) (Filename.concat directconnect_directory mylistxmlbz2
);
222 if !verbose_upload
then lprintf_nl "Created mylist.xml file";
223 string_to_che3_to_file (make_mylist () ) (Filename.concat directconnect_directory mylist
);
224 if !verbose_upload
then lprintf_nl "Created mylist file";
227 (*let dc_share_file dcsh = ()*)
229 match Magic.M.magic_fileinfo dcsh.dc_shared_fullname false with
231 | Some magic -> Some (HashMagic.merge files_magic magic)
233 (*let fd = Unix32.create_ro dcsh.dc_shared_fullname in
234 let info, index = CommonUploads.new_info dcsh.dc_shared_fullname dcsh.dc_shared_size in *)
237 impl_shared_update = 1;
238 impl_shared_fullname = dcsh.dc_shared_fullname;
239 impl_shared_codedname = dcsh.dc_shared_codedname;
240 impl_shared_size = dcsh.dc_shared_size;
241 impl_shared_id = Md4.null;
243 impl_shared_uploaded = Int64.zero;
244 impl_shared_ops = shared_ops;
246 impl_shared_requests = 0;
247 impl_shared_magic = magic;
251 shared_codedname = dcsh.dc_shared_codedname;
253 shared_format = CommonMultimedia.get_info dcsh.dc_shared_fullname;
255 shared_uids_wanted = [];
257 update_shared_num impl *)
258 (*Hashtbl.add shareds_by_id info.shared_id sh;*)
259 (*List.iter (fun uid -> add_by_uid uid sh) info.shared_uids;*)
260 (*SharedFilesIndex.add sh.shared_info;*)
261 (* add_shared_file shared_tree sh (String2.split dcsh.dc_shared_codedname '/');
262 shared_counter := !shared_counter ++ dcsh.dc_shared_size *)
264 (* Compute (at most) one TigerTree chunk from unhashed shared files *)
265 let dc_check_hashed_files () =
266 let module M
= CommonHasher
in
267 if not
!dc_tiger_computing
then begin
268 (match !dc_files_to_hash
with
272 if not
(Sys.file_exists dcsh
.dc_shared_fullname
) then raise Not_found
;
273 if Unix32.getsize dcsh
.dc_shared_fullname
<> dcsh
.dc_shared_size
then
274 raise
(Wrong_file_size
((Unix32.getsize dcsh
.dc_shared_fullname
), dcsh
.dc_shared_size
));
276 dc_tiger_computing
:= true;
277 let end_pos = dcsh
.dc_shared_pos
++ CommonUploads.tiger_block_size
in
278 let end_pos = min
end_pos dcsh
.dc_shared_size
in
279 let len = end_pos -- dcsh
.dc_shared_pos
in
280 (*lprintf_nl "Hashing chunk %d: %Ld-%Ld (%Ld) of %s"
281 dcsh.dc_shared_chunks dcsh.dc_shared_pos end_pos len dcsh.dc_shared_fullname;*)
283 M.compute_tiger dcsh
.dc_shared_fullname dcsh
.dc_shared_pos
len
285 if job
.M.job_error
then begin
286 lprintf_nl "Error prevent hashing/sharing %s" dcsh
.dc_shared_fullname
;
287 dc_files_to_hash
:= files
;
289 let new_tiger = job
.M.job_result
in
290 (*lprintf_nl " (%s)" (TigerTree.to_string new_tiger);*)
291 dcsh
.dc_shared_tiger_list
<- new_tiger :: dcsh
.dc_shared_tiger_list
;
292 dcsh
.dc_shared_pos
<- end_pos;
293 dcsh
.dc_shared_chunks
<- dcsh
.dc_shared_chunks
+ 1;
295 if dcsh
.dc_shared_chunks
= dc_get_nchunks dcsh
.dc_shared_size
then begin
296 let array = Array.of_list
(List.rev dcsh
.dc_shared_tiger_list
) in
297 let root = TigerTree.to_string
(CommonUploads.tiger_of_array
array) in
298 (*dcsh.dc_shared_tiger_array <- array;*)
299 dcsh
.dc_shared_tiger_list
<- [];
300 dcsh
.dc_shared_tiger_root
<- root;
301 (*if !verbose_upload then*) lprintf_nl "New shared file (%s) (%s)" root dcsh
.dc_shared_fullname
;
302 dc_files_to_hash
:= files
;
303 Hashtbl.add dc_shared_files_by_hash
root dcsh
;
304 DcComplexOptions.dc_saved_shared_files
=:= dcsh
:: !!DcComplexOptions.dc_saved_shared_files
;
307 dc_tiger_computing
:= false
310 | Wrong_file_size
(real,computed
) ->
311 dc_files_to_hash
:= files
;
312 if !verbose_upload
|| !verbose_unexpected_messages
then
313 lprintf_nl "Computed filesize %Ld does not match physical filesize %Ld, %s not shared"
314 computed
real dcsh
.dc_shared_fullname
316 dc_files_to_hash
:= files
;
317 dc_tiger_computing
:= false;
318 if !verbose_upload
|| !verbose_unexpected_messages
then
319 lprintf_nl "Exception %s prevents sharing of %s"
320 (Printexc2.to_string e
) dcsh
.dc_shared_fullname
) )
323 let dc_updatesharesize () =
324 let dc_sharesize = ref Int64.zero
in
325 Hashtbl.iter (fun _ dcsh
->
326 dc_sharesize := !dc_sharesize ++ dcsh
.dc_shared_size
) dc_shared_files_by_codedname
;
330 network
.op_network_share
<- (fun fullname codedname size
-> (* this is called once/60s with all shared files *)
332 let dcsh = Hashtbl.find dc_shared_files_by_fullname fullname
in
333 if (dcsh.dc_shared_size
= size
) then begin (* if size is correct... *)
334 if dcsh.dc_shared_codedname
<> codedname
then begin (* if codedname is different *)
335 (*lprintf_nl " Changing codedname (%s) to (%s)" dcsh.dc_shared_codedname codedname;*)
336 let old_cname = dcsh.dc_shared_codedname
in
337 Hashtbl.remove dc_shared_files_by_codedname
old_cname;
338 dcsh.dc_shared_codedname
<- codedname
;
339 Hashtbl.add dc_shared_files_by_codedname codedname
dcsh;
340 if !verbose_upload
then lprintf_nl "Changed codedname from (%s) to (%s)" old_cname codedname
;
342 end else raise Not_found
(* create new shared *)
344 (* if file is moved it is recalculated *)
346 dc_shared_fullname
= fullname
;
347 dc_shared_codedname
= codedname
;
348 dc_shared_searchname
= String.lowercase
(List.nth
(String2.splitn codedname '
/'
1) 1);
349 dc_shared_size
= size
;
350 dc_shared_tiger_root
= empty_string
;
351 (*dc_shared_tiger_array = [||];*)
352 dc_shared_tiger_list
= [];
353 dc_shared_pos
= Int64.zero
;
354 dc_shared_chunks
= 0;
356 (*lprintf_nl "New shared file (%s)" codedname;*)
357 Hashtbl.add dc_shared_files_by_fullname fullname
dcsh;
358 Hashtbl.add dc_shared_files_by_codedname codedname
dcsh;
359 dc_add_shared_file dc_shared_tree
dcsh (String2.split codedname '
/'
);
360 dc_files_to_hash
:= dcsh :: !dc_files_to_hash
;
363 (*ignore (CommonUploads.add_shared fullname codedname size)*)