let copy       ?(ignore_strange=false) ?(symlinks=`Fail) ?(buffer_size=64_000)       ?(if_exists=`Fail)       ~src dst =     let rec copy_aux ~src ~dst =       file_info src       >>= begin function       | `Absent -> fail (`File_not_found src)       | `Block_device       | `Character_device       | `Fifo       | `Socket as k ->         if ignore_strange then return () else fail (`Wrong_file_kind (src, k))       | `Symlink content ->         begin match symlinks with         | `Fail -> fail (`Wrong_file_kind (src, `Symlink content))         | `Follow -> copy_aux ~src:content ~dst         | `Redo ->           let link_path = path_of_destination ~src ~dst in           begin match if_exists with           | `Fail -> (* make_symlink already fails on existing files *)             return ()           | `Overwrite           | `Update -> remove link_path (* remove does not fail on missing files *)           end           >>= fun () ->           make_symlink ~target:content ~link_path         end       | `Regular_file _->         let output_path = path_of_destination ~src ~dst in         let open_spec =           match if_exists with           | `Fail -> `Create_file output_path           | `Overwrite | `Update -> `Overwrite_file output_path         in         IO.with_out_channel ~buffer_size open_spec ~f:(fun outchan ->             IO.with_in_channel ~buffer_size (`File src) ~f:(fun inchan ->                 let rec loop () =                   IO.read ~count:buffer_size inchan                   >>= begin function                   | "" -> return ()                   | buf ->                     IO.write outchan buf >>= fun () ->                     loop ()                   end                 in                 loop ()))       | `Directory ->         let new_dir = path_of_destination ~src ~dst in         file_info new_dir         >>= begin function         | `Absent ->           make_new_directory new_dir         | smth_else ->           begin match if_exists with           | `Fail -> fail (`File_exists new_dir)           | `Overwrite ->             remove new_dir             >>= fun () ->             make_new_directory new_dir           | `Update ->             if smth_else = `Directory             then return ()             else fail (`Not_a_directory new_dir)           end         end         >>= fun () ->         let `Stream next_dir = list_directory src in         let rec loop () =           next_dir ()           >>= begin function           | Some ".."           | Some "." -> loop ()           | Some name ->             copy_aux               ~src:(Filename.concat src name)               ~dst:(`Into new_dir)             >>= fun () ->             loop ()           | None -> return ()           end         in         loop ()       end     in     (copy_aux ~src ~dst      >>< begin function      | `Ok () -> return ()      | `Error err ->        begin match err with        | `IO (`Exn e) -> fail (`System (`Copy src, `Exn e))        | `IO (`File_exists _)        | `IO (`Wrong_path _)        | `File_exists _        | `File_not_found _        | `Not_a_directory _        | `Wrong_file_kind _ as e -> fail (`System (`Copy src, e))        | `System e -> fail (`System e)        end      end)