diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./config/config.h.in ./config/config.h.in
--- ./config/config.h.in	2005-06-25 01:49:14.000000000 +0200
+++ ./config/config.h.in	2005-07-18 18:55:40.000000000 +0200
@@ -144,3 +144,6 @@
 
 /* Define to 1 if you have jpg support in libgd. */
 #undef HAVE_GD_JPG
+
+/* Define to 1 if you have bzip2 support. */
+#undef USE_BZIP2
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./config/configure.in ./config/configure.in
--- ./config/configure.in	2005-07-18 01:07:55.000000000 +0200
+++ ./config/configure.in	2005-07-18 19:01:28.000000000 +0200
@@ -523,6 +523,13 @@
   echo "Zlib missing, did you install zlib and zlib-developer packages?"; exit 1
 fi
 
+BZIP2=no
+AC_CHECK_LIB(bz2,BZ2_bzReadOpen,[AC_CHECK_HEADERS(bzlib.h,[BZIP2=yes],)])
+if test "$BZIP2" = "yes"; then
+  HAS_BZIP2=true
+  AC_DEFINE(USE_BZIP2, 1, [Define to 1 if you have bzip2 support.])
+fi
+
 AC_CHECK_HEADERS(endian.h sys/endian.h machine/endian.h,[SHA1_VERSION=sha1new; break],[SHA1_VERSION=sha1old])
 if test "$SHA1_VERSION" = "sha1old"; then
     AC_MSG_CHECKING(trying to guess endianess) 
@@ -1167,6 +1174,7 @@
 AC_SUBST(MD4ARCH)
 AC_SUBST(MD4COMP)
 AC_SUBST(ZLIB)
+AC_SUBST(BZIP2)
 AC_SUBST(GD)
 AC_SUBST(GD_JPG)
 AC_SUBST(GD_PNG)
@@ -1225,6 +1233,7 @@
 AC_SUBST(ZLIB__UNCOMPRESS_STRING2)
 AC_SUBST(ZLIB__COMPRESS_STRING)
 AC_SUBST(ZLIB__GZIP_STRING)
+AC_SUBST(HAS_BZIP2)
 
 AC_SUBST(COMMONSWARMING)
 
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./config/Makefile.config.in ./config/Makefile.config.in
--- ./config/Makefile.config.in	2005-07-17 18:29:00.000000000 +0200
+++ ./config/Makefile.config.in	2005-07-18 18:43:16.000000000 +0200
@@ -47,6 +47,7 @@
 
 ICONV=@ICONV@
 ZLIB=@ZLIB@
+BZIP2=@BZIP2@
 GD=@GD@
 GD_JPG=@GD_JPG@
 GD_PNG=@GD_PNG@
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./config/Makefile.in ./config/Makefile.in
--- ./config/Makefile.in	2005-07-17 18:29:00.000000000 +0200
+++ ./config/Makefile.in	2005-07-18 19:09:10.000000000 +0200
@@ -142,7 +142,13 @@
 ifeq ("$(ZLIB)" , "yes")
   LIBS_flags += -cclib -lz
 #  LIBS_byte += -cclib -lz
-  CDK_SRCS +=  $(CDK)/zlib.ml $(CDK)/zlibstubs.c
+  CDK_SRCS +=  $(CDK)/zlib.ml $(CDK)/zip.ml $(CDK)/gzip.ml $(CDK)/zlibstubs.c
+endif
+
+ifeq ("$(BZIP2)" , "yes")
+  LIBS_flags += -cclib -lbz2
+#  LIBS_byte += -cclib -lz
+  CDK_SRCS +=  $(CDK)/bzlib.ml $(CDK)/bzip2.ml $(CDK)/tar.ml
 endif
 
 ifeq ("$(GD)", "yes")
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/common/commonGlobals.ml ./src/daemon/common/commonGlobals.ml
--- ./src/daemon/common/commonGlobals.ml	2005-07-17 18:12:59.000000000 +0200
+++ ./src/daemon/common/commonGlobals.ml	2005-07-18 19:02:10.000000000 +0200
@@ -85,6 +85,7 @@
       ^ "\nFeatures:"
           ^ (if BasicSocket.has_threads () then " threads" else " no-threads")
           ^ (if Autoconf.has_zlib then " zlib" else " no-zlib")
+          ^ (if Autoconf.has_bzip2 then " bzip2" else " no-bzip2")
           ^ (if Autoconf.has_gd && Autoconf.has_gd_png && Autoconf.has_gd_jpg then " gd(jpg/png)" else "")
 	  ^ (if Autoconf.has_gd && Autoconf.has_gd_png && not Autoconf.has_gd_jpg then " gd(png)" else "")
 	  ^ (if Autoconf.has_gd && not Autoconf.has_gd_png && Autoconf.has_gd_jpg then " gd(jpg)" else "")
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/driver/driverMain.ml ./src/daemon/driver/driverMain.ml
--- ./src/daemon/driver/driverMain.ml	2005-07-17 18:36:07.000000000 +0200
+++ ./src/daemon/driver/driverMain.ml	2005-07-18 17:29:06.000000000 +0200
@@ -156,9 +156,9 @@
     | e -> lprintf_nl (_b "Error while reading motd.conf(%s): %s") filename
 	(Printexc2.to_string e);
 	close_in ic
