   end
 
   @doc """
-  Copies the contents of `source` to `destination`. Both
-  parameters can be a filename or an io device opened with `File.open`.
-  `bytes_count` specifies the number of bytes to count, the default
-  being `:infinity`.
+  Copies the contents of `source` to `destination`.
+
+  Both parameters can be a filename or an io device opened
+  with `File.open/2`. `bytes_count` specifies the number of
+  bytes to copy, the default being `:infinity`.
 
   If file `destination` already exists, it is overriden
   by the contents in `source`.

  end

  @doc """
  Copies the contents in `source` to `destination`.
  Similar to the command `cp -r` in Unix systems,
  this function behaves differently depending
  if `source` and `destination` are a file or a directory.

  If both are files, it simply copies `source` to
  `destination`. However, if `destination` is a directory,
  it copies the contents of `source` to `destination/source`
  recursively.

  If a file already exists in the destination,
  it invokes a callback which should return
  true if the existing file should be overriden,
  false otherwise. It defaults to return true.

  It returns `:ok` in case of success, returns
  `{ :error, reason }` otherwise.
  """
  def cp(source, destination, callback // fn(_, _) -> true end) do
    if dir?(source) do
      { :error, :eisdir }
    else
      output =
        if dir?(destination) do
          mkdir(destination)
          FN.join(destination, FN.basename(source))
        else
          destination
        end

      case do_cp_file(source, output, callback, []) do
        { :error, reason, _ } -> { :error, reason }
        _ -> :ok
      end
    end
  end


defmodule File do
  @moduledoc """
  This module contains function to manipulate files.

  Some of those functions are low-level, allowing the user
  to interact with the file or IO devices, like `File.open/2`,
  `File.copy/3` and others. This module also provides higher
  level functions, with their naming based on its UNIX variants.
  For example, one can copy a file via `File.cp/3` and remove
  files and directories recursively via `File.rm_rf/2`

  In order to write and read files, one must use the functions
  in the IO module. By default, a file is opened in binary mode
  which requires the functions `IO.binread`, `IO.binwrite` and
  `IO.binreadline` to interact with the file. A developer may
  pass `:utf8` as an option when opening the file and then all
  other functions from IO are available, since they work directly
  with Unicode data.

  Most of the functions in this module return `:ok` or
  `{ :ok, result }` in case of success, `{ :error, reason }`
  otherwise. Those function are also followed by a variant
  that ends with `!` which returns the result (without the
  `{ :ok, result }` tuple) in case of success or raises an
  exception in case it fails. For example:

      File.read("hello.txt")
      #=> { :ok, "World" }
