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
30 let log_prefix = "[dcSh]"
33 lprintf_nl2
log_prefix fmt
35 (* Share files tabs *)
36 let rec buf_tabs buf n
=
38 Buffer.add_char buf '
\t'
;
42 (* Create list of shared files *)
44 let buf = Buffer.create
1000 in
45 let rec iter ntabs node
=
46 let dirname = node
.shared_dirname
in
48 if dirname = "" then ntabs else begin
51 Printf.bprintf
buf "%s\r\n" (DcProtocol.utf_to_dc
dir);
55 List.iter (fun dcsh
->
57 let fname = Filename2.basename dcsh
.dc_shared_codedname
in
58 Printf.bprintf
buf "%s|%Ld\r\n" (DcProtocol.utf_to_dc
fname) dcsh
.dc_shared_size
60 List.iter (fun (_
, node
) ->
64 iter 0 dc_shared_tree
;
67 (* Create mylist of shared files in xml-format *)
68 let make_xml_mylist root
=
69 let buf = Buffer.create
1000 in
70 Printf.bprintf
buf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\r\n";
71 Printf.bprintf
buf "<FileListing Version=\"1\" CID=\"1,0,2,3,4,5,6\" Base=\"/\" Generator=\"MLDC-%s\">\r\n" (Xml.escape
Autoconf.current_version
);
72 let rec iter ntabs node
=
74 Printf.bprintf
buf "<Directory Name=\"%s\">\r\n" (Xml.escape node
.shared_dirname
);
75 List.iter (fun dcsh
->
76 buf_tabs buf (ntabs + 1);
77 let fname = Filename2.basename dcsh
.dc_shared_codedname
in
78 Printf.bprintf
buf "<File Name=\"%s\" Size=\"%Ld\" TTH=\"%s\"/>\r\n" (Xml.escape
fname)
79 dcsh
.dc_shared_size
(Xml.escape dcsh
.dc_shared_tiger_root
)
81 List.iter (fun (_
, node
) -> iter (ntabs+1) node
) node
.shared_dirs
;
83 Printf.bprintf
buf "</Directory>\r\n"
85 if root
.shared_dirname
= "" then
86 List.iter (fun (_
,node
) -> iter 0 node
) root
.shared_dirs
89 Printf.bprintf
buf "</FileListing>\r\n";
92 let file_to_che3_to_string filename
=
93 let buf = Buffer.create
8192 in
94 let file_fd = Unix32.create_ro filename
in
95 let flen = Unix32.getsize64
file_fd in
99 let rlen = int64_min_int
(flen -- pos
) slen in
100 let npos = Int64.add pos
(Int64.of_int
rlen) in
101 let str = Bytes.create
slen in
102 Unix32.read file_fd pos
str 0 rlen;
103 Buffer.add_bytes
buf str;
104 if npos < flen then read npos
107 Unix32.close
file_fd;
108 Che3.decompress
(Buffer.contents
buf)
110 if !verbose_unexpected_messages
then
111 lprintf_nl "Exception (%s) in (file_to_che3_to_string)" (Printexc2.to_string e
);
114 (* Compress string to Che3 and write to file *)
115 let string_to_che3_to_file str filename
=
117 let s = Che3.compress
str in
119 (*let str = String.create slen in*)
120 let slen = String.length
s in
121 let file_fd = Unix32.create_rw filename
in
124 if (pos
+ wlen) > slen then slen-pos
127 let npos = pos
+ len in
128 Unix32.write file_fd (Int64.of_int pos
) s pos
len;
129 if npos < slen then write npos
132 Unix32.close
file_fd;
135 if !verbose_unexpected_messages
then
136 lprintf_nl "Exception (%s) in (string_to_che3_to_file)" (Printexc2.to_string e
) )
138 (* Open bz2 file and return opened data in buffer *)
139 let file_to_bz2_to_buffer filename
=
140 let buf = Buffer.create
8192 in
141 let ic = Bzip2.open_in filename
in
143 (*let rec getchar () =
144 ignore (Bzip2.input_char ic);
148 let rec decompress () =
149 let str = Bytes.create
4096 in
150 let n = Bzip2.input
ic str 0 (Bytes.length
str) in
153 (*let ss = (String.sub str 0 n) in*)
154 Buffer.add_string
buf (Bytes.sub_string
str 0 n);
155 (*lprintf_nl "(%s)" ss;*)
161 (*lprintf_nl "Size of bz2 buffer: %d" (Buffer.length buf);*)
165 if !verbose_unexpected_messages
then
166 lprintf_nl "Exception (%s) in (file_to_bz2_to_buffer)" (Printexc2.to_string e
);
170 (* Compress buffer to bz2 and save to file *)
171 let buffer_to_bz2_to_file buf filename
=
174 (*let str = String.create slen in*)
175 let blen = Buffer.length
buf in
176 let oc = Bzip2.open_out filename
in
177 let rec compress pos
=
179 if (pos
+ slen) > blen then blen-pos
182 let npos = pos
+ len in
183 let str = Bytes.unsafe_of_string
@@ Buffer.sub
buf pos
len in
184 Bzip2.output
oc str 0 len;
185 if npos < blen then compress npos
190 if !verbose_unexpected_messages
then
191 lprintf_nl "Exception (%s) in (buffer_to_bz2_to_file)" (Printexc2.to_string e
) )
193 (* Create xml and mylist filelist *)
194 let create_filelist () =
195 buffer_to_bz2_to_file (make_xml_mylist dc_shared_tree
) (Filename.concat directconnect_directory mylistxmlbz2
);
196 if !verbose_upload
then lprintf_nl "Created mylist.xml file";
197 string_to_che3_to_file (make_mylist () ) (Filename.concat directconnect_directory mylist
);
198 if !verbose_upload
then lprintf_nl "Created mylist file";
201 let find_dir_exn name
=
202 let path = String2.split_simplify name '
/'
in
203 let rec follow path node
=
206 | x
::xs
-> follow xs
(List.assoc x node
.shared_dirs
)
208 follow path dc_shared_tree
210 (*let dc_share_file dcsh = ()*)
212 match Magic.M.magic_fileinfo dcsh.dc_shared_fullname false with
214 | Some magic -> Some (HashMagic.merge files_magic magic)
216 (*let fd = Unix32.create_ro dcsh.dc_shared_fullname in
217 let info, index = CommonUploads.new_info dcsh.dc_shared_fullname dcsh.dc_shared_size in *)
220 impl_shared_update = 1;
221 impl_shared_fullname = dcsh.dc_shared_fullname;
222 impl_shared_codedname = dcsh.dc_shared_codedname;
223 impl_shared_size = dcsh.dc_shared_size;
224 impl_shared_id = Md4.null;
226 impl_shared_uploaded = Int64.zero;
227 impl_shared_ops = shared_ops;
229 impl_shared_requests = 0;
230 impl_shared_magic = magic;
234 shared_codedname = dcsh.dc_shared_codedname;
236 shared_format = CommonMultimedia.get_info dcsh.dc_shared_fullname;
238 shared_uids_wanted = [];
240 update_shared_num impl *)
241 (*Hashtbl.add shareds_by_id info.shared_id sh;*)
242 (*List.iter (fun uid -> add_by_uid uid sh) info.shared_uids;*)
243 (*SharedFilesIndex.add sh.shared_info;*)
244 (* add_shared_file shared_tree sh (String2.split dcsh.dc_shared_codedname '/');
245 shared_counter := !shared_counter ++ dcsh.dc_shared_size *)
247 (* Compute (at most) one TigerTree chunk from unhashed shared files *)
248 let dc_check_hashed_files () =
249 let module M
= CommonHasher
in
250 match !dc_tiger_computing
, !dc_files_to_hash
with
251 | _
, [] | Some _
, _
-> ()
252 | None
, dcsh
:: files
->
254 if not
(Sys.file_exists dcsh
.dc_shared_fullname
) then raise Not_found
;
255 if Unix32.getsize dcsh
.dc_shared_fullname
<> dcsh
.dc_shared_size
then
256 raise
(Wrong_file_size
((Unix32.getsize dcsh
.dc_shared_fullname
), dcsh
.dc_shared_size
));
258 dc_tiger_computing
:= Some dcsh
;
259 let end_pos = dcsh
.dc_shared_pos
++ CommonUploads.tiger_block_size
in
260 let end_pos = min
end_pos dcsh
.dc_shared_size
in
261 let len = end_pos -- dcsh
.dc_shared_pos
in
262 (*lprintf_nl "Hashing chunk %d: %Ld-%Ld (%Ld) of %s"
263 dcsh.dc_shared_chunks dcsh.dc_shared_pos end_pos len dcsh.dc_shared_fullname;*)
265 M.compute_tiger dcsh
.dc_shared_fullname dcsh
.dc_shared_pos
len
267 if job
.M.job_error
then begin
268 lprintf_nl "Error prevent hashing/sharing %s" dcsh
.dc_shared_fullname
;
269 dc_files_to_hash
:= files
;
271 let new_tiger = job
.M.job_result
in
272 (*lprintf_nl " (%s)" (TigerTree.to_string new_tiger);*)
273 dcsh
.dc_shared_tiger_list
<- new_tiger :: dcsh
.dc_shared_tiger_list
;
274 dcsh
.dc_shared_pos
<- end_pos;
275 dcsh
.dc_shared_chunks
<- dcsh
.dc_shared_chunks
+ 1;
277 if dcsh
.dc_shared_chunks
= dc_get_nchunks dcsh
.dc_shared_size
then begin
278 let array = Array.of_list
(List.rev dcsh
.dc_shared_tiger_list
) in
279 let root = TigerTree.to_string
(CommonUploads.tiger_of_array
array) in
280 (*dcsh.dc_shared_tiger_array <- array;*)
281 dcsh
.dc_shared_tiger_list
<- [];
282 dcsh
.dc_shared_tiger_root
<- root;
283 (*if !verbose_upload then*) lprintf_nl "New shared file (%s) (%s)" root dcsh
.dc_shared_fullname
;
284 dc_files_to_hash
:= files
;
285 Hashtbl.add dc_shared_files_by_hash
root dcsh
;
286 DcComplexOptions.dc_saved_shared_files
=:= dcsh
:: !!DcComplexOptions.dc_saved_shared_files
;
289 dc_tiger_computing
:= None
292 | Wrong_file_size
(real,computed
) ->
293 dc_files_to_hash
:= files
;
294 if !verbose_upload
|| !verbose_unexpected_messages
then
295 lprintf_nl "Computed filesize %Ld does not match physical filesize %Ld, %s not shared"
296 computed
real dcsh
.dc_shared_fullname
298 dc_files_to_hash
:= files
;
299 dc_tiger_computing
:= None
;
300 if !verbose_upload
|| !verbose_unexpected_messages
then
301 lprintf_nl "Exception %s prevents sharing of %s"
302 (Printexc2.to_string e
) dcsh
.dc_shared_fullname
304 let dc_updatesharesize () =
305 let dc_sharesize = ref Int64.zero
in
306 Hashtbl.iter (fun _ dcsh
->
307 dc_sharesize := !dc_sharesize ++ dcsh
.dc_shared_size
) dc_shared_files_by_codedname
;
311 network
.op_network_share
<- (fun fullname codedname size
-> (* this is called once/60s with all shared files *)
312 (* file path in DC network should use '/' as separator, convert local path accordingly *)
314 match Filename2.slash
with
316 | c
-> String2.replace_char
codedname c '
/'
319 let dcsh = Hashtbl.find dc_shared_files_by_fullname fullname
in
320 if (dcsh.dc_shared_size
= size
) then begin (* if size is correct... *)
321 if dcsh.dc_shared_codedname
<> codedname then begin (* if codedname is different *)
322 (*lprintf_nl " Changing codedname (%s) to (%s)" dcsh.dc_shared_codedname codedname;*)
323 let old_cname = dcsh.dc_shared_codedname
in
324 Hashtbl.remove dc_shared_files_by_codedname
old_cname;
325 dcsh.dc_shared_codedname
<- codedname;
326 Hashtbl.add dc_shared_files_by_codedname
codedname dcsh;
327 if !verbose_upload
then lprintf_nl "Changed codedname from (%s) to (%s)" old_cname codedname;
329 end else raise Not_found
(* create new shared *)
331 (* if file is moved it is recalculated *)
333 dc_shared_fullname
= fullname
;
334 dc_shared_codedname
= codedname;
335 dc_shared_searchname
= String.lowercase
(List.nth
(String2.splitn
codedname '
/'
1) 1);
336 dc_shared_size
= size
;
337 dc_shared_tiger_root
= empty_string
;
338 (*dc_shared_tiger_array = [||];*)
339 dc_shared_tiger_list
= [];
340 dc_shared_pos
= Int64.zero
;
341 dc_shared_chunks
= 0;
343 (*lprintf_nl "New shared file (%s)" codedname;*)
344 Hashtbl.add dc_shared_files_by_fullname fullname
dcsh;
345 Hashtbl.add dc_shared_files_by_codedname
codedname dcsh;
346 dc_add_shared_file dc_shared_tree
dcsh (String2.split
codedname '
/'
);
347 dc_files_to_hash
:= dcsh :: !dc_files_to_hash
;
350 (*ignore (CommonUploads.add_shared fullname codedname size)*)