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 name, ino 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 = inode; pos = 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_name, inode_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 left, right with Not_found -> name, "" let rec relative_namei inode name = if String.length name == 0 || name = "/" then inode else let left_part, right_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_size) SEEK_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_size) in begin match inode.stats.st_kind with | S_DIR -> iput inode; system_error EISDIR "unlink" basename | S_REG -> () end; let _ = lseek descr (0 - dirent_size) SEEK_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 |