-			   );
+  );
   CommonWeb.add_web_kind "guarding.p2p" (fun _ filename ->
-      Ip_set.bl := Ip_set.load filename
+      lprintf_nl "web_infos.file_kinds p2p %s" filename; Ip_set.bl := Ip_set.load filename
 (*      Ip_set.bl := Ip_set.load_merge !Ip_set.bl filename *)
   )
 
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/bzip2.ml ./src/utils/cdk/bzip2.ml
--- ./src/utils/cdk/bzip2.ml	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/bzip2.ml	2004-04-18 21:11:07.000000000 +0200
@@ -0,0 +1,177 @@
+
+(* Module [Bzip2]: reading and writing to/from [bzip2] compressed files *)
+
+exception Error of string
+
+let buffer_size = 1024
+
+type in_channel =
+  { in_chan: Pervasives.in_channel;
+    in_buffer: string;
+    mutable in_pos: int;
+    mutable in_avail: int;
+    mutable in_eof: bool;
+    in_stream: Bzlib.stream;
+    mutable in_size: int32; }
+
+let open_in_chan ic =
+  { in_chan = ic;
+    in_buffer = String.create buffer_size;
+    in_pos = 0;
+    in_avail = 0;
+    in_eof = false;
+    in_stream = Bzlib.decompress_init 0 false;
+    in_size = Int32.zero }
+
+let open_in filename =
+  open_in_chan (Pervasives.open_in_bin filename)
+
+let read_byte iz =
+  if iz.in_avail = 0 then begin
+    let n = Pervasives.input iz.in_chan iz.in_buffer 0
+                             (String.length iz.in_buffer) in
+    if n = 0 then raise End_of_file;
+    iz.in_pos <- 0;
+    iz.in_avail <- n
+  end;
+  let c = iz.in_buffer.[iz.in_pos] in
+  iz.in_pos <- iz.in_pos + 1;
+  iz.in_avail <- iz.in_avail - 1;
+  Char.code c
+
+let read_int32 iz =
+  let b1 = read_byte iz in
+  let b2 = read_byte iz in
+  let b3 = read_byte iz in
+  let b4 = read_byte iz in
+  Int32.logor (Int32.of_int b1)
+    (Int32.logor (Int32.shift_left (Int32.of_int b2) 8)
+      (Int32.logor (Int32.shift_left (Int32.of_int b3) 16)
+                   (Int32.shift_left (Int32.of_int b4) 24)))
+
+let rec input iz buf pos len =
+  if pos < 0 || len < 0 || pos + len > String.length buf then
+    invalid_arg "Bzip2.input";
+  if iz.in_eof then 0 else begin
+    if iz.in_avail = 0 then begin
+      let n = Pervasives.input iz.in_chan iz.in_buffer 0
+                               (String.length iz.in_buffer) in
+      if n = 0 then raise(Error("truncated file"));
+      iz.in_pos <- 0;
+      iz.in_avail <- n
+    end;
+    let (finished, used_in, used_out) =
+      try
+        Bzlib.decompress iz.in_stream iz.in_buffer iz.in_pos iz.in_avail
+                                   buf pos len
+      with Bzlib.Error(_, e) ->
+        raise(Error(Bzlib.string_of_error e)) in
+    iz.in_pos <- iz.in_pos + used_in;
+    iz.in_avail <- iz.in_avail - used_in;
+    iz.in_size <- Int32.add iz.in_size (Int32.of_int used_out);
+    if finished then begin
+      iz.in_eof <- true;
+      used_out
+    end else if used_out = 0 then
+      input iz buf pos len
+    else
+      used_out
+  end
+
+let rec really_input iz buf pos len =
+  if len <= 0 then () else begin
+    let n = input iz buf pos len in
+    if n = 0 then raise End_of_file;
+    really_input iz buf (pos + n) (len - n)
+  end
+
+let char_buffer = String.create 1
+
+let input_char iz =
+  if input iz char_buffer 0 1 = 0 then raise End_of_file else char_buffer.[0]
+
+let input_byte iz =
+  Char.code (input_char iz)
+
+let dispose iz =
+  iz.in_eof <- true;
+  Bzlib.decompress_end iz.in_stream
+
+let close_in iz =
+  dispose iz;
+  Pervasives.close_in iz.in_chan
+
+type out_channel =
+  { out_chan: Pervasives.out_channel;
+    out_buffer: string;
+    mutable out_pos: int;
+    mutable out_avail: int;
+    out_stream: Bzlib.stream;
+    mutable out_size: int32; }
+
+let open_out_chan ?(level = 6) oc =
+  if level < 1 || level > 9 then invalid_arg "Bzip2.open_out: bad level";
+  { out_chan = oc;
+    out_buffer = String.create buffer_size;
+    out_pos = 0;
+    out_avail = buffer_size;
+    out_stream = Bzlib.compress_init level 0 0;
+    out_size = Int32.zero }
+
+let open_out ?(level = 6) filename =
+  open_out_chan ~level (Pervasives.open_out_bin filename)
+
+let rec output oz buf pos len =
+  if pos < 0 || len < 0 || pos + len > String.length buf then
+    invalid_arg "Bzlib2.output";
+  (* If output buffer is full, flush it *)
+  if oz.out_avail = 0 then begin
+    Printf.printf "Flushing out_avail\n";
+    Pervasives.output oz.out_chan oz.out_buffer 0 oz.out_pos;
+    oz.out_pos <- 0;
+    oz.out_avail <- String.length oz.out_buffer
+  end;
+  let (_, used_in, used_out) =
+    try
+      Bzlib.compress oz.out_stream buf pos len
+                                 oz.out_buffer oz.out_pos oz.out_avail
+                                 Bzlib.BZ_RUN
+    with Bzlib.Error(f, e) ->
+      raise (Error(Bzlib.string_of_error e)) in
+  oz.out_pos <- oz.out_pos + used_out;
+  oz.out_avail <- oz.out_avail - used_out;
+  oz.out_size <- Int32.add oz.out_size (Int32.of_int used_in);
+  if used_in < len then output oz buf (pos + used_in) (len - used_in)
+
+let output_char oz c =
+  char_buffer.[0] <- c;
+  output oz char_buffer 0 1
+
+let output_byte oz b =
+  output_char oz (Char.unsafe_chr b)
+
+let flush oz =
+  let rec do_flush () =
+    (* If output buffer is full, flush it *)
+    if oz.out_avail = 0 then begin
+      Pervasives.output oz.out_chan oz.out_buffer 0 oz.out_pos;
+      oz.out_pos <- 0;
+      oz.out_avail <- String.length oz.out_buffer
+    end;
+    let (finished, _, used_out) =
+      Bzlib.compress oz.out_stream oz.out_buffer 0 0
+                                 oz.out_buffer oz.out_pos oz.out_avail
+                                 Bzlib.BZ_FINISH in
+    oz.out_pos <- oz.out_pos + used_out;
+    oz.out_avail <- oz.out_avail - used_out;
+    if not finished then do_flush() in
+  do_flush();
+  (* Final data flush *)
+  if oz.out_pos > 0 then
+    Pervasives.output oz.out_chan oz.out_buffer 0 oz.out_pos;
+  Bzlib.compress_end oz.out_stream
+
+let close_out oz =
+  flush oz;
+  Pervasives.close_out oz.out_chan
+
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/bzip2.mli ./src/utils/cdk/bzip2.mli
--- ./src/utils/cdk/bzip2.mli	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/bzip2.mli	2004-04-18 21:11:14.000000000 +0200
@@ -0,0 +1,108 @@
+
+(* Module [Bzip2]: reading and writing to/from [bzip2] compressed files *)
+
+(* This module provides functions to read and write compressed data
+   to/from files in [bzip2] format. *)
+
+(*** Reading from compressed files *)
+
+type in_channel
+        (* Abstract type representing a channel opened for reading
+           from a compressed file. *)
+val open_in: string -> in_channel
+        (* Open a compressed file for reading.  The argument is the file
+           name. *)
+val open_in_chan: Pervasives.in_channel -> in_channel
+        (* Open a compressed file for reading.  The argument is a
+           regular file channel already opened on the compressed file. *)
+val input_char: in_channel -> char
+        (* Uncompress one character from the given channel, and return it.
+           Raise [End_of_file] if no more compressed data is available. *)
+val input_byte: in_channel -> int
+        (* Same as [Bzip2.input_char], but return the 8-bit integer representing
+           the character.
+           Raise [End_of_file] if no more compressed data is available. *)
+val input: in_channel -> string -> int -> int -> int
+        (* [input ic buf pos len] uncompresses up to [len] characters
+           from the given channel [ic],
+           storing them in string [buf], starting at character number [pos].
+           It returns the actual number of characters read, between 0 and
+           [len] (inclusive).
+           A return value of 0 means that the end of file was reached.
+           A return value between 0 and [len] exclusive means that
+           not all requested [len] characters were read, either because
+           no more characters were available at that time, or because
+           the implementation found it convenient to do a partial read;
+           [input] must be called again to read the remaining characters,
+           if desired.  (See also [Bzip2.really_input] for reading
+           exactly [len] characters.)
+           Exception [Invalid_argument "Bzip2.input"] is raised if
+           [pos] and [len] do not designate a valid substring of [buf]. *)
+val really_input: in_channel -> string -> int -> int -> unit
+        (* [really_input ic buf pos len] uncompresses [len] characters
+           from the given channel, storing them in
+           string [buf], starting at character number [pos].
+           Raise [End_of_file] if fewer than [len] characters can be read.
+           Raise [Invalid_argument "Bzip2.input"] if
+           [pos] and [len] do not designate a valid substring of [buf]. *)
+val close_in: in_channel -> unit
+        (* Close the given input channel.  If the channel was created with
+           [Bzip2.open_in_chan], the underlying regular file channel
+           (of type [Pervasives.in_channel]) is also closed.
+           Do not apply any of the functions above to a closed channel. *)
+val dispose: in_channel -> unit
+        (* Same as [Bzip2.close_in], but does not close the underlying
+           regular file channel (of type [Pervasives.in_channel]);
+           just dispose of the resources associated with the decompression
+           channel.  This can be useful if e.g. the underlying file channel
+           is a network socket on which more (uncompressed) data 
+           is expected. *)
+
+(*** Writing to compressed files *)
+
+type out_channel
+        (* Abstract type representing a channel opened for writing
+           to a compressed file. *)
+val open_out: ?level:int -> string -> out_channel
+        (* Open a compressed file for writing.  The argument is the file
+           name.  The file is created if it does not exist, or
+           truncated to zero length if it exists. 
+           The optional [level] argument (an integer between 1 and 9)
+           indicates the compression level, with 1 being the weakest
+           (but fastest) compression and 9 being the strongest
+           (but slowest) compression.  The default level is 6
+           (medium compression). *)
+val open_out_chan: ?level:int -> Pervasives.out_channel -> out_channel
+        (* Open a compressed file for writing.  The argument is a
+           regular file channel already opened on the compressed file.
+           The optional [level] argument sets the compression level
+           as documented for [Bzip2.open_out]. *)
+val output_char: out_channel -> char -> unit
+        (* Output one character to the given compressed channel. *)
+val output_byte: out_channel -> int -> unit
+        (* Same as [Bzip2.output_char], but the output character is given
+           by its code.  The given integer is taken modulo 256. *)
+val output: out_channel -> string -> int -> int -> unit
+        (* [output oc buf pos len] compresses and writes [len] characters
+           from string [buf], starting at offset [pos], and writes the
+           compressed data to the channel [oc].
+           Raise [Invalid_argument "Bzip2.output"] if
+           [pos] and [len] do not designate a valid substring of [buf]. *)
+val close_out: out_channel -> unit
+        (* Close the given output channel.  If the channel was created with
+           [Bzip2.open_out_chan], the underlying regular file channel
+           (of type [Pervasives.out_channel]) is also closed.
+           Do not apply any of the functions above to a closed channel. *)
+val flush: out_channel -> unit
+        (* Same as [Bzip2.close_out], but do not close the underlying
+           regular file channel (of type [Pervasives.out_channel]);
+           just flush all pending compressed data and
+           dispose of the resources associated with the compression
+           channel.  This can be useful if e.g. the underlying file channel
+           is a network socket on which more data is to be sent. *)
+
+(*** Error reporting *)
+
+exception Error of string
+        (* Exception raised by the functions above to signal errors during
+           compression or decompression, or ill-formed input files. *)
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/bzlib.ml ./src/utils/cdk/bzlib.ml
--- ./src/utils/cdk/bzlib.ml	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/bzlib.ml	2004-01-31 08:38:41.000000000 +0100
@@ -0,0 +1,38 @@
+
+type bzlib_error = BZ_CONFIG_ERROR | BZ_SEQUENCE_ERROR | BZ_PARAM_ERROR
+		   | BZ_MEM_ERROR | BZ_DATA_ERROR | BZ_DATA_ERROR_MAGIC
+		   | BZ_UNKNOWN_ERROR
+
+let string_of_error = function
+  | BZ_CONFIG_ERROR -> "Configuration Error"
+  | BZ_SEQUENCE_ERROR -> "Sequence Error"
+  | BZ_PARAM_ERROR -> "Invalid Parameter"
+  | BZ_MEM_ERROR -> "Memory Error"
+  | BZ_DATA_ERROR -> "Data Error in Bzip2 Stream"
+  | BZ_DATA_ERROR_MAGIC -> "Bad Magic Number"
+  | BZ_UNKNOWN_ERROR -> "Unknown"
+
+exception Error of string * bzlib_error
+
+let _ =
+  Callback.register_exception "Bzlib.Error" (Error("",BZ_CONFIG_ERROR))
+
+type stream
+
+type action = BZ_RUN | BZ_FLUSH | BZ_FINISH
+
+external compress_init: int -> int -> int -> stream = "camlzip_bzCompressInit"
+external compress:
+  stream -> string -> int -> int -> string -> int -> int -> action
+         -> bool * int * int
+  = "camlzip_bzCompress_bytecode" "camlzip_bzCompress"
+external compress_end: stream -> unit = "camlzip_bzCompressEnd"
+
+
+external decompress_init: int -> bool -> stream = "camlzip_bzDecompressInit"
+external decompress:
+  stream -> string -> int -> int -> string -> int -> int -> bool * int * int
+  = "camlzip_bzDecompress_bytecode" "camlzip_bzDecompress"
+external decompress_end: stream -> unit = "camlzip_bzDecompressEnd"
+
+
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/bzlib.mli ./src/utils/cdk/bzlib.mli
--- ./src/utils/cdk/bzlib.mli	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/bzlib.mli	2004-01-31 08:38:31.000000000 +0100
@@ -0,0 +1,23 @@
+
+type bzlib_error = BZ_CONFIG_ERROR | BZ_SEQUENCE_ERROR | BZ_PARAM_ERROR | BZ_MEM_ERROR | BZ_DATA_ERROR | BZ_DATA_ERROR_MAGIC | BZ_UNKNOWN_ERROR
+exception Error of string * bzlib_error
+
+val string_of_error: bzlib_error -> string
+
+type stream
+
+type action = BZ_RUN | BZ_FLUSH | BZ_FINISH
+
+external compress_init: int -> int -> int -> stream = "camlzip_bzCompressInit"
+external compress:
+  stream -> string -> int -> int -> string -> int -> int -> action
+         -> bool * int * int
+  = "camlzip_bzCompress_bytecode" "camlzip_bzCompress"
+external compress_end: stream -> unit = "camlzip_bzCompressEnd"
+
+
+external decompress_init: int -> bool -> stream = "camlzip_bzDecompressInit"
+external decompress:
+  stream -> string -> int -> int -> string -> int -> int -> bool * int * int
+  = "camlzip_bzDecompress_bytecode" "camlzip_bzDecompress"
+external decompress_end: stream -> unit = "camlzip_bzDecompressEnd"
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/gzip.ml ./src/utils/cdk/gzip.ml
--- ./src/utils/cdk/gzip.ml	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/gzip.ml	2001-08-07 17:32:06.000000000 +0200
@@ -0,0 +1,258 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                         The CamlZip library                         *)
+(*                                                                     *)
+(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
+(*                                                                     *)
+(*  Copyright 2001 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the GNU Library General Public License.         *)
+(*                                                                     *)
+(***********************************************************************)
+
+(* $Id: gzip.ml,v 1.1 2001/08/07 15:32:06 xleroy Exp $ *)
+
+(* Module [Gzip]: reading and writing to/from [gzip] compressed files *)
+
+exception Error of string
+
+let buffer_size = 1024
+
+type in_channel =
+  { in_chan: Pervasives.in_channel;
+    in_buffer: string;
+    mutable in_pos: int;
+    mutable in_avail: int;
+    mutable in_eof: bool;
+    in_stream: Zlib.stream;
+    mutable in_size: int32;
+    mutable in_crc: int32 }
+
+let open_in_chan ic =
+  (* Superficial parsing of header *)
+  begin try
+    let id1 = input_byte ic in
+    let id2 = input_byte ic in
+    if id1 <> 0x1F || id2 <> 0x8B then 
+      raise(Error("bad magic number, not a gzip file"));
+    let cm = input_byte ic in
+    if cm <> 8 then
+      raise(Error("unknown compression method"));
+    let flags = input_byte ic in
+    if flags land 0xE0 <> 0 then
+      raise(Error("bad flags, not a gzip file"));
+    for i = 1 to 6 do ignore(input_byte ic) done;
+    if flags land 0x04 <> 0 then begin
+      (* Skip extra data *)
+      let len1 = input_byte ic in
+      let len2 = input_byte ic in
+      for i = 1 to len1 + len2 lsl 8 do ignore(input_byte ic) done
+    end;
+    if flags land 0x08 <> 0 then begin
+      (* Skip original file name *)
+      while input_byte ic <> 0 do () done
+    end;
+    if flags land 0x10 <> 0 then begin
+      (* Skip comment *)
+      while input_byte ic <> 0 do () done
+    end;
+    if flags land 0x02 <> 0 then begin
+      (* Skip header CRC *)
+      ignore(input_byte ic); ignore(input_byte ic)
+    end
+  with End_of_file ->
+    raise(Error("premature end of file, not a gzip file"))
+  end;
+  { in_chan = ic;
+    in_buffer = String.create buffer_size;
+    in_pos = 0;
+    in_avail = 0;
+    in_eof = false;
+    in_stream = Zlib.inflate_init false;
+    in_size = Int32.zero;
+    in_crc = Int32.zero }
+
+let open_in filename =
+  open_in_chan (Pervasives.open_in_bin filename)
+
+let read_byte iz =
+  if iz.in_avail = 0 then begin
+    let n = Pervasives.input iz.in_chan iz.in_buffer 0
+                             (String.length iz.in_buffer) in
+    if n = 0 then raise End_of_file;
+    iz.in_pos <- 0;
+    iz.in_avail <- n
+  end;
+  let c = iz.in_buffer.[iz.in_pos] in
+  iz.in_pos <- iz.in_pos + 1;
+  iz.in_avail <- iz.in_avail - 1;
+  Char.code c
+
+let read_int32 iz =
+  let b1 = read_byte iz in
+  let b2 = read_byte iz in
+  let b3 = read_byte iz in
+  let b4 = read_byte iz in
+  Int32.logor (Int32.of_int b1)
+    (Int32.logor (Int32.shift_left (Int32.of_int b2) 8)
+      (Int32.logor (Int32.shift_left (Int32.of_int b3) 16)
+                   (Int32.shift_left (Int32.of_int b4) 24)))
+
+let rec input iz buf pos len =
+  if pos < 0 || len < 0 || pos + len > String.length buf then
+    invalid_arg "Gzip.input";
+  if iz.in_eof then 0 else begin
+    if iz.in_avail = 0 then begin
+      let n = Pervasives.input iz.in_chan iz.in_buffer 0
+                               (String.length iz.in_buffer) in
+      if n = 0 then raise(Error("truncated file"));
+      iz.in_pos <- 0;
+      iz.in_avail <- n
+    end;
+    let (finished, used_in, used_out) =
+      try
+        Zlib.inflate iz.in_stream iz.in_buffer iz.in_pos iz.in_avail
+                                   buf pos len Zlib.Z_SYNC_FLUSH
+      with Zlib.Error(_, _) ->
+        raise(Error("error during decompression")) in
+    iz.in_pos <- iz.in_pos + used_in;
+    iz.in_avail <- iz.in_avail - used_in;
+    iz.in_crc <- Zlib.update_crc iz.in_crc buf pos used_out;
+    iz.in_size <- Int32.add iz.in_size (Int32.of_int used_out);
+    if finished then begin
+      try
+        let crc = read_int32 iz in
+        let size = read_int32 iz in
+        if iz.in_crc <> crc then 
+          raise(Error("CRC mismatch, data corrupted"));
+        if iz.in_size <> size then
+          raise(Error("size mismatch, data corrupted"));
+        iz.in_eof <- true;
+        used_out
+      with End_of_file ->
+        raise(Error("truncated file"))
+    end
+    else if used_out = 0 then
+      input iz buf pos len
+    else
+      used_out
+  end
+
+let rec really_input iz buf pos len =
+  if len <= 0 then () else begin
+    let n = input iz buf pos len in
+    if n = 0 then raise End_of_file;
+    really_input iz buf (pos + n) (len - n)
+  end
+
+let char_buffer = String.create 1
+
+let input_char iz =
+  if input iz char_buffer 0 1 = 0 then raise End_of_file else char_buffer.[0]
+
+let input_byte iz =
+  Char.code (input_char iz)
+
+let dispose iz =
+  iz.in_eof <- true;
+  Zlib.inflate_end iz.in_stream
+
+let close_in iz =
+  dispose iz;
+  Pervasives.close_in iz.in_chan
+
+type out_channel =
+  { out_chan: Pervasives.out_channel;
+    out_buffer: string;
+    mutable out_pos: int;
+    mutable out_avail: int;
+    out_stream: Zlib.stream;
+    mutable out_size: int32;
+    mutable out_crc: int32 }
+
+let open_out_chan ?(level = 6) oc =
+  if level < 1 || level > 9 then invalid_arg "Gzip.open_out: bad level";
+  (* Write minimal header *)
+  output_byte oc 0x1F;                  (* ID1 *)
+  output_byte oc 0x8B;                  (* ID2 *)
+  output_byte oc 8;                     (* compression method *)
+  output_byte oc 0;                     (* flags *)
+  for i = 1 to 4 do output_byte oc 0 done; (* mtime *)
+  output_byte oc 0;                     (* xflags *)
+  output_byte oc 0xFF;                  (* OS (unknown) *)
+  { out_chan = oc;
+    out_buffer = String.create buffer_size;
+    out_pos = 0;
+    out_avail = buffer_size;
+    out_stream = Zlib.deflate_init level false;
+    out_size = Int32.zero;
+    out_crc = Int32.zero }
+
+let open_out ?(level = 6) filename =
+  open_out_chan ~level (Pervasives.open_out_bin filename)
+
+let rec output oz buf pos len =
+  if pos < 0 || len < 0 || pos + len > String.length buf then
+    invalid_arg "Gzip.output";
+  (* If output buffer is full, flush it *)
+  if oz.out_avail = 0 then begin
+    Pervasives.output oz.out_chan oz.out_buffer 0 oz.out_pos;
+    oz.out_pos <- 0;
+    oz.out_avail <- String.length oz.out_buffer
+  end;
+  let (_, used_in, used_out) =
+    try
+      Zlib.deflate oz.out_stream buf pos len
+                                 oz.out_buffer oz.out_pos oz.out_avail
+                                 Zlib.Z_NO_FLUSH
+    with Zlib.Error(_, _) ->
+      raise (Error("error during compression")) in
+  oz.out_pos <- oz.out_pos + used_out;
+  oz.out_avail <- oz.out_avail - used_out;
+  oz.out_size <- Int32.add oz.out_size (Int32.of_int used_in);
+  oz.out_crc <- Zlib.update_crc oz.out_crc buf pos used_in;
+  if used_in < len then output oz buf (pos + used_in) (len - used_in)
+
+let output_char oz c =
+  char_buffer.[0] <- c;
+  output oz char_buffer 0 1
+
+let output_byte oz b =
+  output_char oz (Char.unsafe_chr b)
+
+let write_int32 oc n =
+  let r = ref n in
+  for i = 1 to 4 do
+    Pervasives.output_byte oc (Int32.to_int !r);
+    r := Int32.shift_right_logical !r 8
+  done
+
+let flush oz =
+  let rec do_flush () =
+    (* If output buffer is full, flush it *)
+    if oz.out_avail = 0 then begin
+      Pervasives.output oz.out_chan oz.out_buffer 0 oz.out_pos;
+      oz.out_pos <- 0;
+      oz.out_avail <- String.length oz.out_buffer
+    end;
+    let (finished, _, used_out) =
+      Zlib.deflate oz.out_stream oz.out_buffer 0 0
+                                 oz.out_buffer oz.out_pos oz.out_avail
+                                 Zlib.Z_FINISH in
+    oz.out_pos <- oz.out_pos + used_out;
+    oz.out_avail <- oz.out_avail - used_out;
+    if not finished then do_flush() in
+  do_flush();
+  (* Final data flush *)
+  if oz.out_pos > 0 then
+    Pervasives.output oz.out_chan oz.out_buffer 0 oz.out_pos;
+  (* Write CRC and size *)
+  write_int32 oz.out_chan oz.out_crc;
+  write_int32 oz.out_chan oz.out_size;
+  (* Dispose of stream *)
+  Zlib.deflate_end oz.out_stream
+
+let close_out oz =
+  flush oz;
+  Pervasives.close_out oz.out_chan
+
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/gzip.mli ./src/utils/cdk/gzip.mli
--- ./src/utils/cdk/gzip.mli	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/gzip.mli	2002-02-18 10:12:13.000000000 +0100
@@ -0,0 +1,121 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                         The CamlZip library                         *)
+(*                                                                     *)
+(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
+(*                                                                     *)
+(*  Copyright 2001 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the GNU Library General Public License.         *)
+(*                                                                     *)
+(***********************************************************************)
+
+(* $Id: gzip.mli,v 1.2 2002/02/18 09:12:13 xleroy Exp $ *)
+
+(* Module [Gzip]: reading and writing to/from [gzip] compressed files *)
+
+(* This module provides functions to read and write compressed data
+   to/from files in [gzip] format. *)
+
+(*** Reading from compressed files *)
+
+type in_channel
+        (* Abstract type representing a channel opened for reading
+           from a compressed file. *)
+val open_in: string -> in_channel
+        (* Open a compressed file for reading.  The argument is the file
+           name. *)
+val open_in_chan: Pervasives.in_channel -> in_channel
+        (* Open a compressed file for reading.  The argument is a
+           regular file channel already opened on the compressed file. *)
+val input_char: in_channel -> char
+        (* Uncompress one character from the given channel, and return it.
+           Raise [End_of_file] if no more compressed data is available. *)
+val input_byte: in_channel -> int
+        (* Same as [Gzip.input_char], but return the 8-bit integer representing
+           the character.
+           Raise [End_of_file] if no more compressed data is available. *)
+val input: in_channel -> string -> int -> int -> int
+        (* [input ic buf pos len] uncompresses up to [len] characters
+           from the given channel [ic],
+           storing them in string [buf], starting at character number [pos].
+           It returns the actual number of characters read, between 0 and
+           [len] (inclusive).
+           A return value of 0 means that the end of file was reached.
+           A return value between 0 and [len] exclusive means that
+           not all requested [len] characters were read, either because
+           no more characters were available at that time, or because
+           the implementation found it convenient to do a partial read;
+           [input] must be called again to read the remaining characters,
+           if desired.  (See also [Gzip.really_input] for reading
+           exactly [len] characters.)
+           Exception [Invalid_argument "Gzip.input"] is raised if
+           [pos] and [len] do not designate a valid substring of [buf]. *)
+val really_input: in_channel -> string -> int -> int -> unit
+        (* [really_input ic buf pos len] uncompresses [len] characters
+           from the given channel, storing them in
+           string [buf], starting at character number [pos].
+           Raise [End_of_file] if fewer than [len] characters can be read.
+           Raise [Invalid_argument "Gzip.input"] if
+           [pos] and [len] do not designate a valid substring of [buf]. *)
+val close_in: in_channel -> unit
+        (* Close the given input channel.  If the channel was created with
+           [Gzip.open_in_chan], the underlying regular file channel
+           (of type [Pervasives.in_channel]) is also closed.
+           Do not apply any of the functions above to a closed channel. *)
+val dispose: in_channel -> unit
+        (* Same as [Gzip.close_in], but does not close the underlying
+           regular file channel (of type [Pervasives.in_channel]);
+           just dispose of the resources associated with the decompression
+           channel.  This can be useful if e.g. the underlying file channel
+           is a network socket on which more (uncompressed) data 
+           is expected. *)
+
+(*** Writing to compressed files *)
+
+type out_channel
+        (* Abstract type representing a channel opened for writing
+           to a compressed file. *)
+val open_out: ?level:int -> string -> out_channel
+        (* Open a compressed file for writing.  The argument is the file
+           name.  The file is created if it does not exist, or
+           truncated to zero length if it exists. 
+           The optional [level] argument (an integer between 1 and 9)
+           indicates the compression level, with 1 being the weakest
+           (but fastest) compression and 9 being the strongest
+           (but slowest) compression.  The default level is 6
+           (medium compression). *)
+val open_out_chan: ?level:int -> Pervasives.out_channel -> out_channel
+        (* Open a compressed file for writing.  The argument is a
+           regular file channel already opened on the compressed file.
+           The optional [level] argument sets the compression level
+           as documented for [Gzip.open_out]. *)
+val output_char: out_channel -> char -> unit
+        (* Output one character to the given compressed channel. *)
+val output_byte: out_channel -> int -> unit
+        (* Same as [Gzip.output_char], but the output character is given
+           by its code.  The given integer is taken modulo 256. *)
+val output: out_channel -> string -> int -> int -> unit
+        (* [output oc buf pos len] compresses and writes [len] characters
+           from string [buf], starting at offset [pos], and writes the
+           compressed data to the channel [oc].
+           Raise [Invalid_argument "Gzip.output"] if
+           [pos] and [len] do not designate a valid substring of [buf]. *)
+val close_out: out_channel -> unit
+        (* Close the given output channel.  If the channel was created with
+           [Gzip.open_out_chan], the underlying regular file channel
+           (of type [Pervasives.out_channel]) is also closed.
+           Do not apply any of the functions above to a closed channel. *)
+val flush: out_channel -> unit
+        (* Same as [Gzip.close_out], but do not close the underlying
+           regular file channel (of type [Pervasives.out_channel]);
+           just flush all pending compressed data and
+           dispose of the resources associated with the compression
+           channel.  This can be useful if e.g. the underlying file channel
+           is a network socket on which more data is to be sent. *)
+
+(*** Error reporting *)
+
+exception Error of string
+        (* Exception raised by the functions above to signal errors during
+           compression or decompression, or ill-formed input files. *)
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/tar.ml ./src/utils/cdk/tar.ml
--- ./src/utils/cdk/tar.ml	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/tar.ml	2004-02-13 18:19:10.000000000 +0100
@@ -0,0 +1,423 @@
+
+exception Error of string
+
+(* Types of files recongized by tar *)
+type file_type = REGULAR | LINK | SYMLINK | CHRSPEC | BLKSPEC | DIRECTORY | FIFO  | CONTIGIOUS | DUMPDIR (** GNU: A dir entry that contains the names of files that were in the dir at the time the dump was made. *) | LONGLINK (** GNU: Identifies the *next* file on the archive as having a long linkname *)| LONGNAME (** GNU: Identifies the *next* file on the tape as having a long name. *) | MULTIVOL (** GNU: The continuation of a file that began on another volume. *) | NAMES (** GNU: For storing filenames tha do not fit into the main header. *) | SPARSE (** GNU: Sparse file *) | VOLHDR (** GNU: This file is a tape/volume header. Ignore it on extraction. *)
+
+type record_type = POSIX_FORMAT | GNU_FORMAT | OLDGNU_FORMAT | V7_FORMAT
+
+(* The size of a header block *)
+let blocksize = 512 
+
+(* The metadata for a file in a tar archive *)
+type header = {
+  t_name: string;
+  t_mode: int;
+  t_uid: int;
+  t_gid: int;
+  t_size: int;
+  t_mtime: int32;
+  t_chksum: int;
+  t_typeflag: file_type;
+  t_linkname: string;
+  t_format: record_type;
+  t_uname: string;
+  t_gname: string;
+  t_devmajor: int;
+  t_devminor: int;
+  t_prefix: string;
+  t_gnu: gnu_extras option
+}
+and gnu_extras = {
+  t_atime: int32;
+  t_ctime: int32;
+  t_offset: int32;
+  t_realsize: int32;
+}
+
+class in_chan i = object
+  method really_input str pos len = 
+    try Pervasives.really_input i str pos len with
+	End_of_file -> raise (Error "Unexpected end of file")
+  method input str pos len = 
+    try Pervasives.input i str pos len with
+	End_of_file -> raise (Error "Unexpected end of file")
+  method dispose () = ()
+  method close () = Pervasives.close_in i
+end
+
+class gzin_chan i = object
+  method really_input str pos len =
+    try Gzip.really_input i str pos len with
+	End_of_file -> raise (Error "Unexpected end of file")
+  method input str pos len =
+    try Gzip.input i str pos len with
+	End_of_file -> raise (Error "Unexpected end of file")
+  method dispose () = Gzip.dispose i
+  method close () = Gzip.close_in i
+end
+
+class bzin_chan i = object
+  method really_input str pos len =
+    try Bzip2.really_input i str pos len with
+	End_of_file -> raise (Error "Unexpected end of file")
+  method input str pos len =
+    try Bzip2.input i str pos len with
+	End_of_file -> raise (Error "Unexpected end of file")
+  method dispose () = Bzip2.dispose i
+  method close () = Bzip2.close_in i
+end
+
+
+let open_inchan comp chan = 
+  match comp with
+    | `Plain -> new in_chan chan
+    | `Gzip -> new gzin_chan (Gzip.open_in_chan chan)
+    | `Bzip2 -> new bzin_chan (Bzip2.open_in_chan chan)
+
+let pick_comp_type filename = function
+  | `Gzip -> `Gzip
+  | `Bzip2 -> `Bzip2
+  | `Plain -> `Plain
+  | `Guess ->
+      if Filename.check_suffix filename ".tar" then
+	`Plain
+      else if Filename.check_suffix filename ".bz2" then
+	`Bzip2
+      else if Filename.check_suffix filename ".gz"
+	|| Filename.check_suffix filename ".Z"
+	|| Filename.check_suffix filename ".tgz" then
+	  `Gzip
+      else
+	`Plain
+
+type t_in = {
+  chan: in_chan;
+  rawchan: in_channel;
+  mutable last_header: header option;
+}
+
+let open_in_chan ?(compress=`Plain) chan =
+  {
+    chan = open_inchan compress chan;
+    rawchan = chan;
+    last_header = None;
+  }
+
+let open_in ?(compress=`Guess) filename =
+  open_in_chan ~compress:(pick_comp_type filename compress) (open_in_bin filename)
+
+
+let dispose t = t.chan#dispose ()
+and close_in t = t.chan#close ()
+
+(* Add Error Checking! *)
+let c_string raw start = 
+  let nul = String.index_from raw start '\000' in
+    String.sub raw start (nul - start)
+
+(* Numbers are /supposed/ to be 0 padded, octal, with a trailing "\000 ". About the only thing that's universal about this is octal. *)
+let trim_spaces str pos len =
+  let start = ref pos 
+  and stop = ref (pos + len - 1) in
+    while str.[!start] = ' ' do incr start done;
+    while str.[!stop] = ' ' || str.[!stop] = '\000' do decr stop done;
+    String.sub str !start (!stop - !start + 1)
+
+let extract_num raw pos len = 
+  if raw.[pos] = '\000' then 0
+  else try
+    int_of_string ("0o" ^ (trim_spaces raw pos len))
+  with Failure x -> raise (Error "Invalid number in header")
+
+let extract_int32 raw pos len = 
+  if raw.[pos] = '\000' then 0l
+  else try    
+    Int32.of_string ("0o" ^ trim_spaces raw pos len)
+  with Failure x ->  raise (Error "Invalid number in header")
+
+let typeflag = function
+  | '0' | '\000' -> REGULAR
+  | '1' -> LINK
+  | '2' -> SYMLINK
+  | '3' -> CHRSPEC
+  | '4' -> BLKSPEC
+  | '5' -> DIRECTORY
+  | '6' -> FIFO
+  | '7' -> CONTIGIOUS
+  | 'D' -> DUMPDIR
+  | 'K' -> LONGLINK
+  | 'L' -> LONGNAME
+  | 'M' -> MULTIVOL
+  | 'N' -> NAMES
+  | 'S' -> raise (Error "Sparse files are not supported")
+  | 'V' -> VOLHDR
+  | _ -> raise (Error "Unknown file type")
+
+let align_at_header t =
+  match t.last_header with
+    | None -> ()
+    | Some h ->
+	let entry_size = ((h.t_size/blocksize) + 1) * blocksize
+	and buf = String.create blocksize
+	and discarded = ref 0 in
+	  while !discarded < entry_size do
+	    let read = t.chan#input buf 0 blocksize in
+	      discarded := !discarded + read
+	  done;
+	  t.last_header <- None
+
+let empty_block = String.make blocksize '\000'
+
+let compute_chksum buf = 
+  let chksum = ref 256 in (* 256 is the sum of 8 ' ' characters for the chksum field *)
+    for i = 0 to 147 do
+      chksum := !chksum + Char.code buf.[i]
+    done;
+    for i = 156 to 511 do
+      chksum := !chksum + Char.code buf.[i]
+    done;
+    !chksum
+
+let read_magic header typec = 
+  let magic = String.sub header 257 8 in
+    match magic with
+      | "ustar  \000" -> OLDGNU_FORMAT
+      | "ustar\00000" -> begin match typec with
+	  | '0' .. '7' -> POSIX_FORMAT | _ -> GNU_FORMAT
+	end
+      | _ -> V7_FORMAT
+
+let read_oldgnu_header header =
+  { t_atime = extract_int32 header 345 12;
+    t_ctime = extract_int32 header 357 12;
+    t_offset = extract_int32 header 369 12;
+    t_realsize = extract_int32 header 483 12;
+  }
+
+let read_gnu_header t =
+  let buf = String.create blocksize in
+    t.chan#really_input buf 0 blocksize;
+    { t_atime = extract_int32 buf 0 12;
+      t_ctime = extract_int32 buf 12 12;
+      t_offset = extract_int32 buf 24 12;
+      t_realsize = extract_int32 buf 36 12;
+    }
+
+let read_header t =
+  align_at_header t;
+  let buf = String.create blocksize in
+    t.chan#really_input buf 0 blocksize;
+    if buf = empty_block then raise End_of_file;
+    let head1 = { t_name = c_string buf 0;
+		 t_mode = extract_num buf 100 8;
+		 t_uid = extract_num buf 108 8;
+		 t_gid = extract_num buf 116 8;
+		 t_size = extract_num buf 124 12;
+		 t_mtime = extract_int32 buf 136 12;
+		 t_chksum = extract_num buf 148 8;
+		 t_typeflag = typeflag buf.[156];
+		 t_linkname = c_string buf 157;
+		 t_format = read_magic buf buf.[156];
+		 t_uname = c_string buf 265;
+		 t_gname = c_string buf 297;
+		 t_devmajor = extract_num buf 329 8;
+		 t_devminor = extract_num buf 337 8;
+		 t_prefix = String.sub buf 345 155;
+		 t_gnu = None;
+	       } in
+    let chksum = compute_chksum buf in
+      if chksum <> head1.t_chksum then
+	raise (Error (Printf.sprintf "Invalid checksum in tar header. Calculated %d, expected %d" chksum head1.t_chksum));
+      let head =
+	if head1.t_format = OLDGNU_FORMAT then
+	  {head1 with t_gnu = Some (read_oldgnu_header buf) }
+	else if head1.t_format = GNU_FORMAT then
+	  {head1 with t_gnu = Some (read_gnu_header t) }
+	else
+	  head1 in	
+      t.last_header <- Some head;
+      head
+
+let align_at_body t =
+  match t.last_header with
+    | Some _ -> ()
+    | None -> ignore (read_header t)
+
+let get_header t =
+  match t.last_header with
+    | Some h -> h
+    | None -> raise (Error "Missing tar header?")
+    
+let read_body t =
+  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 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
+
+let read_entry t =
+  let head = read_header t in
+    head, read_body t
+
+class out_chan o = object
+  method output str pos len = Pervasives.output o str pos len
+  method flush () = Pervasives.flush o
+  method close () = Pervasives.close_out o
+end
+
+class gzout_chan o = object
+  method output str pos len = Gzip.output o str pos len
+  method flush () = Gzip.flush o
+  method close () = Gzip.close_out o
+end
+
+class bzout_chan o = object
+  method output str pos len = Bzip2.output o str pos len
+  method flush () = Bzip2.flush o
+  method close () = Bzip2.close_out o
+end
+
+
+let open_outchan comp chan = 
+  match comp with
+    | `Plain -> new out_chan chan
+    | `Gzip -> new gzout_chan (Gzip.open_out_chan chan)
+    | `Bzip2 -> new bzout_chan (Bzip2.open_out_chan chan)
+
+type t_out = {
+  ochan: out_chan;
+  rawochan: out_channel;
+}
+
+let open_out_chan ?(compress=`Plain) chan =
+  {
+    ochan = open_outchan compress chan;
+    rawochan = chan;
+  }
+
+let open_out ?(compress=`Plain) filename =
+  open_out_chan ~compress (open_out_bin filename)
+
+let write_str buf pos width str =
+  let len = min (String.length str) (width - 1) in
+    String.blit str 0 buf pos len
+
+let write_num8 buf pos n =
+  let as_str = Printf.sprintf "%07o" n in
+    String.blit as_str 0 buf pos 7
+
+let write_num12 buf pos n =
+  let as_str = Printf.sprintf "%011o" n in
+    String.blit as_str 0 buf pos 11
+
+let write_int32 buf pos n =
+  let as_str = Printf.sprintf "%011lo" n in
+    String.blit as_str 0 buf pos 11
+
+let write_padded_num buf pos n =
+  let as_str = Printf.sprintf "%07o\000 " n in
+    String.blit as_str 0 buf pos 8
+
+let write_magic buf pos magic =
+  let str = match magic with
+    | POSIX_FORMAT | GNU_FORMAT -> "ustar\00000"
+    | OLDGNU_FORMAT -> "ustar  \0000"
+    | V7_FORMAT -> "      \000"
+  in
+    String.blit str 0 buf pos 8
+
+let typeflag_to_char = function
+  | REGULAR -> '0'
+  | LINK -> '1'
+  | SYMLINK -> '2'
+  | CHRSPEC -> '3'
+  | BLKSPEC -> '4'
+  | DIRECTORY -> '5'
+  | FIFO -> '6'
+  | CONTIGIOUS -> '7'
+  | DUMPDIR -> 'D'
+  | LONGLINK -> 'K'
+  | LONGNAME -> 'L'
+  | MULTIVOL -> 'M'
+  | NAMES -> 'N'
+  | SPARSE -> raise (Error "Sparse files aren't supported for output")
+  | VOLHDR -> 'V'
+
+let isdigit = function '0' .. '9' -> true | _ -> false
+
+let write_oldgnu_header t buf =
+  let ext = match t.t_gnu with
+    | Some e -> e
+    | None -> raise (Error "OLDGNU_FORMAT record without t_gnu field set") in
+    write_int32 buf 345 ext.t_atime;
+    write_int32 buf 356 ext.t_ctime;
+    write_int32 buf 369 ext.t_offset;
+    write_int32 buf 483 ext.t_realsize
+
+let write_gnu_header t buf =
+  let ext = match t.t_gnu with
+    | Some e -> e
+    | None -> raise (Error "GNU_FORMAT record without t_gnu field set") in
+    write_int32 buf 0 ext.t_atime;
+    write_int32 buf 12 ext.t_ctime;
+    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
+  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
+      
+let flush t =
+  t.ochan#output empty_block 0 blocksize;
+  t.ochan#flush ()
+
+let close_out t =
+  flush t;
+  close_out t.rawochan
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/tar.mli ./src/utils/cdk/tar.mli
--- ./src/utils/cdk/tar.mli	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/tar.mli	2004-04-18 20:49:16.000000000 +0200
@@ -0,0 +1,106 @@
+
+(** Reading and writing TAR archives *)
+
+(** This module provides functions for reading and creating tar
+  archives. It supports compressed archives, and tries to deal with some
+  of the extensions to the tar format that various versions of tar
+  have. It can read POSIX and most gnu-tar format archives, and has a
+  chance at really old V7-style tar. It cannot yet deal with sparse
+  files. The good news is that it does read all the typical tarballs
+  I've thrown at it. *)
+
+(** Types of files recognized by tar *)
+type file_type = REGULAR | LINK | SYMLINK | CHRSPEC | BLKSPEC | DIRECTORY | FIFO  | CONTIGIOUS | DUMPDIR (** GNU: A dir entry that contains the names of files that were in the dir at the time the dump was made. *) | LONGLINK (** GNU: Identifies the *next* file on the archive as having a long linkname. The body of this entry is the linkname. *)| LONGNAME (** GNU: Identifies the *next* file on the tape as having a long name. The body of this entry is the filename. *) | MULTIVOL (** GNU: The continuation of a file that began on another volume. *) | NAMES (** GNU: For storing filenames that do not fit into the main header. I haven't yet figured out /where/ they're stored. *) | SPARSE (** GNU: Sparse file. *) | VOLHDR (** GNU: This file is a tape/volume header. Ignore it on extraction. *)
+
+(** Types of archives supported by this library. POSIX_FORMAT is the
+  best-supported type. It tries to deal with GNU extensions and the
+  mish-mash of formats that predate POSIX. If you find something it
+  breaks with, please tell me so support for it can be added. *)
+type record_type = POSIX_FORMAT | GNU_FORMAT | OLDGNU_FORMAT | V7_FORMAT
+
+(** The metadata for a file in a tar archive *)
+type header = {
+  t_name: string;
+  t_mode: int;
+  t_uid: int;
+  t_gid: int;
+  t_size: int;
+  t_mtime: int32;
+  t_chksum: int;
+  t_typeflag: file_type;
+  t_linkname: string;
+  t_format: record_type;
+  t_uname: string;
+  t_gname: string;
+  t_devmajor: int;
+  t_devminor: int;
+  t_prefix: string;
+  t_gnu: gnu_extras option; (** These aren't always set to meaningful values even with [OLDGNU_FORMAT] and [GNU_FORMAT] records. *)
+}
+and gnu_extras = {
+  t_atime: int32;
+  t_ctime: int32;
+  t_offset: int32;
+  t_realsize: int32;
+}
+
+(** Raised on errors involving not being able to parse the tar format
+  being used *)
+exception Error of string
+
+(** {1 Reading a tar archive} *)
+
+(** The type of tar files opened for reading *)
+type t_in
+
+(** Open a tar file, optionally compressed with gzip or bzip2. The
+  default behavior is to guess how the file is compressed based on its
+  extension. When in doubt, be specific. *)
+val open_in: ?compress:[<`Plain|`Gzip|`Bzip2|`Guess>`Guess] -> string -> t_in
+
+(** Treat an already-opened channel as a tar file, optionally compressed. *)
+val open_in_chan: ?compress:[<`Plain|`Gzip|`Bzip2>`Plain] -> in_channel -> t_in
+
+(** Return the header for the next file in the tar archive *)
+val read_header: t_in -> header
+
+(** 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
+
+(** Return the next file header and body in the archive *)
+val read_entry: t_in -> header * string
+
+(** Clean up and stop processing the archive without closing the input
+  channel *)
+val dispose: t_in -> unit
+
+(** Clean up and close the archive's input channel. *)
+val close_in: t_in -> unit
+
+(** {1 Writing a tar archive} *)
+
+(** The type for a tar file opened for reading *)
+type t_out
+
+(** Create a new tar file, optionally compressed with gzip or
+  bzip2. *)
+val open_out: ?compress:[<`Plain|`Gzip|`Bzip2>`Plain] -> string -> t_out
+
+(** Treat already-opened channel as the sink for a tar file to be
+  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
+  used as the file. [header.t_chksum] is also filled in
+  automatically. *)
+val output: t_out -> header -> string -> unit
+
+(** Flush out the tar archive but don't close the underlying
+  [out_channel] *)
+val flush: t_out -> unit
+
+(** Closes the tar file *)
+val close_out: t_out -> unit
+
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/zip.ml ./src/utils/cdk/zip.ml
--- ./src/utils/cdk/zip.ml	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/zip.ml	2001-08-07 17:32:06.000000000 +0200
@@ -0,0 +1,548 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                         The CamlZip library                         *)
+(*                                                                     *)
+(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
+(*                                                                     *)
+(*  Copyright 2001 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the GNU Library General Public License.         *)
+(*                                                                     *)
+(***********************************************************************)
+
+(* $Id: zip.ml,v 1.1 2001/08/07 15:32:06 xleroy Exp $ *)
+
+(* Module [Zip]: reading and writing ZIP archives *)
+
+exception Error of string * string * string
+
+let read1 = input_byte
+let read2 ic =
+  let lb = read1 ic in let hb = read1 ic in lb lor (hb lsl 8)
+let read4 ic =
+  let lw = read2 ic in let hw = read2 ic in
+  Int32.logor (Int32.of_int lw) (Int32.shift_left (Int32.of_int hw) 16)
+let read4_int ic =
+  let lw = read2 ic in let hw = read2 ic in
+  if hw > max_int lsr 16 then raise (Error("", "", "32-bit data too large"));
+  lw lor (hw lsl 16)
+let readstring ic n =
+  let s = String.create n in
+  really_input ic s 0 n; s
+
+let write1 = output_byte
+let write2 oc n =
+  write1 oc n; write1 oc (n lsr 8)
+let write4 oc n =
+  write2 oc (Int32.to_int n);
+  write2 oc (Int32.to_int (Int32.shift_right_logical n 16))
+let write4_int oc n =
+  write2 oc n;
+  write2 oc (n lsr 16)
+let writestring oc s =
+  output oc s 0 (String.length s)
+
+type compression_method = Stored | Deflated
+
+type entry =
+  { filename: string;
+    extra: string;
+    comment: string;
+    methd: compression_method;
+    mtime: float;
+    crc: int32;
+    uncompressed_size: int;
+    compressed_size: int;
+    is_directory: bool;
+    file_offset: int }
+
+type in_file =
+  { if_filename: string;
+    if_channel: Pervasives.in_channel;
+    if_entries: entry list;
+    if_directory: (string, entry) Hashtbl.t;
+    if_comment: string }
+
+let entries ifile = ifile.if_entries
+let comment ifile = ifile.if_comment
+
+type out_file =
+  { of_filename: string;
+    of_channel: Pervasives.out_channel;
+    mutable of_entries: entry list;
+    of_comment: string }
+
+exception Error of string * string * string
+
+(* Return the position of the last occurrence of s1 in s2, or -1 if not
+   found. *)
+
+let strrstr pattern buf ofs len =
+  let rec search i j =
+    if i < ofs then -1
+    else if j >= String.length pattern then i
+    else if pattern.[j] = buf.[i + j] then search i (j+1)
+    else search (i-1) 0
+  in search (ofs + len - String.length pattern) 0
+
+(* Determine if a file name is a directory (ends with /) *)
+
+let filename_is_directory name =
+  String.length name > 0 && name.[String.length name - 1] = '/'
+
+(* Convert between Unix dates and DOS dates *)
+
+let unixtime_of_dostime time date =
+  fst(Unix.mktime
+        { Unix.tm_sec = (time lsl 1) land 0x3e;
+          Unix.tm_min = (time lsr 5) land 0x3f;
+          Unix.tm_hour = (time lsr 11) land 0x1f;
+          Unix.tm_mday = date land 0x1f;
+          Unix.tm_mon = ((date lsr 5) land 0xf) - 1;
+          Unix.tm_year = ((date lsr 9) land 0x7f) + 80;
+          Unix.tm_wday = 0;
+          Unix.tm_yday = 0;
+          Unix.tm_isdst = false })
+
+let dostime_of_unixtime t =
+  let tm = Unix.localtime t in
+  (tm.Unix.tm_sec lsr 1
+     + (tm.Unix.tm_min lsl 5)
+     + (tm.Unix.tm_hour lsl 11),
+   tm.Unix.tm_mday
+     + (tm.Unix.tm_mon + 1) lsl 5
+     + (tm.Unix.tm_year - 80) lsl 9)
+
+(* Read end of central directory record *)
+
+let read_ecd filename ic =
+  let buf = String.create 256 in
+  let filelen = in_channel_length ic in
+  let rec find_ecd pos len =
+    (* On input, bytes 0 ... len - 1 of buf reflect what is at pos in ic *)
+    if pos <= 0 || filelen - pos >= 0x10000 then
+      raise (Error(filename, "",
+                   "end of central directory not found, not a ZIP file"));
+    let toread = min pos 128 in
+    (* Make room for "toread" extra bytes, and read them *)
+    String.blit buf 0 buf toread (256 - toread);
+    let newpos = pos - toread in
+    seek_in ic newpos;
+    really_input ic buf 0 toread;
+    let newlen = min (toread + len) 256 in
+    (* Search for magic number *)
+    let ofs = strrstr "PK\005\006" buf 0 newlen in
+    if ofs < 0 || newlen < 22 || 
+       (let comment_len = 
+          Char.code buf.[ofs + 20] lor (Char.code buf.[ofs + 21] lsl 8) in
+        newpos + ofs + 22 + comment_len <> filelen) then
+      find_ecd newpos newlen
+    else
+      newpos + ofs in
+  seek_in ic (find_ecd filelen 0);
+  let magic = read4 ic in
+  let disk_no = read2 ic in
+  let cd_disk_no = read2 ic in
+  let disk_entries = read2 ic in
+  let cd_entries = read2 ic in
+  let cd_size = read4_int ic in
+  let cd_offset = read4_int ic in
+  let comment_len = read2 ic in
+  let comment = readstring ic comment_len in
+  assert (magic = Int32.of_int 0x06054b50);
+  if disk_no <> 0 || cd_disk_no <> 0 then
+    raise (Error(filename, "", "multi-disk ZIP files not supported"));
+  (cd_entries, cd_offset, comment)
+
+(* Read central directory *)
+
+let read_cd filename ic cd_entries cd_offset =
+  try
+    seek_in ic cd_offset;
+    let e = ref [] in
+    for num_entry = 1 to cd_entries do
+      let magic = read4 ic in
+      let version_made_by = read2 ic in
+      let version_needed = read2 ic in
+      let flags = read2 ic in
+      let methd = read2 ic in
+      let lastmod_time = read2 ic in
+      let lastmod_date = read2 ic in
+      let crc = read4 ic in
+      let compr_size = read4_int ic in
+      let uncompr_size = read4_int ic in
+      let name_len = read2 ic in
+      let extra_len = read2 ic in
+      let comment_len = read2 ic in
+      let disk_number = read2 ic in
+      let internal_attr = read2 ic in
+      let external_attr = read4 ic in
+      let header_offset = read4_int ic in
+      let name = readstring ic name_len in
+      let extra = readstring ic extra_len in
+      let comment = readstring ic comment_len in
+      if magic <> Int32.of_int 0x02014b50 then
+        raise (Error(filename, name,
+                     "wrong file header in central directory"));
+      if flags land 1 <> 0 then
+        raise (Error(filename, name, "encrypted entries not supported"));
+
+      e := { filename = name;
+             extra = extra;
+             comment = comment;
+             methd = (match methd with
+                         0 -> Stored
+                       | 8 -> Deflated
+                       | _ -> raise (Error(filename, name,
+                                           "unknown compression method")));
+             mtime = unixtime_of_dostime lastmod_time lastmod_date;
+             crc = crc;
+             uncompressed_size = uncompr_size;
+             compressed_size = compr_size;
+             is_directory = filename_is_directory name;
+             file_offset = header_offset
+           } :: !e
+    done;
+    List.rev !e
+  with End_of_file ->
+    raise (Error(filename, "", "end-of-file while reading central directory"))
+
+(* Open a ZIP file for reading *)
+
+let open_in filename =
+  let ic = Pervasives.open_in_bin filename in
+  let (cd_entries, cd_offset, cd_comment) = read_ecd filename ic in
+  let entries = read_cd filename ic cd_entries cd_offset in
+  let dir = Hashtbl.create (cd_entries / 3) in
+  List.iter (fun e -> Hashtbl.add dir e.filename e) entries;
+  { if_filename = filename;
+    if_channel = ic;
+    if_entries = entries;
+    if_directory = dir;
+    if_comment = cd_comment }
+
+(* Close a ZIP file opened for reading *)
+
+let close_in ifile =
+  Pervasives.close_in ifile.if_channel
+
+(* Return the info associated with an entry *)
+
+let find_entry ifile name =
+  Hashtbl.find ifile.if_directory name
+
+(* Position on an entry *)
+
+let goto_entry ifile e =
+  try
+    let ic = ifile.if_channel in
+    seek_in ic e.file_offset;
+    let magic = read4 ic in
+    let version_needed = read2 ic in
+    let flags = read2 ic in
+    let methd = read2 ic in
+    let lastmod_time = read2 ic in
+    let lastmod_date = read2 ic in
+    let crc = read4 ic in
+    let compr_size = read4_int ic in
+    let uncompr_size = read4_int ic in
+    let filename_len = read2 ic in
+    let extra_len = read2 ic in
+    if magic <> Int32.of_int 0x04034b50 then
+       raise (Error(ifile.if_filename, e.filename, "wrong local file header"));
+    (* Could validate information read against directory entry, but
+       what the heck *)
+    seek_in ifile.if_channel (e.file_offset + 30 + filename_len + extra_len)
+  with End_of_file ->
+    raise (Error(ifile.if_filename, e.filename, "truncated local file header"))
+
+(* Read the contents of an entry as a string *)
+
+let read_entry ifile e =
+  try
+    goto_entry ifile e;
+    let res = String.create e.uncompressed_size in
+    match e.methd with
+      Stored ->
+        if e.compressed_size <> e.uncompressed_size then
+          raise (Error(ifile.if_filename, e.filename,
+                       "wrong size for stored entry"));
+        really_input ifile.if_channel res 0 e.uncompressed_size;
+        res
+    | Deflated ->
+        let in_avail = ref e.compressed_size in
+        let out_pos = ref 0 in
+        begin try
+          Zlib.uncompress ~header:false
+            (fun buf ->
+              let read = input ifile.if_channel buf 0
+                               (min !in_avail (String.length buf)) in
+              in_avail := !in_avail - read;
+              read)
+            (fun buf len ->
+              if !out_pos + len > String.length res then
+                raise (Error(ifile.if_filename, e.filename,
+                             "wrong size for deflated entry (too much data)"));
+              String.blit buf 0 res !out_pos len;
+              out_pos := !out_pos + len)
+        with Zlib.Error(_, _) ->
+          raise (Error(ifile.if_filename, e.filename, "decompression error"))
+        end;
+        if !out_pos <> String.length res then
+          raise (Error(ifile.if_filename, e.filename,
+                       "wrong size for deflated entry (not enough data)"));
+        let crc = Zlib.update_crc Int32.zero res 0 (String.length res) in
+        if crc <> e.crc then
+          raise (Error(ifile.if_filename, e.filename, "CRC mismatch"));
+        res
+  with End_of_file ->
+    raise (Error(ifile.if_filename, e.filename, "truncated data"))
+    
+(* Write the contents of an entry into an out channel *)
+
+let copy_entry_to_channel ifile e oc =
+  try
+    goto_entry ifile e;
+    match e.methd with
+      Stored ->
+        if e.compressed_size <> e.uncompressed_size then
+          raise (Error(ifile.if_filename, e.filename,
+                       "wrong size for stored entry"));
+        let buf = String.create 4096 in
+        let rec copy n =
+          if n > 0 then begin
+            let r = input ifile.if_channel buf 0 (min n (String.length buf)) in
+            output oc buf 0 r;
+            copy (n - r)
+          end in
+        copy e.uncompressed_size
+    | Deflated ->
+        let in_avail = ref e.compressed_size in
+        let crc = ref Int32.zero in
+        begin try
+          Zlib.uncompress ~header:false
+            (fun buf ->
+              let read = input ifile.if_channel buf 0
+                               (min !in_avail (String.length buf)) in
+              in_avail := !in_avail - read;
+              read)
+            (fun buf len ->
+              output oc buf 0 len;
+              crc := Zlib.update_crc !crc buf 0 len)
+        with Zlib.Error(_, _) ->
+          raise (Error(ifile.if_filename, e.filename, "decompression error"))
+        end;
+        if !crc <> e.crc then
+          raise (Error(ifile.if_filename, e.filename, "CRC mismatch"))
+  with End_of_file ->
+    raise (Error(ifile.if_filename, e.filename, "truncated data"))
+    
+(* Write the contents of an entry to a file *)
+
+let copy_entry_to_file ifile e outfilename =
+  let oc = open_out_bin outfilename in
+  try
+    copy_entry_to_channel ifile e oc;
+    close_out oc;
+    begin try
+      Unix.utimes outfilename e.mtime e.mtime
+    with Unix.Unix_error(_, _, _) | Invalid_argument _ -> ()
+    end
+  with x ->
+    close_out oc;
+    Sys.remove outfilename;
+    raise x
+
+(* Open a ZIP file for writing *)
+
+let open_out ?(comment = "") filename =
+  if String.length comment >= 0x10000 then
+    raise(Error(filename, "", "comment too long"));
+  { of_filename = filename;
+    of_channel = Pervasives.open_out_bin filename;
+    of_entries = [];
+    of_comment = comment }
+
+(* Close a ZIP file for writing.  Add central directory. *)
+
+let write_directory_entry oc e =
+  write4 oc (Int32.of_int 0x02014b50);  (* signature *)
+  let version = match e.methd with Stored -> 10 | Deflated -> 20 in
+  write2 oc version;                    (* version made by *)
+  write2 oc version;                    (* version needed to extract *)
+  write2 oc 8;                          (* flags *)
+  write2 oc (match e.methd with Stored -> 0 | Deflated -> 8); (* method *)
+  let (time, date) = dostime_of_unixtime e.mtime in
+  write2 oc time;                       (* last mod time *)
+  write2 oc date;                       (* last mod date *)
+  write4 oc e.crc;                      (* CRC32 *)
+  write4_int oc e.compressed_size;      (* compressed size *)
+  write4_int oc e.uncompressed_size;    (* uncompressed size *)
+  write2 oc (String.length e.filename); (* filename length *)
+  write2 oc (String.length e.extra);    (* extra length *)
+  write2 oc (String.length e.comment);  (* comment length *)
+  write2 oc 0;                          (* disk number start *)
+  write2 oc 0;                          (* internal attributes *)
+  write4_int oc 0;                      (* external attributes *)
+  write4_int oc e.file_offset;          (* offset of local header *)
+  writestring oc e.filename;            (* filename *)
+  writestring oc e.extra;               (* extra info *)
+  writestring oc e.comment              (* file comment *)
+
+let close_out ofile =
+  let oc = ofile.of_channel in
+  let start_cd = pos_out oc in
+  List.iter (write_directory_entry oc) (List.rev ofile.of_entries);
+  let cd_size = pos_out oc - start_cd in
+  let num_entries = List.length ofile.of_entries in
+  if num_entries >= 0x10000 then
+    raise(Error(ofile.of_filename, "", "too many entries"));
+  write4 oc (Int32.of_int 0x06054b50);  (* signature *)
+  write2 oc 0;                          (* disk number *)
+  write2 oc 0;                          (* number of disk with central dir *)
+  write2 oc num_entries;                (* # entries in this disk *)
+  write2 oc num_entries;                (* # entries in central dir *)
+  write4_int oc cd_size;                (* size of central dir *)
+  write4_int oc start_cd;               (* offset of central dir *)
+  write2 oc (String.length ofile.of_comment); (* length of comment *)
+  writestring oc ofile.of_comment;         (* comment *)
+  Pervasives.close_out oc
+
+(* Write a local file header and return the corresponding entry *)
+
+let add_entry_header ofile extra comment level mtime filename =
+  if level < 0 || level > 9 then
+    raise(Error(ofile.of_filename, filename, "wrong compression level"));
+  if String.length filename >= 0x10000 then
+    raise(Error(ofile.of_filename, filename, "filename too long"));
+  if String.length extra >= 0x10000 then
+    raise(Error(ofile.of_filename, filename, "extra data too long"));
+  if String.length comment >= 0x10000 then
+    raise(Error(ofile.of_filename, filename, "comment too long"));
+  let oc = ofile.of_channel in
+  let pos = pos_out oc in
+  write4 oc (Int32.of_int 0x04034b50);  (* signature *)
+  let version = if level = 0 then 10 else 20 in
+  write2 oc version;                    (* version needed to extract *)
+  write2 oc 8;                          (* flags *)
+  write2 oc (if level = 0 then 0 else 8); (* method *)
+  let (time, date) = dostime_of_unixtime mtime in
+  write2 oc time;                       (* last mod time *)
+  write2 oc date;                       (* last mod date *)
+  write4 oc Int32.zero;                 (* CRC32 - to be filled later *)
+  write4_int oc 0;                      (* compressed size - later *)
+  write4_int oc 0;                      (* uncompressed size - later *)
+  write2 oc (String.length filename);   (* filename length *)
+  write2 oc (String.length extra);      (* extra length *)
+  writestring oc filename;              (* filename *)
+  writestring oc extra;                 (* extra info *)
+  { filename = filename;
+    extra = extra;
+    comment = comment;
+    methd = (if level = 0 then Stored else Deflated);
+    mtime = mtime;
+    crc = Int32.zero;
+    uncompressed_size = 0;
+    compressed_size = 0;
+    is_directory = filename_is_directory filename;
+    file_offset = pos }
+
+(* Write a data descriptor and update the entry *)
+
+let add_data_descriptor ofile crc compr_size uncompr_size entry =
+  let oc = ofile.of_channel in
+  write4 oc (Int32.of_int 0x08074b50);  (* signature *)
+  write4 oc crc;                        (* CRC *)
+  write4_int oc compr_size;             (* compressed size *)
+  write4_int oc uncompr_size;           (* uncompressed size *)
+  { entry with crc = crc;
+               uncompressed_size = uncompr_size;
+               compressed_size = compr_size }
+
+(* Add an entry with the contents of a string *)
+
+let add_entry data ofile ?(extra = "") ?(comment = "") 
+                         ?(level = 6) ?(mtime = Unix.time()) name =
+  let e = add_entry_header ofile extra comment level mtime name in
+  let crc = Zlib.update_crc Int32.zero data 0 (String.length data) in
+  let compr_size =
+    match level with
+      0 ->
+        output ofile.of_channel data 0 (String.length data);
+        String.length data
+    | _ ->
+        let in_pos = ref 0 in
+        let out_pos = ref 0 in
+        try
+          Zlib.compress ~header:false
+            (fun buf ->
+               let n = min (String.length data - !in_pos)
+                           (String.length buf) in
+               String.blit data !in_pos buf 0 n;
+               in_pos := !in_pos + n;
+               n)
+            (fun buf n ->
+                output ofile.of_channel buf 0 n;
+                out_pos := !out_pos + n);
+          !out_pos
+        with Zlib.Error(_, _) ->
+          raise (Error(ofile.of_filename, name, "compression error")) in
+  let e' = add_data_descriptor ofile crc compr_size (String.length data) e in
+  ofile.of_entries <- e' :: ofile.of_entries
+
+(* Add an entry with the contents of an in channel *)
+
+let copy_channel_to_entry ic ofile ?(extra = "") ?(comment = "") 
+                                   ?(level = 6) ?(mtime = Unix.time()) name =
+  let e = add_entry_header ofile extra comment level mtime name in
+  let crc = ref Int32.zero in
+  let (compr_size, uncompr_size) =
+    match level with
+      0 ->
+        let buf = String.create 4096 in
+        let rec copy sz =
+          let r = input ic buf 0 (String.length buf) in
+          if r = 0 then sz else begin
+            crc := Zlib.update_crc !crc buf 0 r;
+            output ofile.of_channel buf 0 r;
+            sz + r
+          end in
+        let size = copy 0 in
+        (size, size)
+    | _ ->
+        let in_pos = ref 0 in
+        let out_pos = ref 0 in
+        try
+          Zlib.compress ~header:false
+            (fun buf ->
+               let r = input ic buf 0 (String.length buf) in
+               crc := Zlib.update_crc !crc buf 0 r;
+               in_pos := !in_pos + r;
+               r)
+            (fun buf n ->            
+               output ofile.of_channel buf 0 n;
+               out_pos := !out_pos + n);
+          (!out_pos, !in_pos)
+        with Zlib.Error(_, _) ->
+          raise (Error(ofile.of_filename, name, "compression error")) in
+  let e' = add_data_descriptor ofile !crc compr_size uncompr_size e in
+  ofile.of_entries <- e' :: ofile.of_entries
+
+(* Add an entry with the contents of a file *)
+
+let copy_file_to_entry infilename ofile ?(extra = "") ?(comment = "") 
+                                        ?(level = 6) ?mtime name =
+  let ic = open_in_bin infilename in
+  let mtime' =
+    match mtime with 
+      Some t -> mtime
+    | None ->
+        try Some((Unix.stat infilename).Unix.st_mtime)
+        with Unix.Unix_error(_,_,_) -> None in
+  try
+    copy_channel_to_entry ic ofile ~extra ~comment ~level ?mtime:mtime' name;
+    Pervasives.close_in ic
+  with x ->
+    Pervasives.close_in ic; raise x
+
+
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/zip.mli ./src/utils/cdk/zip.mli
--- ./src/utils/cdk/zip.mli	1970-01-01 01:00:00.000000000 +0100
+++ ./src/utils/cdk/zip.mli	2001-08-07 17:32:07.000000000 +0200
@@ -0,0 +1,153 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                         The CamlZip library                         *)
+(*                                                                     *)
+(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
+(*                                                                     *)
+(*  Copyright 2001 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the GNU Library General Public License.         *)
+(*                                                                     *)
+(***********************************************************************)
+
+(* $Id: zip.mli,v 1.1 2001/08/07 15:32:07 xleroy Exp $ *)
+
+(* Module [Zip]: reading and writing ZIP archives *)
+
+(* This module provides functions for reading and writing ZIP archive
+   files.  ZIP archives package one or more compressed files into
+   a single ``ZIP file'' along with information about the files,
+   including file name, date and time of last modification, user-provided
+   comments, and a checksum to verify the integrity of each entry.
+   The entries of a ZIP file are not necessarily actual files, and can
+   actually consist of arbitrary data.
+
+   The ZIP file format used in this module is identical to that
+   implemented by the popular [pkzip] archiver under Windows,
+   and by the Info-ZIP [zip] and [unzip] commands under Unix and Windows.
+   This format is also identical to the JAR file format used by Java. *)
+
+(*** Information on ZIP entries *)
+
+type compression_method =
+    Stored                     (* data is stored without compression *)
+  | Deflated                   (* data is compressed with the ``deflate'' algorithm *)
+        (* Indicate whether the data in the entry is compressed or not. *)
+
+type entry =
+  { filename: string;          (* file name for entry *)
+    extra: string;             (* extra information attached to entry *)
+    comment: string;           (* comment attached to entry *)
+    methd: compression_method; (* compression method *)
+    mtime: float;              (* last modification time (seconds since epoch) *)
+    crc: int32;                (* cyclic redundancy check for data *)
+    uncompressed_size: int;    (* size of original data in bytes *)
+    compressed_size: int;      (* size of compressed data *)
+    is_directory: bool;        (* whether this entry represents a directory *)
+    file_offset: int }         (* for internal use *)
+          (* Description of an entry in a ZIP file. *)
+
+(*** Reading from ZIP files *)
+
+type in_file
+          (* Abstract type representing a channel opened for reading from
+             a ZIP file. *)
+val open_in: string -> in_file
+          (* Open the ZIP file with the given filename.  Return a
+             channel opened for reading from this file. *)
+val entries: in_file -> entry list
+          (* Return a list of all entries in the given ZIP file. *)
+val comment: in_file -> string
+          (* Return the comment attached to the given ZIP file, or the
+             empty string if none. *)
+val find_entry: in_file -> string -> entry
+          (* [Zip.find_entry zf filename] returns the description of the
+             entry having name [filename] in the ZIP file [zf].
+             Raises [Not_found] if no such entry exists.
+             The file name must match exactly; in particular, case is
+             significant.  File names must use [/] (slash) as the directory
+             separator.  The name of a directory must end with a trailing 
+             [/] (slash). *)
+val read_entry: in_file -> entry -> string
+          (* [Zip.read_entry zf e] reads and uncompresses the data
+             (file contents) associated with entry [e] of ZIP file [zf].
+             The data is returned as a character string. *)
+val copy_entry_to_channel: in_file -> entry -> out_channel -> unit
+          (* [Zip.copy_entry_to_channel zf e oc] reads and uncompresses
+             the data associated with entry [e] of ZIP file [zf].
+             It then writes this data to the output channel [oc]. *)
+val copy_entry_to_file: in_file -> entry -> string -> unit
+          (* [Zip.copy_entry_to_file zf e destfile] reads and uncompresses
+             the data associated with entry [e] of ZIP file [zf].
+             It then writes this data to the file named [destfile].
+             The file [destfile] is created if it does not exist,
+             and overwritten otherwise.  The last modification date of
+             the file is set to that indicated in the ZIP entry [e],
+             if possible. *)
+val close_in: in_file -> unit
+          (* Close the given ZIP file channel. *)
+
+(*** Writing from ZIP files *)
+
+type out_file
+          (* Abstract type representing a channel opened for writing from
+             a ZIP file. *)
+val open_out: ?comment: string -> string -> out_file
+          (* Create (or truncate to zero length) the ZIP file with
+             the given filename.  Return a channel opened for writing
+             to this file.  The optional argument [comment] is a
+             comment string that is attached to the ZIP file as a whole
+             (as opposed to the comments that can be attached to individual
+             ZIP entries). *) 
+val add_entry:
+  string -> out_file -> 
+    ?extra: string -> ?comment: string -> ?level: int ->
+    ?mtime: float -> string -> unit
+          (* [Zip.add_entry data zf name] adds a new entry to the 
+             ZIP file [zf].  The data (file contents) associated with
+             the entry is taken from the string [data].  It is compressed
+             and written to the ZIP file [zf].  [name] is the file name
+             stored along with this entry.  Several optional arguments
+             can be provided to control the format and attached information 
+             of the entry:
+-            [extra]  extra data attached to the entry (a string).
+               Default: empty.
+-            [comment]  comment attached to the entry (a string)
+               Default: empty.
+-            [level]  compression level for the entry.  This is an integer
+               between 0 and 9, with 0 meaning no compression (store as is),
+               1 lowest compression, 9 highest compression.  Higher
+               levels result in smaller compressed data, but longer compression
+               times.  Default: 6 (moderate compression).
+-            [mtime]  last modification time (in seconds since the epoch).
+               Default: the current time. *)
+val copy_channel_to_entry:
+  in_channel -> out_file -> 
+    ?extra: string -> ?comment: string -> ?level: int ->
+    ?mtime: float -> string -> unit
+          (* Same as [Zip.add_entry], but the data associated with the
+             entry is read from the input channel given as first argument.
+             The channel is read up to end of file. *)
+val copy_file_to_entry:
+  string -> out_file -> 
+    ?extra: string -> ?comment: string -> ?level: int ->
+    ?mtime: float -> string -> unit
+          (* Same as [Zip.add_entry], but the data associated with the
+             entry is read from the file whose name is given as first
+             argument.  Also, the default value for the [mtime]
+             optional parameter is the time of last modification of the
+             file. *)
+val close_out: out_file -> unit
+          (* Finish writing the ZIP archive by adding the table of
+             contents, and close it. *)
+
+(*** Error reporting *)
+
+exception Error of string * string * string
+          (* Exception raised when an ill-formed ZIP archive is encountered,
+             or illegal parameters are given to the functions in this
+             module.  The exception is of the form
+             [Error(ZIP_name, entry_name, message)] where [ZIP_name]
+             is the name of the ZIP file, [entry_name] the name of
+             the offending entry, and [message] an explanation of the
+             error. *)
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/cdk/zlibstubs.c ./src/utils/cdk/zlibstubs.c
--- ./src/utils/cdk/zlibstubs.c	2003-04-23 00:33:40.000000000 +0200
+++ ./src/utils/cdk/zlibstubs.c	2005-07-18 18:57:44.000000000 +0200
@@ -10,10 +10,18 @@
 /*                                                                     */
 /***********************************************************************/
 
+/* $Id: zlibstubs.c,v 1.1 2001/08/07 15:32:08 xleroy Exp $ */
+
 /* Stub code to interface with Zlib */
 
+#include "../../../config/config.h"
+
 #include <zlib.h>
 
+#ifdef USE_BZIP2
+#include <bzlib.h>
+#endif
+
 #include <caml/mlvalues.h>
 #include <caml/alloc.h>
 #include <caml/callback.h>
@@ -170,3 +178,189 @@
                           Long_val(len)));
 }
 
+/* Bzip2 interface code */
+
+#define BZStream_val(v) ((bz_stream *) (v))
+
+static value * camlzip_bzerror_exn = NULL;
+
+#ifdef USE_BZIP2
+static void camlzip_bzerror(char * fn, int err)
+{
+  char * msg;
+  value s1 = Val_unit, s2 = Val_unit, bucket = Val_unit;
+
+  if (camlzip_bzerror_exn == NULL) {
+    camlzip_bzerror_exn = caml_named_value("Bzlib.Error");
+    if (camlzip_bzerror_exn == NULL)
+      invalid_argument("Exception Bzlib.Error not initialized");
+  }
+  Begin_roots3(s1, s2, bucket);
+    s1 = copy_string(fn);
+    switch (err) {
+    case BZ_CONFIG_ERROR:
+      s2 = Val_int(0);
+      break;
+    case BZ_SEQUENCE_ERROR:
+      s2 = Val_int(1);
+      break;
+    case BZ_PARAM_ERROR:
+      s2 = Val_int(2);
+      break;
+    case BZ_MEM_ERROR:
+      s2 = Val_int(3);
+      break;
+    case BZ_DATA_ERROR:
+      s2 = Val_int(4);
+      break;
+    case BZ_DATA_ERROR_MAGIC:
+      s2 = Val_int(5);
+      break;
+    default:
+      s2 = Val_int(6);
+    }
+    bucket = alloc_small(3, 0);
+    Field(bucket, 0) = *camlzip_bzerror_exn;
+    Field(bucket, 1) = s1;
+    Field(bucket, 2) = s2;
+  End_roots();
+  mlraise(bucket);
+}
+
+static value camlzip_new_bzstream(void)
+{
+  value res = alloc((sizeof(bz_stream) + sizeof(value) - 1) / sizeof(value),
+                    Abstract_tag);
+  ZStream_val(res)->zalloc = NULL;
+  ZStream_val(res)->zfree = NULL;
+  ZStream_val(res)->opaque = NULL;
+  ZStream_val(res)->next_in = NULL;
+  ZStream_val(res)->next_out = NULL;
+  return res;
+}
+
+int camlzip_action_table[] = { BZ_RUN, BZ_FLUSH, BZ_FINISH };
+#endif
+
+
+value camlzip_bzCompressInit(value blockSize100k, value verbosity, value workFactor) {
+#ifdef USE_BZIP2
+  int err;
+  value vbzs = camlzip_new_bzstream();
+  if ((err = BZ2_bzCompressInit(BZStream_val(vbzs),
+			 Int_val(blockSize100k),
+			 Int_val(verbosity),
+			 Int_val(workFactor))) != BZ_OK)
+    camlzip_bzerror("Zlib.deflateInit", err);
+  return vbzs;
+#else
+  failwith("Bzip2 compression not supported.");
+#endif
+}
+
+value camlzip_bzCompress(value vzs, value srcbuf, value srcpos, value srclen,
+                      value dstbuf, value dstpos, value dstlen,
+                      value vflush)
+{
+#ifdef USE_BZIP2
+  bz_stream * zs = BZStream_val(vzs);
+  int retcode;
+  long used_in, used_out;
+  value res;
+
+  zs->next_in = &Byte(srcbuf, Long_val(srcpos));
+  zs->avail_in = Long_val(srclen);
+  zs->next_out = &Byte(dstbuf, Long_val(dstpos));
+  zs->avail_out = Long_val(dstlen);
+  retcode = BZ2_bzCompress(zs, camlzip_action_table[Int_val(vflush)]);
+  if (retcode < 0) camlzip_bzerror("Bzlib.compress", retcode);
+  used_in = Long_val(srclen) - zs->avail_in;
+  used_out = Long_val(dstlen) - zs->avail_out;
+  zs->next_in = NULL;         /* not required, but cleaner */
+  zs->next_out = NULL;        /* (avoid dangling pointers into Caml heap) */
+  res = alloc_small(3, 0);
+  Field(res, 0) = Val_bool(retcode == BZ_STREAM_END);
+  Field(res, 1) = Val_int(used_in);
+  Field(res, 2) = Val_int(used_out);
+  return res;
+#else
+  failwith("Bzip2 compression not supported");
+#endif
+}
+
+value camlzip_bzCompress_bytecode(value * arg, int nargs)
+{
+  return camlzip_bzCompress(arg[0], arg[1], arg[2], arg[3],
+                         arg[4], arg[5], arg[6], arg[7]);
+}
+
+value camlzip_bzCompressEnd(value stream) {
+#ifdef USE_BZIP2
+  int err;
+  if ((err = BZ2_bzCompressEnd(BZStream_val(stream))) != BZ_OK)
+    camlzip_bzerror("Bzlib.compress_end", err);
+#else
+  failwith("Bzip2 compression not supported");
+#endif
+  return Val_unit;
+}
+
+value camlzip_bzDecompressInit(value verbosity, value small)
+{
+#ifdef USE_BZIP2
+  int err;
+  value vzs = camlzip_new_bzstream();
+  if ((err = BZ2_bzDecompressInit(BZStream_val(vzs), Int_val(verbosity), Bool_val(small))) != BZ_OK)
+    camlzip_bzerror("Bzlib.decompress_init", err);
+  return vzs;
+#else
+  failwith("Bzip2 compression not supported");
+#endif
+}
+
+value camlzip_bzDecompress(value vzs, value srcbuf, value srcpos, value srclen,
+			   value dstbuf, value dstpos, value dstlen)
+{
+#ifdef USE_BZIP2
+  bz_stream * zs = BZStream_val(vzs);
+  int retcode;
+  long used_in, used_out;
+  value res;
+
+  zs->next_in = &Byte(srcbuf, Long_val(srcpos));
+  zs->avail_in = Long_val(srclen);
+  zs->next_out = &Byte(dstbuf, Long_val(dstpos));
+  zs->avail_out = Long_val(dstlen);
+  retcode = BZ2_bzDecompress(zs);
+  if (retcode < 0)
+    camlzip_bzerror("Bzlib.decompress", retcode);
+  used_in = Long_val(srclen) - zs->avail_in;
+  used_out = Long_val(dstlen) - zs->avail_out;
+  zs->next_in = NULL;           /* not required, but cleaner */
+  zs->next_out = NULL;          /* (avoid dangling pointers into Caml heap) */
+  res = alloc_small(3, 0);
+  Field(res, 0) = Val_bool(retcode == BZ_STREAM_END);
+  Field(res, 1) = Val_int(used_in);
+  Field(res, 2) = Val_int(used_out);
+  return res;
+#else
+  failwith("Bzip2 compression not supported");
+#endif
+}
+
+value camlzip_bzDecompress_bytecode(value * arg, int nargs)
+{
+  return camlzip_bzDecompress(arg[0], arg[1], arg[2], arg[3],
+                         arg[4], arg[5], arg[6]);
+}
+
+value camlzip_bzDecompressEnd(value stream) {
+#ifdef USE_BZIP2
+  int err;
+  if ((err = BZ2_bzDecompressEnd(BZStream_val(stream))) != BZ_OK)
+    camlzip_bzerror("Bzlib.decompressEnd", err);
+#else
+  failwith("Bzip2 compression not supported");
+#endif
+  return Val_unit;
+}
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/lib/autoconf.ml.new.in ./src/utils/lib/autoconf.ml.new.in
--- ./src/utils/lib/autoconf.ml.new.in	2005-07-13 01:08:57.000000000 +0200
+++ ./src/utils/lib/autoconf.ml.new.in	2005-07-18 19:01:48.000000000 +0200
@@ -39,6 +39,7 @@
 let has_gd_png = @HAS_GD_PNG@
 let has_gd_jpg = @HAS_GD_JPG@
 
+let has_bzip2 = @HAS_BZIP2@
 let has_zlib = @HAS_ZLIB@
 let zlib__uncompress_string2 s = @ZLIB__UNCOMPRESS_STRING2@
 let zlib__compress_string s = @ZLIB__COMPRESS_STRING@
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/lib/misc.ml ./src/utils/lib/misc.ml
--- ./src/utils/lib/misc.ml	2005-07-13 01:08:57.000000000 +0200
+++ ./src/utils/lib/misc.ml	2005-07-18 20:16:56.000000000 +0200
@@ -48,3 +48,94 @@
 let bin2dec num =
   let s = string_of_int num in
     int_of_string ("0b" ^ s)
+
+let zip_extract_entry ifile e =
+  if e.Zip.is_directory then begin
+    try
+      Unix.mkdir e.Zip.filename 0o777
+    with Unix.Unix_error(Unix.EEXIST, _, _) -> ()
+  end else begin
+    Zip.copy_entry_to_file ifile e e.Zip.filename
+  end
+
+let zip_extract zipfile =
+  let ic = Zip.open_in zipfile in
+  List.iter (zip_extract_entry ic) (Zip.entries ic);
+  Zip.close_in ic
+
+let rec zip_add_entry oc file =
+  let s = Unix.stat file in
+  match s.Unix.st_kind with
+    Unix.S_REG ->
+      Zip.copy_file_to_entry file oc ~mtime:s.Unix.st_mtime file
+  | Unix.S_DIR ->
+      Zip.add_entry "" oc ~mtime:s.Unix.st_mtime
+        (if Filename.check_suffix file "/" then file else file ^ "/");
+      let d = Unix.opendir file in
+      begin try
+        while true do
+          let e = Unix.readdir d in
+          if e <> "." && e <> ".." then zip_add_entry oc (Filename.concat file e)
+        done
+      with End_of_file -> ()
+      end;
+      Unix.closedir d
+  | _ -> ()  
+
+let zip_create zipfile files =
+  let oc = Zip.open_out zipfile in
+  Array.iter (zip_add_entry oc) files;
+  Zip.close_out oc
+
+let bz2_extract filename =
+  begin
+    try
+      let buffer = String.create 4096 in
+      let file_out = Filename.temp_file "arch_" ".tmp" in
+      let ic = Bzip2.open_in filename
+      in
+      let oc = open_out_bin file_out in
+	let rec decompress () =
+	  let n = Bzip2.input ic buffer 0 (String.length buffer) in
+            if n = 0 then ()
+	    else
+	      begin
+		output oc buffer 0 n;
+		decompress()
+	      end
+	    in decompress();
+            Bzip2.close_in ic;
+	    close_out oc;
+	    file_out
+    with e -> ""
+  end
+
+let gz_extract filename =
+  begin
+    try
+      let buffer = String.create 4096 in
+      let file_out = Filename.temp_file "arch_" ".tmp" in
+      let ic = Gzip.open_in filename
+      in
+      let oc = open_out_bin file_out in
+	let rec decompress () =
+	  let n = Gzip.input ic buffer 0 (String.length buffer) in
+            if n = 0 then ()
+	    else
+	      begin
+		output oc buffer 0 n;
+		decompress()
+	      end
+	    in decompress();
+            Gzip.close_in ic;
+	    close_out oc;
+	    file_out
+    with e -> ""
+  end
+
+let archive_extract filename archive_type =
+  match archive_type with
+    "zip" -> zip_extract filename; ""
+  | "bz2" -> bz2_extract filename
+  | "gz" -> gz_extract filename
+  | _ -> ""
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/net/http_client.ml ./src/utils/net/http_client.ml
--- ./src/utils/net/http_client.ml	2005-07-14 16:02:28.000000000 +0200
+++ ./src/utils/net/http_client.ml	2005-07-18 18:28:30.000000000 +0200
@@ -383,7 +383,8 @@
           lprintf "Empty content for url %s\n" 
             (Url.to_string r.req_url);
         end;
-      let filename = Filename.temp_file "http_" ".tmp" in
+      let ext = (String.lowercase (Filename2.extension r.req_url.Url.short_file)) in
+      let filename = Filename.temp_file "http_" (if ext = "" then ".tmp" else ext) in
       let oc = open_out_bin filename in
       output_string oc s;
       close_out oc;
diff -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/utils/net/ip_set.ml ./src/utils/net/ip_set.ml
--- ./src/utils/net/ip_set.ml	2005-07-07 02:25:46.000000000 +0200
+++ ./src/utils/net/ip_set.ml	2005-07-18 20:32:57.000000000 +0200
@@ -73,7 +73,8 @@
     | None -> ());
   m
 
-let load_merge bl filename =
+let load_merge bl filename remove =
+  lprintf_nl "load_merge %s" filename;
   let guardian_regexp = Str.regexp "^\\(.*\\): *\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\)-\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\)" in
   let ipfilter_regexp = Str.regexp "^\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\) *- *\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\) *, *[0-9]+ *, *\\(.*\\)$" in
 
@@ -109,11 +110,47 @@
     bl_empty (* not reached *)
   with End_of_file ->
     close_in cin;
+    if remove then (try Sys.remove filename with _ -> ());
     lprintf "IP blacklist: %d ranges loaded\n" !nranges;
     !bl
 
 let load filename =
-  load_merge bl_empty filename
+  lprintf_nl "ipset.load %s" filename;
+  if Sys.file_exists filename then
+    let ext = String.lowercase (Filename2.extension filename) in
+      match ext with
+        ".zip" | ".p2p.zip" ->
+	    begin
+	      try
+		let file = Zip.find_entry (Zip.open_in filename) "guarding.p2p" in
+		  lprintf_nl "ipset.load guarding.p2p found in zip file";
+		  let s = Misc.archive_extract filename "zip" in
+		  load_merge bl_empty file.Zip.filename true
+		with e ->
+		  lprintf_nl "Exception %s while extracting guarding.p2p from %s"
+		    (Printexc2.to_string e) filename;
+		    bl_empty
+	    end
+      | ".bz2" | ".p2p.bz2" | ".gz" | ".p2p.gz" ->
+	    begin
+	      let filetype =
+	        if ext = ".bz2" || ext = ".p2p.bz2" then "bz2" else "gz" in
+	      try
+                let s = Misc.archive_extract filename filetype in
+                  load_merge bl_empty s true
+		with e ->
+		  lprintf_nl "Exception %s while extracting guarding.p2p from %s"
+		    (Printexc2.to_string e) filename;
+		    bl_empty
+	    end
+      | ".tar.bz2" | ".p2p.tar.bz2" | ".tar.gz" | ".p2p.tar.gz" ->
+	    lprintf_nl "ipset.load: %s found" filename; bl_empty
+      | _ -> load_merge bl_empty filename false
+  else
+    begin
+      lprintf_nl "ipset.load: file %s not found" filename;
+      bl_empty
+    end
 
 let of_list l =
   let rec of_list_aux l bl =
