First patch fixed writes...
That one should also fix reads ;)

Untested.

Index: src/daemon/common/commonComplexOptions.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/common/commonComplexOptions.ml,v
retrieving revision 1.59
diff -u -r1.59 commonComplexOptions.ml
--- src/daemon/common/commonComplexOptions.ml	16 Aug 2006 19:12:55 -0000	1.59
+++ src/daemon/common/commonComplexOptions.ml	29 Aug 2006 15:40:56 -0000
@@ -998,35 +998,35 @@
 let backup_tar archive files =
   let failed_files = ref [] in
   Unix2.tryopen_write_tar ~compress:`Gzip archive (fun otar ->
+    let input_buffer_size = 1024 * 1024 in
+    let input_buffer = String.create input_buffer_size in
     List.iter (fun arg ->
       try
-	let header, s =
-	  Unix2.tryopen_read_bin arg (fun ic ->
-	    let stat = Unix.stat arg in
-	    let size = stat.Unix.st_size in
-	    if size > Sys.max_string_length then
-	      failwith (Printf.sprintf "Tar: file %s too big, limit %d byte" arg Sys.max_string_length);
-	    let header = 
-	      { Tar.t_name = arg;
-	      t_mode = 0o644;
-	      t_uid = stat.Unix.st_uid;
-	      t_gid = stat.Unix.st_gid;
-	      t_size = 0;
-	      t_mtime = Int32.of_float stat.Unix.st_mtime;
-	      t_chksum = 0;
-	      t_typeflag = REGULAR;
-	      t_linkname = "";
-	      t_format = POSIX_FORMAT;
-	      t_uname = "";
-	      t_gname = "";
-	      t_devmajor = 0;
-	      t_devminor = 0;
-	      t_prefix = "";
-	      t_gnu = None;} in
-	    let s = String.create size in
-	    Pervasives.really_input ic s 0 size;
-	    header, s) in
-	Tar.output otar header s
+	Unix2.tryopen_read_bin arg (fun ic ->
+	  let stat = Unix.stat arg in
+	  let size = stat.Unix.st_size in
+	  let header = 
+	    { Tar.t_name = arg;
+	    t_mode = 0o644;
+	    t_uid = stat.Unix.st_uid;
+	    t_gid = stat.Unix.st_gid;
+	    t_size = size;
+	    t_mtime = Int32.of_float stat.Unix.st_mtime;
+	    t_chksum = 0;
+	    t_typeflag = REGULAR;
+	    t_linkname = "";
+	    t_format = POSIX_FORMAT;
+	    t_uname = "";
+	    t_gname = "";
+	    t_devmajor = 0;
+	    t_devminor = 0;
+	    t_prefix = "";
+	    t_gnu = None;} in
+	  Tar.output_chunked otar header (fun () -> 
+	    let nread = Pervasives.input ic input_buffer 0 input_buffer_size in
+	    if nread = 0 then raise End_of_file
+	    else if nread = input_buffer_size then input_buffer
+	    else String.sub input_buffer 0 nread))
       with e ->
 	let error = Printexc2.to_string e in
 	if error = "Gzip.Error(\"error during compression\")"
Index: src/utils/cdk/tar.mlcpp
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/utils/cdk/tar.mlcpp,v
retrieving revision 1.2
diff -u -r1.2 tar.mlcpp
--- src/utils/cdk/tar.mlcpp	6 Feb 2006 12:54:58 -0000	1.2
+++ src/utils/cdk/tar.mlcpp	29 Aug 2006 15:40:57 -0000
@@ -259,24 +259,39 @@
     | Some h -> h
     | None -> raise (Error "Missing tar header?")
     
-let read_body t =
+let read_body_chunked t f =
   align_at_body t;
   let header = get_header t in
     t.last_header <- None;
-    if header.t_size = 0 then "" 
-    else let buf = String.create header.t_size in
-      t.chan#really_input buf 0 header.t_size;
+    let buffer_size = 1024 * 1024 in
+    let buf = String.create (min buffer_size header.t_size) in
+    let rec aux left =
+      if left > 0 then
+	let to_read = min buffer_size left in
+	  t.chan#really_input buf 0 to_read;
+	  f (if to_read = buffer_size then buf else String.sub buf 0 to_read);
+	  aux (left - to_read) in
+      aux header.t_size;
       let align = blocksize - (header.t_size mod blocksize) in
 	if align <> blocksize then begin
 	  let leftover = String.create blocksize in	    
 	    t.chan#really_input leftover 0 align
-	end;
-	buf
+	end
+
+let read_body t =
+  let buf = Buffer.create 1024 in
+    read_body_chunked t (Buffer.add_string buf);
+    Buffer.contents buf
 
 let read_entry t =
   let head = read_header t in
     head, read_body t
 
+let read_entry_chunked t f =
+  let head = read_header t in
+    read_body_chunked t f;
+    head
+
 class out_chan o = object
   method output str pos len = Pervasives.output o str pos len
   method flush () = Pervasives.flush o
@@ -388,49 +403,114 @@
     write_int32 buf 24 ext.t_offset;
     write_int32 buf 36 ext.t_realsize
   
-let output t head body =
-  let size = String.length body in
+(* looks like ocaml needs better channels... *)
+type tar_input_buffer = {
+  fgetmore : unit -> string;
+  mutable data : string;
+  mutable len : int; (* len = String.length data *)
+  mutable ndx : int; (* 0 <= ndx, unread <= len *)
+  mutable unread : int; (* ndx + unread = len *)
+}
+
+let output_chunked t head fgetmore =
+  let create_input_buffer f = {
+    fgetmore = f;
+    data = "";
+    len = 0;
+    ndx = 0;
+    unread = 0;
+  } in
+  let read_input_buffer ib nchars outf =
+    let transfer n =
+      outf ib.data ib.ndx n;
+      ib.ndx <- ib.ndx + n;
+      ib.unread <- ib.unread - n in
+
+    let rec loop () =
+      if ib.unread >= nchars then 
+	transfer nchars
+      else begin
+	transfer ib.unread;
+	(* reload some data from input *)
+	(* it should only happen when not enough data is available, as
+	   fgetmore is free to raise End_of_file *)
+	ib.data <- ib.fgetmore ();
+	ib.len <- String.length ib.data;
+	ib.ndx <- 0;
+	ib.unread <- ib.len;
+	loop ()
+      end in
+    loop () in
+
   let buf = String.copy empty_block in
-    write_str buf 0 100 head.t_name;
-    write_num8 buf 100 head.t_mode;
-    write_num8 buf 108 head.t_uid;
-    write_num8 buf 116 head.t_gid;
-    write_num12 buf 124 size;
-    write_int32 buf 136 head.t_mtime;
-    buf.[156] <- typeflag_to_char head.t_typeflag;
-    write_str buf 157 100 head.t_linkname;
-    write_magic buf 257 head.t_format;
-    write_str buf 265 32 head.t_uname;
-    write_str buf 297 32 head.t_gname;
-    write_num8 buf 329 head.t_devmajor;
-    write_num8 buf 337 head.t_devminor;
-    write_str buf 345 155 head.t_prefix;
-    if head.t_format = OLDGNU_FORMAT then
-      write_oldgnu_header head buf;
-    let chksum = compute_chksum buf in
-      write_padded_num buf 148 chksum;
-      t.ochan#output buf 0 blocksize;
-      if head.t_format = GNU_FORMAT && isdigit buf.[156] then begin
-	let buf2 = String.copy empty_block in
-	  write_gnu_header head buf2;
-	  t.ochan#output buf2 0 blocksize
-      end;
-      if size > 0 then begin
-	let blocks = size / blocksize in
-	  for n = 0 to blocks do
-	    let pos = n * blocksize in
-	    let len =
-	      if size - pos >= blocksize then
-		blocksize
-	      else
-		size - pos in
-	      t.ochan#output body (n * 512) len;
-	  done;	 
-	  let align = blocksize - (size mod blocksize) in
-	    if align > 0 && align < blocksize then 
-	      t.ochan#output empty_block 0 align
-      end
-      
+  write_str buf 0 100 head.t_name;
+  write_num8 buf 100 head.t_mode;
+  write_num8 buf 108 head.t_uid;
+  write_num8 buf 116 head.t_gid;
+  write_num12 buf 124 head.t_size;
+  write_int32 buf 136 head.t_mtime;
+  buf.[156] <- typeflag_to_char head.t_typeflag;
+  write_str buf 157 100 head.t_linkname;
+  write_magic buf 257 head.t_format;
+  write_str buf 265 32 head.t_uname;
+  write_str buf 297 32 head.t_gname;
+  write_num8 buf 329 head.t_devmajor;
+  write_num8 buf 337 head.t_devminor;
+  write_str buf 345 155 head.t_prefix;
+  if head.t_format = OLDGNU_FORMAT then
+    write_oldgnu_header head buf;
+  let chksum = compute_chksum buf in
+  write_padded_num buf 148 chksum;
+  t.ochan#output buf 0 blocksize;
+  if head.t_format = GNU_FORMAT && isdigit buf.[156] then begin
+    let buf2 = String.copy empty_block in
+    write_gnu_header head buf2;
+    t.ochan#output buf2 0 blocksize
+  end;
+  let input_buffer = create_input_buffer fgetmore in
+
+  let rec transfer left =
+    let transfer_block nchars =
+      read_input_buffer input_buffer nchars (fun s offset len ->
+	t.ochan#output s offset len) in
+
+    if left >= blocksize then begin
+      transfer_block blocksize;
+      transfer (left - blocksize)
+    end 
+    else begin
+      transfer_block left;
+      let padding = blocksize - left in
+      if padding > 0 then
+	t.ochan#output empty_block 0 padding 
+    end in
+  
+  if head.t_size > 0 then begin
+    try
+      transfer head.t_size
+    with End_of_file ->
+      failwith "Tar.output: error, file is too short"
+  end;
+
+  (* try to read one char over declared length to see if it
+     triggers an error, as expected *)
+  try
+    read_input_buffer input_buffer 1 (fun s offset len ->
+      failwith "Tar.output: error, file too large")
+  with End_of_file ->
+    ()
+
+let output t head body =
+  let len = String.length body in
+  let fixed_head = { head with t_size = len } in
+  let eof = ref (len = 0) in
+  output_chunked t fixed_head (fun () -> 
+    if !eof then raise End_of_file
+    else begin
+      eof := true;
+      body
+    end)
+
 let flush t =
   t.ochan#output empty_block 0 blocksize;
   t.ochan#flush ()
Index: src/utils/cdk/tar.mli
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/utils/cdk/tar.mli,v
retrieving revision 1.3
diff -u -r1.3 tar.mli
--- src/utils/cdk/tar.mli	5 Feb 2006 13:45:06 -0000	1.3
+++ src/utils/cdk/tar.mli	29 Aug 2006 15:40:57 -0000
@@ -67,9 +67,11 @@
 (** Return the contents of the next file in the tar archive. If the
   file size is 0, returns an empty string. *)
 val read_body: t_in -> string
+val read_body_chunked: t_in -> (string -> unit) -> unit
 
 (** Return the next file header and body in the archive *)
 val read_entry: t_in -> header * string
+val read_entry_chunked: t_in -> (string -> unit) -> header
 
 (** Clean up and stop processing the archive without closing the input
   channel *)
@@ -91,16 +93,26 @@
   written to, optionally compressed. *)
 val open_out_chan: ?compress:[<`Plain|`Gzip|`Bzip2>`Plain] -> out_channel -> t_out
 
-(** Write a file to the tar archive using the given header and file
-  body. [header.t_size] is set based on the length of the string that's
+(** Write data to the tar archive.
+
+  [output] uses the given header and file body. 
+  [header.t_size] is set based on the length of the string that's
   used as the file. [header.t_chksum] is also filled in
-  automatically. *)
+  automatically. 
+
+  For larger files, data can be delivered in consecutive chunks to
+  [output_chunked] by calls to the function parameter. 
+  Contrary to [output], [output_chunked] expects [header.t_size] to be
+  correct, and checks that it is (the function argument must
+  raises the End_of_file exception exactly when [header.t_size] bytes
+  have been consumed).
+*)
 val output: t_out -> header -> string -> unit
+val output_chunked: t_out -> header -> (unit -> string) -> unit
 
 (** Flush out the tar archive but don't close the underlying
-  [out_channel] *)
+    [out_channel] *)
 val flush: t_out -> unit
 
 (** Closes the tar file *)
 val close_out: t_out -> unit
-
