let fill_buffer_with_dirent buffer name n = let len = String.length name in assert (String.length buffer >= dirent_size); assert (len <= filename_max_size); String.blit name 0 buffer 0 len; if len < filename_max_size then for i = len to filename_max_size - 1 do buffer.[i] <- '\000' done; Misc.write_int n buffer filename_max_size let add_dirent dir_inode name inode_nb = let descr = open_inode dir_inode true in let buffer = String.create dirent_size in let rec find_free_entry pos = if pos < descr.inode.stats.st_size then let _ = lseek descr pos SEEK_SET in let _ = read descr buffer 0 1 in if buffer.[0] <> '\000' then find_free_entry (pos + dirent_size) else pos else descr.inode.stats.st_size in let pos = find_free_entry (2 * dirent_size) in let k = lseek descr pos SEEK_SET in fill_buffer_with_dirent buffer name inode_nb; let _ = write descr buffer 0 dirent_size in close descr let validate_name name = String.length name > 0 && (let rec ok i = i < 0 || name.[i] <> '\000' && ok (i - 1) in ok (String.length name -1)) let mkdir name = let dirname = Filename.dirname name in let dir_inode = try namei dirname with Not_found -> system_error ENOENT "mkdir" dirname in try_finalize begin fun () -> let basename = Filename.basename name in if not (validate_name basename) then system_error EINVAL "mkdir" basename; try let inode = find_name_in_dir_inode dir_inode basename in iput inode; system_error EEXIST "mkdir" name with End_of_file -> let new_inode = ialloc S_DIR in add_dirent new_inode Filename.current_dir_name new_inode.stats.st_ino; new_inode.stats.st_nlink <- 2; (* current_dir_name. *) add_dirent new_inode Filename.parent_dir_name dir_inode.stats.st_ino; add_dirent dir_inode basename new_inode.stats.st_ino; (* above sequence cannot fail *) iput new_inode; (* dir_inode has one more link: parent_dir_name in new_inode *) dir_inode.stats.st_nlink <- dir_inode.stats.st_nlink + 1; end () iput dir_inode |
let openfile name flags = if List.sort compare flags <> [ O_RDWR; O_CREAT] then implementation_error "Manadatory flags are [ O_RDWR; O_CREAT ]"; let dirname = Filename.dirname name in let dir_inode = try namei dirname with Not_found -> system_error EACCESS "openfile" dirname in try_finalize begin function () -> if dir_inode.stats.st_kind != S_DIR then system_error ENOTDIR "openfile" dirname; let filename = Filename.basename name in if not (validate_name filename) then system_error EINVAL "openfile" filename; let inode = try let inode = find_name_in_dir_inode dir_inode filename in let system_error x = iput inode; system_error x in if inode.stats.st_kind != S_REG then system_error EISDIR "openfile" name; if inode.stats.st_size > max_file_size then system_error EIO "Inconsistent file system" name; inode with End_of_file -> let new_inode = ialloc S_REG in add_dirent dir_inode filename new_inode.stats.st_ino; new_inode in open_inode inode false end () iput dir_inode ;; |