Definition os_after_external (ov: option val) (s: xT): option xT :=
  match after_external csem ov (get_core s) with
  | Some c => Some (mkxT (get_ext s) c (get_fs s))
  | None => None
  end.Definition os_halted (s: xT): option val :=
  halted csem (get_core s).Program Definition FSCoreSem := Build_CoreSemantics genv xT mem
  os_initial_core
  os_at_external
  os_after_external
  os_halted
  os_step
  _ _ _ _.Program Definition FSCoopSem :=
  Build_CoopCoreSem _ _ FSCoreSem _.(*
Next Obligation.
inv CS.
destruct csem.
eapply corestep_wdmem; eauto.
auto.
eapply mem_lemmas.mem_wd_storebytes; eauto.
intros v IN.
clear - H5 IN.
induction bytes.
simpl in IN; inv IN.
simpl in IN.
destruct IN. subst. inv H5.
destruct v; simpl in H1; try inv H1.
solve[apply memval_inject_byte].
apply IHbytes; auto.
solve[inv H5; auto].
Qed.
*)

Definition file_exists (fsys: fs) (fname: int) := isSome (get_fstore fsys fname).Definition fs_pre (ef: AST.external_function) u (typs: list typ) args (fsz: fs*Z) m :=
  match ef, fsz, args with
  | SYS_OPEN, (fsys, z), fname0::md0::nil =>
    match val2oint fname0, val2omode md0 with
    | Some fname, Some md =>
        List.Forall2 Val.has_type (md0::nil) (sig_args SYS_OPEN_SIG) /\
        get_nfiles_open fsys < nat_of_Z (Int.unsigned (get_max_fds fsys)) /\
        (~file_exists fsys fname=true -> fwritable md=true) /\
        ~is_open fsys fname
    | _, _ => False
    end
  | SYS_READ, (fsys, z), (fd0::buf::nbytes0::nil) =>
    match val2oint fd0, val2oadr buf, val2oint nbytes0 with
    | Some fd, Some adr, Some nbytes =>
        u=adr /\
        List.Forall2 Val.has_type (fd0::buf::nbytes0::nil) (sig_args SYS_READ_SIG) /\
        is_readable fsys fd /\
        Mem.range_perm m (fst adr) (Int.unsigned (snd adr))
                         (Int.unsigned (snd adr) + Int.unsigned nbytes) Cur Writable
    | _, _, _ => False
    end
  | SYS_WRITE, (fsys, z), (fd0::buf::nbytes0::nil) =>
    match val2oint fd0, val2oadr buf, val2oint nbytes0 with
    | Some fd, Some adr, Some nbytes =>
        u=adr /\
        List.Forall2 Val.has_type (fd0::buf::nbytes0::nil) (sig_args SYS_WRITE_SIG) /\
        is_writable fsys fd /\
        Mem.range_perm m (fst adr) (Int.unsigned (snd adr))
                         (Int.unsigned (snd adr) + Int.unsigned nbytes) Cur Readable
     | _, _, _ => False
     end
  | _, _, _ => False
  end.Definition obind {A B: Type} (d: B) (o: option A) (f: A -> B) :=
  match o with Some a => f a | None => d end.(*TODO: to make fs_post more precise, we'll have to add more information
   to the shared parameter x, i.e., the fd and fptr for file read/written*)
Definition fs_post (ef: AST.external_function) (adr: address) (ty: option typ)
                   retval0 (fsz: fs*Z) (m: mem) :=
  match ef, fsz with
  | SYS_OPEN, (fsys, z) => obind False retval0 (fun retval =>
      obind False (val2oint retval) (fun fd => is_readable fsys fd))
  | SYS_READ, (fsys, z) => obind False retval0 (fun retval =>
      obind False (val2oint retval) (fun nbytes =>
        exists bytes,
          nbytes=Int.repr (Zlength bytes) /\
          Mem.loadbytes m (fst adr) (Int.unsigned (snd adr)) (Int.unsigned nbytes) = Some bytes))
  | SYS_WRITE, (fsys, z) => True
  | _, _ => True
  end.Definition Client_FSExtSpec :=
  Build_external_specification Memory.mem AST.external_function (fs*Z)
  (fun ef: AST.external_function => address) fs_pre fs_post.

(* Specifications: *)
Lemma fs_ext_pf3: forall (s : xT) (c : cT) (s' : xT) (c' : cT) (ef : external_function) (sig : signature) (args : list val) (sig' : signature) (args' : list val), get_core s = c -> at_external csem c = Some (ef, sig, args) -> at_external FSCoreSem s = None -> get_core s' = c' -> at_external csem c' = Some (ef, sig', args') -> at_external FSCoreSem s' = None.