let stat (fln: filename) =
  try
    let ustat = 
      Unix.LargeFile.lstat fln
    in
    let stat_of_kind knd = 
      {
        kind              = knd;
        is_link           = false;
        permission        = permission_of_int ustat.Unix.LargeFile.st_perm;
        size              = B ustat.Unix.LargeFile.st_size;
        owner             = ustat.Unix.LargeFile.st_uid;
        group_owner       = ustat.Unix.LargeFile.st_gid;
        access_time       = ustat.Unix.LargeFile.st_atime;
        modification_time = ustat.Unix.LargeFile.st_mtime;
        creation_time     = ustat.Unix.LargeFile.st_ctime;
      }
    in
      match ustat.Unix.LargeFile.st_kind with
        | Unix.S_REG -> 
            stat_of_kind File 
        | Unix.S_DIR -> 
            stat_of_kind Dir 
        | Unix.S_CHR -> 
            stat_of_kind Dev_char 
        | Unix.S_BLK -> 
            stat_of_kind Dev_block
        | Unix.S_FIFO -> 
            stat_of_kind Fifo 
        | Unix.S_SOCK -> 
            stat_of_kind Socket
        | Unix.S_LNK -> 
            (
              let stat_of_kind knd =
                {(stat_of_kind knd) with is_link = true}
              in
                match (Unix.stat fln).Unix.st_kind with
                  | Unix.S_REG -> 
                      stat_of_kind File 
                  | Unix.S_DIR -> 
                      stat_of_kind Dir 
                  | Unix.S_CHR -> 
                      stat_of_kind Dev_char 
                  | Unix.S_BLK -> 
                      stat_of_kind Dev_block
                  | Unix.S_FIFO -> 
                      stat_of_kind Fifo 
                  | Unix.S_SOCK -> 
                      stat_of_kind Socket
                  | Unix.S_LNK -> 
                      failwith 
                        (Printf.sprintf 
                           "Unix.stat of file '%s' return a link"
                           fln)
            )
  with Unix.Unix_error(_) ->
    raise (FileDoesntExist fln)