(*Definition genv := Genv.t Clight.fundef Ctypes.type.*)
Inductive fmode: Type := RDONLY | WRONLY | RDWR.
Definition fwritable (mode: fmode) :=
match mode with
| RDONLY => false
| WRONLY => true
| RDWR => true
end.
(* model of a simple "flat" filesystem *)
Inductive file: Type := mkfile: forall (size: nat) (contents: forall (ofs: nat), memval), file.
Definition fptr := nat.
(*typedef struct { int cur_dir; // i-node of the current working directory int n_inodes; // allocated i-nodes int n_open_files; uint8_t map_open_files[BITMAP_SIZE(N_INODES)]; uint8_t map_inodes[BITMAP_SIZE(N_INODES)]; uint8_t map_blocks[BITMAP_SIZE(N_BLOCKS)]; uint32_t fd_map[MAX_OPEN_FILES]; // maps FDs to i-nodes uint32_t fptr_map[MAX_OPEN_FILES]; // maps FDs to file pointers file_mode_t fperm_map[MAX_OPEN_FILES]; // maps FDs to file permissions uint8_t block_cache[CACHE_N_BLOCKS][BLOCK_SIZE]; // data block cache uint32_t cache_map[CACHE_N_BLOCKS]; // maps cache block # to data block # // maps cache block # to approximate time since last access uint32_t cache_last_access_map[CACHE_N_BLOCKS]; } fs_data;*)
Inductive fs_data: Type := mkfsdata: forall
(fdtable: forall (fd: int), option (fmode*fptr)) (*None = fd unused*)
(fcache: forall (fd: int), option file) (*models in-memory storage*)
(fnames: forall (fd: int), option int) (*map from file descriptors to file names*),
fs_data.
Inductive fs: Type := mkfs: forall
(MAX_FILE_DESCRIPTORS: int)
(fsdata: fs_data)
(fstore: forall (name: int), option file), (*models on-disk storage*)
fs.
Section selectors.
Variable (fs: fs).
Definition get_max_fds := match fs with mkfs maxfds _ _ => maxfds end.
Definition get_fsdata := match fs with mkfs _ fsdata _ => fsdata end.
Definition get_fstore := match fs with mkfs _ _ fstore => fstore end.
Definition get_fdtable := match get_fsdata with mkfsdata fdtable _ _ => fdtable end.
Definition get_fcache := match get_fsdata with mkfsdata _ fcache _ => fcache end.
Definition get_fnames := match get_fsdata with mkfsdata _ _ fnames => fnames end.
Variable (fd: int).
Definition get_file := get_fcache fd.
Definition get_fmode :=
match get_fdtable fd with
| None => None
| Some (md, cur) => Some md
end.
Definition get_fptr :=
match get_fdtable fd with
| None => None
| Some (md, cur) => Some cur
end.
Variable (f: file).
Definition get_size := match f with mkfile sz _ => sz end.
Definition get_contents := match f with mkfile _ contents => contents end.
Definition isSome {A: Type} (a: option A) :=
match a with
| None => false
| Some _ => true
end.
Fixpoint get_nfiles_open_aux (n: nat) (fcache: int -> option (fmode*fptr)) :=
match n with
| O => O
| S n' => if isSome (fcache (Int.repr (Z_of_nat n)))
then S (get_nfiles_open_aux n' fcache)
else get_nfiles_open_aux n' fcache
end.
Definition get_nfiles_open :=
get_nfiles_open_aux (nat_of_Z (Int.unsigned get_max_fds)) get_fdtable.
End selectors.
(*return the highest unallocated file descriptor, or None if none available*)
Section alloc_fd.
Variable (fs: fs).
Fixpoint find_unused_fd (n: nat) (fdtable: int -> option (fmode*fptr)) :=
match n with
| O => None
| S n' => match fdtable (Int.repr (Z_of_nat n)) with
| None => Some (Int.repr (Z_of_nat n))
| Some _ => find_unused_fd n' fdtable
end
end.
Definition max_fds: nat := nat_of_Z (Int.unsigned (get_max_fds fs)).
Definition alloc_fd := find_unused_fd max_fds (get_fdtable fs).

Lemma alloc_fd_success :
(get_nfiles_open fs < max_fds)%nat -> exists unused_fd, alloc_fd = Some unused_fd.