src/HOL/Unix/Unix.thy
changeset 18372 2bffdf62fe7f
parent 17455 151e76f0e3c7
child 18447 da548623916a
equal deleted inserted replaced
18371:d93fdf00f8a6 18372:2bffdf62fe7f
   253 lemma access_some_lookup:
   253 lemma access_some_lookup:
   254   "access root path uid perms = Some file \<Longrightarrow>
   254   "access root path uid perms = Some file \<Longrightarrow>
   255     lookup root path = Some file"
   255     lookup root path = Some file"
   256   by (simp add: access_def split: option.splits if_splits)
   256   by (simp add: access_def split: option.splits if_splits)
   257 
   257 
   258 lemma access_update_other: "path' \<parallel> path \<Longrightarrow>
   258 lemma access_update_other:
   259   access (update path' opt root) path uid perms = access root path uid perms"
   259   assumes parallel: "path' \<parallel> path"
       
   260   shows "access (update path' opt root) path uid perms = access root path uid perms"
   260 proof -
   261 proof -
   261   assume "path' \<parallel> path"
   262   from parallel obtain y z xs ys zs where
   262   then obtain y z xs ys zs where
       
   263       "y \<noteq> z" and "path' = xs @ y # ys" and "path = xs @ z # zs"
   263       "y \<noteq> z" and "path' = xs @ y # ys" and "path = xs @ z # zs"
   264     by (blast dest: parallel_decomp)
   264     by (blast dest: parallel_decomp)
   265   hence "lookup (update path' opt root) path = lookup root path"
   265   then have "lookup (update path' opt root) path = lookup root path"
   266     by (blast intro: lookup_update_other)
   266     by (blast intro: lookup_update_other)
   267   thus ?thesis by (simp only: access_def)
   267   then show ?thesis by (simp only: access_def)
   268 qed
   268 qed
   269 
   269 
   270 
   270 
   271 section {* File-system transitions \label{sec:unix-trans} *}
   271 section {* File-system transitions \label{sec:unix-trans} *}
   272 
   272 
   435   simplify our subsequent development to some extent, since we only
   435   simplify our subsequent development to some extent, since we only
   436   have to reason about a partial function rather than a general
   436   have to reason about a partial function rather than a general
   437   relation.
   437   relation.
   438 *}
   438 *}
   439 
   439 
   440 theorem transition_uniq: "root \<midarrow>x\<rightarrow> root' \<Longrightarrow> root \<midarrow>x\<rightarrow> root'' \<Longrightarrow> root' = root''"
   440 theorem transition_uniq:
   441 proof -
   441   assumes root': "root \<midarrow>x\<rightarrow> root'"
   442   assume root: "root \<midarrow>x\<rightarrow> root'"
   442     and root'': "root \<midarrow>x\<rightarrow> root''"
   443   assume "root \<midarrow>x\<rightarrow> root''"
   443   shows "root' = root''"
   444   thus "root' = root''"
   444   using root''
   445   proof cases
   445 proof cases
   446     case read
   446   case read
   447     with root show ?thesis by cases auto
   447   with root' show ?thesis by cases auto
   448   next
   448 next
   449     case write
   449   case write
   450     with root show ?thesis by cases auto
   450   with root' show ?thesis by cases auto
   451   next
   451 next
   452     case chmod
   452   case chmod
   453     with root show ?thesis by cases auto
   453   with root' show ?thesis by cases auto
   454   next
   454 next
   455     case creat
   455   case creat
   456     with root show ?thesis by cases auto
   456   with root' show ?thesis by cases auto
   457   next
   457 next
   458     case unlink
   458   case unlink
   459     with root show ?thesis by cases auto
   459   with root' show ?thesis by cases auto
   460   next
   460 next
   461     case mkdir
   461   case mkdir
   462     with root show ?thesis by cases auto
   462   with root' show ?thesis by cases auto
   463   next
   463 next
   464     case rmdir
   464   case rmdir
   465     with root show ?thesis by cases auto
   465   with root' show ?thesis by cases auto
   466   next
   466 next
   467     case readdir
   467   case readdir
   468     with root show ?thesis by cases fastsimp+
   468   with root' show ?thesis by cases fastsimp+
   469   qed
       
   470 qed
   469 qed
   471 
   470 
   472 text {*
   471 text {*
   473   \medskip Apparently, file-system transitions are \emph{type-safe} in
   472   \medskip Apparently, file-system transitions are \emph{type-safe} in
   474   the sense that the result of transforming an actual directory yields
   473   the sense that the result of transforming an actual directory yields
   475   again a directory.
   474   again a directory.
   476 *}
   475 *}
   477 
   476 
   478 theorem transition_type_safe:
   477 theorem transition_type_safe:
   479   "root \<midarrow>x\<rightarrow> root' \<Longrightarrow> \<exists>att dir. root = Env att dir
   478   assumes tr: "root \<midarrow>x\<rightarrow> root'"
   480     \<Longrightarrow> \<exists>att dir. root' = Env att dir"
   479     and inv: "\<exists>att dir. root = Env att dir"
   481 proof -
   480   shows "\<exists>att dir. root' = Env att dir"
   482   assume tr: "root \<midarrow>x\<rightarrow> root'"
   481 proof (cases "path_of x")
   483   assume inv: "\<exists>att dir. root = Env att dir"
   482   case Nil
   484   show ?thesis
   483   with tr inv show ?thesis
   485   proof (cases "path_of x")
   484     by cases (auto simp add: access_def split: if_splits)
   486     case Nil
   485 next
   487     with tr inv show ?thesis
   486   case Cons
   488       by cases (auto simp add: access_def split: if_splits)
   487   from tr obtain opt where
   489   next
   488       "root' = root \<or> root' = update (path_of x) opt root"
   490     case Cons
   489     by cases auto
   491     from tr obtain opt where
   490   with inv Cons show ?thesis
   492         "root' = root \<or> root' = update (path_of x) opt root"
   491     by (auto simp add: update_eq split: list.splits)
   493       by cases auto
       
   494     with inv Cons show ?thesis
       
   495       by (auto simp add: update_eq split: list.splits)
       
   496   qed
       
   497 qed
   492 qed
   498 
   493 
   499 text {*
   494 text {*
   500   The previous result may be seen as the most basic invariant on the
   495   The previous result may be seen as the most basic invariant on the
   501   file-system state that is enforced by any proper kernel
   496   file-system state that is enforced by any proper kernel
   537 *}
   532 *}
   538 
   533 
   539 lemma transitions_nil_eq: "root =[]\<Rightarrow> root' = (root = root')"
   534 lemma transitions_nil_eq: "root =[]\<Rightarrow> root' = (root = root')"
   540 proof
   535 proof
   541   assume "root =[]\<Rightarrow> root'"
   536   assume "root =[]\<Rightarrow> root'"
   542   thus "root = root'" by cases simp_all
   537   then show "root = root'" by cases simp_all
   543 next
   538 next
   544   assume "root = root'"
   539   assume "root = root'"
   545   thus "root =[]\<Rightarrow> root'" by (simp only: transitions.nil)
   540   then show "root =[]\<Rightarrow> root'" by (simp only: transitions.nil)
   546 qed
   541 qed
   547 
   542 
   548 lemma transitions_cons_eq:
   543 lemma transitions_cons_eq:
   549   "root =(x # xs)\<Rightarrow> root'' = (\<exists>root'. root \<midarrow>x\<rightarrow> root' \<and> root' =xs\<Rightarrow> root'')"
   544   "root =(x # xs)\<Rightarrow> root'' = (\<exists>root'. root \<midarrow>x\<rightarrow> root' \<and> root' =xs\<Rightarrow> root'')"
   550 proof
   545 proof
   551   assume "root =(x # xs)\<Rightarrow> root''"
   546   assume "root =(x # xs)\<Rightarrow> root''"
   552   thus "\<exists>root'. root \<midarrow>x\<rightarrow> root' \<and> root' =xs\<Rightarrow> root''"
   547   then show "\<exists>root'. root \<midarrow>x\<rightarrow> root' \<and> root' =xs\<Rightarrow> root''"
   553     by cases auto
   548     by cases auto
   554 next
   549 next
   555   assume "\<exists>root'. root \<midarrow>x\<rightarrow> root' \<and> root' =xs\<Rightarrow> root''"
   550   assume "\<exists>root'. root \<midarrow>x\<rightarrow> root' \<and> root' =xs\<Rightarrow> root''"
   556   thus "root =(x # xs)\<Rightarrow> root''"
   551   then show "root =(x # xs)\<Rightarrow> root''"
   557     by (blast intro: transitions.cons)
   552     by (blast intro: transitions.cons)
   558 qed
   553 qed
   559 
   554 
   560 text {*
   555 text {*
   561   The next two rules show how to ``destruct'' known transition
   556   The next two rules show how to ``destruct'' known transition
   566 
   561 
   567 lemma transitions_nilD: "root =[]\<Rightarrow> root' \<Longrightarrow> root' = root"
   562 lemma transitions_nilD: "root =[]\<Rightarrow> root' \<Longrightarrow> root' = root"
   568   by (simp add: transitions_nil_eq)
   563   by (simp add: transitions_nil_eq)
   569 
   564 
   570 lemma transitions_consD:
   565 lemma transitions_consD:
   571   "root =(x # xs)\<Rightarrow> root'' \<Longrightarrow> root \<midarrow>x\<rightarrow> root' \<Longrightarrow> root' =xs\<Rightarrow> root''"
   566   assumes list: "root =(x # xs)\<Rightarrow> root''"
       
   567     and hd: "root \<midarrow>x\<rightarrow> root'"
       
   568   shows "root' =xs\<Rightarrow> root''"
   572 proof -
   569 proof -
   573   assume "root =(x # xs)\<Rightarrow> root''"
   570   from list obtain r' where r': "root \<midarrow>x\<rightarrow> r'" and root'': "r' =xs\<Rightarrow> root''"
   574   then obtain r' where r': "root \<midarrow>x\<rightarrow> r'" and root'': "r' =xs\<Rightarrow> root''"
       
   575     by cases simp_all
   571     by cases simp_all
   576   assume "root \<midarrow>x\<rightarrow> root'"
   572   from r' hd have "r' = root'" by (rule transition_uniq)
   577   with r' have "r' = root'" by (rule transition_uniq)
       
   578   with root'' show "root' =xs\<Rightarrow> root''" by simp
   573   with root'' show "root' =xs\<Rightarrow> root''" by simp
   579 qed
   574 qed
   580 
   575 
   581 text {*
   576 text {*
   582   \medskip The following fact shows how an invariant @{term Q} of
   577   \medskip The following fact shows how an invariant @{term Q} of
   584   iterated transitions.  The proof is rather obvious by rule induction
   579   iterated transitions.  The proof is rather obvious by rule induction
   585   over the definition of @{term "root =xs\<Rightarrow> root'"}.
   580   over the definition of @{term "root =xs\<Rightarrow> root'"}.
   586 *}
   581 *}
   587 
   582 
   588 lemma transitions_invariant:
   583 lemma transitions_invariant:
   589   "(\<And>r x r'. r \<midarrow>x\<rightarrow> r' \<Longrightarrow> Q r \<Longrightarrow>  P x \<Longrightarrow> Q r') \<Longrightarrow>
   584   assumes r: "\<And>r x r'. r \<midarrow>x\<rightarrow> r' \<Longrightarrow> Q r \<Longrightarrow>  P x \<Longrightarrow> Q r'"
   590     root =xs\<Rightarrow> root' \<Longrightarrow> Q root \<Longrightarrow> \<forall>x \<in> set xs. P x \<Longrightarrow> Q root'"
   585     and trans: "root =xs\<Rightarrow> root'"
   591 proof -
   586   shows "Q root \<Longrightarrow> \<forall>x \<in> set xs. P x \<Longrightarrow> Q root'"
   592   assume r: "\<And>r x r'. r \<midarrow>x\<rightarrow> r' \<Longrightarrow> Q r \<Longrightarrow>  P x \<Longrightarrow> Q r'"
   587   using trans
   593   assume "root =xs\<Rightarrow> root'"
   588 proof induct
   594   thus "Q root \<Longrightarrow> (\<forall>x \<in> set xs. P x) \<Longrightarrow> Q root'" (is "PROP ?P root xs root'")
   589   case nil
   595   proof (induct root xs root')
   590   show ?case by assumption
   596     fix root assume "Q root"
   591 next
   597     thus "Q root" .
   592   case (cons root root' root'' x xs)
   598   next
   593   note P = `\<forall>x \<in> set (x # xs). P x`
   599     fix root root' root'' and x xs
   594   then have "P x" by simp
   600     assume root': "root \<midarrow>x\<rightarrow> root'"
   595   with `root \<midarrow>x\<rightarrow> root'` and `Q root` have Q': "Q root'" by (rule r)
   601     assume hyp: "PROP ?P root' xs root''"
   596   from P have "\<forall>x \<in> set xs. P x" by simp
   602     assume Q: "Q root"
   597   with Q' show "Q root''" by (rule cons.hyps)
   603     assume P: "\<forall>x \<in> set (x # xs). P x"
       
   604     hence "P x" by simp
       
   605     with root' Q have Q': "Q root'" by (rule r)
       
   606     from P have "\<forall>x \<in> set xs. P x" by simp
       
   607     with Q' show "Q root''" by (rule hyp)
       
   608   qed
       
   609 qed
   598 qed
   610 
   599 
   611 text {*
   600 text {*
   612   As an example of applying the previous result, we transfer the basic
   601   As an example of applying the previous result, we transfer the basic
   613   type-safety property (see \secref{sec:unix-single-trans}) from
   602   type-safety property (see \secref{sec:unix-single-trans}) from
   673 text {*
   662 text {*
   674   \medskip In case that we already know that a certain sequence can be
   663   \medskip In case that we already know that a certain sequence can be
   675   executed we may destruct it backwardly into individual transitions.
   664   executed we may destruct it backwardly into individual transitions.
   676 *}
   665 *}
   677 
   666 
   678 lemma can_exec_snocD: "\<And>root. can_exec root (xs @ [y])
   667 lemma can_exec_snocD: "can_exec root (xs @ [y])
   679     \<Longrightarrow> \<exists>root' root''. root =xs\<Rightarrow> root' \<and> root' \<midarrow>y\<rightarrow> root''"
   668     \<Longrightarrow> \<exists>root' root''. root =xs\<Rightarrow> root' \<and> root' \<midarrow>y\<rightarrow> root''"
   680   (is "PROP ?P xs" is "\<And>root. ?A root xs \<Longrightarrow> ?C root xs")
   669 proof (induct xs fixing: root)
   681 proof (induct xs)
   670   case Nil
   682   fix root
   671   then show ?case
   683   {
   672     by (simp add: can_exec_def transitions_nil_eq transitions_cons_eq)
   684     assume "?A root []"
   673 next
   685     thus "?C root []"
   674   case (Cons x xs)
   686       by (simp add: can_exec_def transitions_nil_eq transitions_cons_eq)
   675   from `can_exec root ((x # xs) @ [y])` obtain r root'' where
   687   next
   676       x: "root \<midarrow>x\<rightarrow> r" and
   688     fix x xs
   677       xs_y: "r =(xs @ [y])\<Rightarrow> root''"
   689     assume hyp: "PROP ?P xs"
   678     by (auto simp add: can_exec_def transitions_nil_eq transitions_cons_eq)
   690     assume asm: "?A root (x # xs)"
   679   from xs_y Cons.hyps obtain root' r' where xs: "r =xs\<Rightarrow> root'" and y: "root' \<midarrow>y\<rightarrow> r'"
   691     show "?C root (x # xs)"
   680     by (unfold can_exec_def) blast
   692     proof -
   681   from x xs have "root =(x # xs)\<Rightarrow> root'"
   693       from asm obtain r root'' where x: "root \<midarrow>x\<rightarrow> r" and
   682     by (rule transitions.cons)
   694           xs_y: "r =(xs @ [y])\<Rightarrow> root''"
   683   with y show ?case by blast
   695         by (auto simp add: can_exec_def transitions_nil_eq transitions_cons_eq)
       
   696       from xs_y hyp obtain root' r' where xs: "r =xs\<Rightarrow> root'" and y: "root' \<midarrow>y\<rightarrow> r'"
       
   697         by (unfold can_exec_def) blast
       
   698       from x xs have "root =(x # xs)\<Rightarrow> root'"
       
   699         by (rule transitions.cons)
       
   700       with y show ?thesis by blast
       
   701     qed
       
   702   }
       
   703 qed
   684 qed
   704 
   685 
   705 
   686 
   706 subsection {* Example executions \label{sec:unix-examples} *}
   687 subsection {* Example executions \label{sec:unix-examples} *}
   707 
   688 
   801   The following theorem expresses the general procedure we are
   782   The following theorem expresses the general procedure we are
   802   following to achieve the main result.
   783   following to achieve the main result.
   803 *}
   784 *}
   804 
   785 
   805 theorem general_procedure:
   786 theorem general_procedure:
   806   "(\<And>r r'. Q r \<Longrightarrow> r \<midarrow>y\<rightarrow> r' \<Longrightarrow> False) \<Longrightarrow>
   787   assumes cannot_y: "\<And>r r'. Q r \<Longrightarrow> r \<midarrow>y\<rightarrow> r' \<Longrightarrow> False"
   807     (\<And>root. init users =bs\<Rightarrow> root \<Longrightarrow> Q root) \<Longrightarrow>
   788     and init_inv: "\<And>root. init users =bs\<Rightarrow> root \<Longrightarrow> Q root"
   808     (\<And>r x r'. r \<midarrow>x\<rightarrow> r' \<Longrightarrow> Q r \<Longrightarrow>  P x \<Longrightarrow> Q r') \<Longrightarrow>
   789     and preserve_inv: "\<And>r x r'. r \<midarrow>x\<rightarrow> r' \<Longrightarrow> Q r \<Longrightarrow> P x \<Longrightarrow> Q r'"
   809     init users =bs\<Rightarrow> root \<Longrightarrow>
   790     and init_result: "init users =bs\<Rightarrow> root"
   810       \<not> (\<exists>xs. (\<forall>x \<in> set xs. P x) \<and> can_exec root (xs @ [y]))"
   791   shows "\<not> (\<exists>xs. (\<forall>x \<in> set xs. P x) \<and> can_exec root (xs @ [y]))"
   811 proof -
   792 proof -
   812   assume cannot_y: "\<And>r r'. Q r \<Longrightarrow> r \<midarrow>y\<rightarrow> r' \<Longrightarrow> False"
       
   813   assume init_inv: "\<And>root. init users =bs\<Rightarrow> root \<Longrightarrow> Q root"
       
   814   assume preserve_inv: "\<And>r x r'. r \<midarrow>x\<rightarrow> r' \<Longrightarrow> Q r \<Longrightarrow> P x \<Longrightarrow> Q r'"
       
   815   assume init_result: "init users =bs\<Rightarrow> root"
       
   816   {
   793   {
   817     fix xs
   794     fix xs
   818     assume Ps: "\<forall>x \<in> set xs. P x"
   795     assume Ps: "\<forall>x \<in> set xs. P x"
   819     assume can_exec: "can_exec root (xs @ [y])"
   796     assume can_exec: "can_exec root (xs @ [y])"
   820     then obtain root' root'' where
   797     then obtain root' root'' where
   823     from init_result have "Q root" by (rule init_inv)
   800     from init_result have "Q root" by (rule init_inv)
   824     from preserve_inv xs this Ps have "Q root'"
   801     from preserve_inv xs this Ps have "Q root'"
   825       by (rule transitions_invariant)
   802       by (rule transitions_invariant)
   826     from this y have False by (rule cannot_y)
   803     from this y have False by (rule cannot_y)
   827   }
   804   }
   828   thus ?thesis by blast
   805   then show ?thesis by blast
   829 qed
   806 qed
   830 
   807 
   831 text {*
   808 text {*
   832   Here @{prop "P x"} refers to the restriction on file-system
   809   Here @{prop "P x"} refers to the restriction on file-system
   833   operations that are admitted after having reached the critical
   810   operations that are admitted after having reached the critical
   928 
   905 
   929   \medskip The first two lemmas are technically straight forward ---
   906   \medskip The first two lemmas are technically straight forward ---
   930   we just have to inspect rather special cases.
   907   we just have to inspect rather special cases.
   931 *}
   908 *}
   932 
   909 
   933 lemma (in invariant)
   910 lemma (in invariant) cannot_rmdir:
   934   cannot_rmdir: "invariant root bogus_path \<Longrightarrow>
   911   assumes inv: "invariant root bogus_path"
   935     root \<midarrow>(Rmdir user\<^isub>1 [user\<^isub>1, name\<^isub>1])\<rightarrow> root' \<Longrightarrow> False"
   912     and rmdir: "root \<midarrow>(Rmdir user\<^isub>1 [user\<^isub>1, name\<^isub>1])\<rightarrow> root'"
       
   913   shows False
   936 proof -
   914 proof -
   937   assume "invariant root bogus_path"
   915   from inv obtain "file" where "access root bogus_path user\<^isub>1 {} = Some file"
   938   then obtain "file" where "access root bogus_path user\<^isub>1 {} = Some file"
       
   939     by (unfold invariant_def) blast
   916     by (unfold invariant_def) blast
   940   moreover
   917   moreover
   941   assume "root \<midarrow>(Rmdir user\<^isub>1 [user\<^isub>1, name\<^isub>1])\<rightarrow> root'"
   918   from rmdir obtain att where
   942   then obtain att where
       
   943       "access root [user\<^isub>1, name\<^isub>1] user\<^isub>1 {} = Some (Env att empty)"
   919       "access root [user\<^isub>1, name\<^isub>1] user\<^isub>1 {} = Some (Env att empty)"
   944     by cases auto
   920     by cases auto
   945   hence "access root ([user\<^isub>1, name\<^isub>1] @ [name\<^isub>2]) user\<^isub>1 {} = empty name\<^isub>2"
   921   then have "access root ([user\<^isub>1, name\<^isub>1] @ [name\<^isub>2]) user\<^isub>1 {} = empty name\<^isub>2"
   946     by (simp only: access_empty_lookup lookup_append_some) simp
   922     by (simp only: access_empty_lookup lookup_append_some) simp
   947   ultimately show False by (simp add: bogus_path_def)
   923   ultimately show False by (simp add: bogus_path_def)
   948 qed
   924 qed
   949 
   925 
   950 lemma (in invariant)
   926 lemma (in invariant)
   951   init_invariant: "init users =bogus\<Rightarrow> root \<Longrightarrow> invariant root bogus_path"
   927   assumes init: "init users =bogus\<Rightarrow> root"
   952 proof -
   928   notes eval = facts access_def init_def
   953   note eval = facts access_def init_def
   929   shows init_invariant: "invariant root bogus_path"
   954   case rule_context thus ?thesis
   930   using init
   955     apply (unfold bogus_def bogus_path_def)
   931   apply (unfold bogus_def bogus_path_def)
   956     apply (drule transitions_consD, rule transition.intros,
   932   apply (drule transitions_consD, rule transition.intros,
   957       (force simp add: eval)+, (simp add: eval)?)+
   933       (force simp add: eval)+, (simp add: eval)?)+
   958       -- "evaluate all operations"
   934     -- "evaluate all operations"
   959     apply (drule transitions_nilD)
   935   apply (drule transitions_nilD)
   960       -- "reach final result"
   936     -- "reach final result"
   961     apply (simp add: invariant_def eval)
   937   apply (simp add: invariant_def eval)
   962       -- "check the invariant"
   938     -- "check the invariant"
   963     done
   939   done
   964 qed
       
   965 
   940 
   966 text {*
   941 text {*
   967   \medskip At last we are left with the main effort to show that the
   942   \medskip At last we are left with the main effort to show that the
   968   ``bogosity'' invariant is preserved by any file-system operation
   943   ``bogosity'' invariant is preserved by any file-system operation
   969   performed by @{term user\<^isub>1} alone.  Note that this holds for
   944   performed by @{term user\<^isub>1} alone.  Note that this holds for
   970   any @{term path} given, the particular @{term bogus_path} is not
   945   any @{term path} given, the particular @{term bogus_path} is not
   971   required here.
   946   required here.
   972 *}
   947 *}
   973 
   948 
   974 lemma (in invariant)
   949 lemma (in invariant) preserve_invariant:
   975   preserve_invariant: "root \<midarrow>x\<rightarrow> root' \<Longrightarrow>
   950   assumes tr: "root \<midarrow>x\<rightarrow> root'"
   976     invariant root path \<Longrightarrow> uid_of x = user\<^isub>1 \<Longrightarrow> invariant root' path"
   951     and inv: "invariant root path"
       
   952     and uid: "uid_of x = user\<^isub>1"
       
   953   shows "invariant root' path"
   977 proof -
   954 proof -
   978   assume tr: "root \<midarrow>x\<rightarrow> root'"
       
   979   assume inv: "invariant root path"
       
   980   assume uid: "uid_of x = user\<^isub>1"
       
   981 
       
   982   from inv obtain att dir where
   955   from inv obtain att dir where
   983       inv1: "access root path user\<^isub>1 {} = Some (Env att dir)" and
   956       inv1: "access root path user\<^isub>1 {} = Some (Env att dir)" and
   984       inv2: "dir \<noteq> empty" and
   957       inv2: "dir \<noteq> empty" and
   985       inv3: "user\<^isub>1 \<noteq> owner att" and
   958       inv3: "user\<^isub>1 \<noteq> owner att" and
   986       inv4: "access root path user\<^isub>1 {Writable} = None"
   959       inv4: "access root path user\<^isub>1 {Writable} = None"
  1017       proof (cases ys)
   990       proof (cases ys)
  1018         assume "ys = []"
   991         assume "ys = []"
  1019         with tr uid inv2 inv3 lookup changed path and user\<^isub>1_not_root
   992         with tr uid inv2 inv3 lookup changed path and user\<^isub>1_not_root
  1020         have False
   993         have False
  1021           by cases (auto simp add: access_empty_lookup dest: access_some_lookup)
   994           by cases (auto simp add: access_empty_lookup dest: access_some_lookup)
  1022         thus ?thesis ..
   995         then show ?thesis ..
  1023       next
   996       next
  1024         fix z zs assume ys: "ys = z # zs"
   997         fix z zs assume ys: "ys = z # zs"
  1025         have "lookup root' path = lookup root path"
   998         have "lookup root' path = lookup root path"
  1026         proof -
   999         proof -
  1027           from inv2 lookup path ys
  1000           from inv2 lookup path ys
  1083                 by (cases ys rule: rev_cases) fastsimp+
  1056                 by (cases ys rule: rev_cases) fastsimp+
  1084               with tr path
  1057               with tr path
  1085               have "lookup root ((path @ [y]) @ (us @ [u])) \<noteq> None \<or>
  1058               have "lookup root ((path @ [y]) @ (us @ [u])) \<noteq> None \<or>
  1086                   lookup root ((path @ [y]) @ us) \<noteq> None"
  1059                   lookup root ((path @ [y]) @ us) \<noteq> None"
  1087                 by cases (auto dest: access_some_lookup)
  1060                 by cases (auto dest: access_some_lookup)
  1088               thus ?thesis by (blast dest!: lookup_some_append)
  1061               then show ?thesis by (blast dest!: lookup_some_append)
  1089             qed
  1062             qed
  1090             finally show ?thesis .
  1063             finally show ?thesis .
  1091           qed
  1064           qed
  1092           with ys show ?thesis
  1065           with ys show ?thesis
  1093             by (insert that, auto simp add: update_cons_cons_env)
  1066             by (insert that, auto simp add: update_cons_cons_env)