let file_info ?(follow_symlink=false) path =
    let stat_fun =
      if follow_symlink then Lwt_unix.stat else Lwt_unix.lstat in
    (* eprintf "(l)stat %s? \n%!" path; *)
    Lwt.catch
      Lwt.(fun () -> stat_fun path >>= fun s -> return (`Ok (`Unix_stats s)))
      begin function
      | Unix.Unix_error (Unix.ENOENT, cmd, arg)  -> return `Absent
      | e -> fail_sys (`File_info path, `Exn e)
      end
    >>= fun m ->
    let open Lwt_unix in
    begin match m with
    | `Absent -> return `Absent
    | `Unix_stats stats ->
      begin match stats.st_kind with
      | S_DIR -> return (`Directory)
      | S_REG -> return (`Regular_file (stats.st_size))
      | S_LNK ->
        (* eprintf "readlink %s? \n%!" path; *)
        begin
          catch_deferred (fun () -> lwt_unix_readlink path)
          >>< begin function
          | `Ok s -> return s
          | `Error e -> fail (`System (`File_info path, `Exn e))
          end
        end
        >>= fun destination ->
        (* eprintf "readlink %s worked \n%!" path; *)
        return (`Symlink destination)
      | S_CHR -> return (`Character_device)
      | S_BLK -> return (`Block_device)
      | S_FIFO -> return (`Fifo)
      | S_SOCK -> return (`Socket)
      end
    end