let ialloc kind =
    let start = !last_free_inode + 1 in
    let rec find current =
      let current = ((current -1) mod inode_nb) + 1 in
      let inode = iget current in
      if inode.stats.st_nlink = 0 then
        begin
          last_free_inode := current;
          inode.stats.st_nlink <- 1;
          inode.stats.st_kind <- kind;
          inode
        end
      else
        begin
          iput inode;
          let next = current + 1 in
          if next = start then
            system_error ENOSPC "alloc_block" "No space left"
          else find next
        end in
    find start

  let ifree inode =
    inode.stats.st_nlink <- 0

  let iput inode =
    Printf.printf "iput %d: nlink=%d refcount = %d\n"
      inode.stats.st_ino inode.stats.st_nlink inode.reference_number;
    if inode.reference_number = 1 && inode.stats.st_nlink = 0 then
      begin
        (* last reference and no more links, inode must be deallocated *)
        itrunc inode 0;
        inode.stats.st_kind <- S_REG;
        ifree inode;
      end;
    iput inode (* execute previous definition of iput *)
      
let dirent_size = 16
let filename_max_size = 12

    (* Retuourne la prochaine entrée valide par rapport à la position
       courante sous la form (name, ino).  Le noeud n'est pas alloué. *)
let internal_readdir descr =
  let entry = String.create dirent_size in
  let rec find_next () =
    let n = read descr entry 0 dirent_size in
    if n = 0 then
      raise End_of_file
    else if entry.[0] = '\000' then
      find_next ()
    else
      let ino = Misc.read_int entry filename_max_size in
      entry.[filename_max_size] <- '\000';
      let name_len = String.index entry '\000' in
      let name = String.sub entry 0 name_len in
      nameino in
  find_next ()

type dir_handle = file_descr

let open_inode inode lock =
  (* retourne un descripteur sur inode, augment le nombre de verrous *)
   if lock then inode.reference_number <- inode.reference_number + 1;
   { inode = inodepos = 0; closed = false }

let readdir handle = fst (internal_readdir handle)
let closedir = close

let equal_dirent name entry =
  let len_name = String.length name in
  assert (len_name <= filename_max_size);
  (len_name = filename_max_size || entry.[len_name] = '\000') &&
  String.sub entry 0 len_name = name

let find_name_in_dir_inode dir_inode name =
  let descr = open_inode dir_inode true in
  let rec lookup () =
    let entry_nameinode_nb = internal_readdir descr in
    if entry_name = name then
      iget inode_nb
    else
      lookup () in
  try_finalize lookup () close descr

let rec split_name name =
  try
    let pos = String.index_from name 0 '/' in
    let left = String.sub name 0 pos in
    let right = String.sub name (pos + 1) (String.length name - pos - 1) in
    leftright
  with Not_found -> name""

let rec relative_namei inode name =
  if String.length name == 0 || name = "/" then inode
  else
    let left_partright_part = split_name name in
    let new_inode =
      try find_name_in_dir_inode inode left_part
      with End_of_file -> raise Not_found in
    iput inode;
    relative_namei new_inode right_part

let rec namei name =
  if name.[0] != '/' then
    raise (Invalid_argument (name^" must be absolute"));
  let iroot = iget root_inode in
  if name = "/"  then iroot
  else relative_namei iroot (String.sub name 1 (String.length name - 1))
  (* iroot is either returned or released by relative_namei *)

let opendir dirname =
  let dir_inode = namei dirname in
  if dir_inode.stats.st_kind != S_DIR then
    system_error ENOTDIR "opendir" dirname;
  open_inode dir_inode false

      
let unlink filename =
  let dirname = Filename.dirname filename in
  let basename = Filename.basename filename in
  let dir_inode = namei dirname in
  let descr = open_inode dir_inode false in
  let _ = lseek descr (2 * dirent_sizeSEEK_SET in
  let entry = String.create dirent_size in
  let rec find_name () =
    if descr.pos < descr.inode.stats.st_size then
      let _ = read descr entry 0 dirent_size in
      if equal_dirent basename entry  then
        let inode = iget (Misc.read_int entry filename_max_sizein
        begin match inode.stats.st_kind with
        | S_DIR ->
            iput inode;
            system_error EISDIR "unlink" basename
       | S_REG -> ()
        end;
        let _ = lseek descr (0 - dirent_sizeSEEK_CUR in
        String.fill entry 0 dirent_size '\000';
       ignore (write descr entry 0 dirent_size);
        iput inode
      else find_name()
    else system_error ENOENT "remove_dirent" basename in
  try_finalize find_name () close descr