diff --git a/master_changes.md b/master_changes.md index 85463e6e74d..a5d114927e5 100644 --- a/master_changes.md +++ b/master_changes.md @@ -32,6 +32,7 @@ users) ## Actions * Reorder the list of actions by increased priority [#6864 @kit-ty-kate - fix #6863] * The internal `sources` directory now only serves to cache dev packages instead of every packages, saving disk space. For other packages it is now removed during the build phase. [#6440 @kit-ty-kate - fix #4056 #5448] + * Stop the installation process via .install file from creating unnecessary intermediate directories for paths that contain `..` [#7015 @kit-ty-kate] ## Install * Remove the build directory as soon as possible when installing a package [#6906 @kit-ty-kate - fix #5884] @@ -237,6 +238,7 @@ users) * Add a test showing when opam creates a local switch vs. global [#6981 @kit-ty-kate] * Add a test showing the behaviour of `opam lock` in presence of disjunction in the dependency formula [#6990 @kit-ty-kate] * Add a test showing the behaviour of `opam pin add ` [#7012 @kit-ty-kate] + * Add more tests to ensure the inescapability of relative paths containing `..` in .install files [#7015 @kit-ty-kate] ### Engine * Add `http-server` to launch a minimal http server [#6939 @rjbou] diff --git a/src/client/opamAction.ml b/src/client/opamAction.ml index 1262e7d2568..0e699da7c36 100644 --- a/src/client/opamAction.ml +++ b/src/client/opamAction.ml @@ -101,7 +101,7 @@ let preprocess_dot_install_t st nv build_dir = else (base, false) in let src_file = OpamFilename.create build_dir base.c in - let dst_file = match dst with + let unsafe_dst_file = match dst with | None -> OpamFilename.create dst_dir (OpamFilename.basename src_file) | Some d -> if append && not (OpamFilename.Base.check_suffix d ".exe") then @@ -109,25 +109,25 @@ let preprocess_dot_install_t st nv build_dir = (OpamFilename.Base.add_extension d "exe") else OpamFilename.create dst_dir d in + let dst_file = + OpamFilename.of_string + (OpamSystem.real_path (OpamFilename.to_string unsafe_dst_file)) + in let file = file_wo_prefix dst_file in let inst warning = if append then warning (OpamFilename.to_string src_file) `Add_exe; let check, warn = check ~src:build_dir ~dst:dst_dir base in - let real_dst = - OpamFilename.of_string - (OpamSystem.real_path (OpamFilename.to_string dst_file)) - in let escapes = - not (OpamFilename.starts_with switch_prefix real_dst) - || (OpamFilename.starts_with switch_meta real_dst) + not (OpamFilename.starts_with switch_prefix dst_file) + || (OpamFilename.starts_with switch_meta dst_file) in if escapes then (OpamConsole.error "package %s attempted to install a file outside allowed \ destination directories: %s -> %s." (OpamPackage.Name.to_string name) - (OpamFilename.to_string dst_file) - (OpamFilename.to_string real_dst); + (OpamFilename.to_string unsafe_dst_file) + (OpamFilename.to_string dst_file); failwith ".install file escaping allowed directories") else if check then OpamFilename.install ~warning ~exec ~src:src_file ~dst:dst_file (); diff --git a/tests/reftests/dot-install.test b/tests/reftests/dot-install.test index 2317cf1df74..a3849bc478a 100644 --- a/tests/reftests/dot-install.test +++ b/tests/reftests/dot-install.test @@ -483,3 +483,286 @@ SYSTEM LOCK ${BASEDIR}/OPAM/config.lock (none => none) Not found: ${BASEDIR}/OPAM/escapability/share/eskape/a-file ==> eskape changes opam-version: "2.0" +### : Testing escapability with a relative path containing '..' that does exist and doesn't escape +### +opam-version: "2.0" +install: [ "echo" "hellow" ] +### touch OPAM/escapability/a-file +### +lib: [ + "a-file" { "../../a-file" } +] +etc: [ + "a-file" { "../../a-file" } +] +share: [ + "a-file" { "../../a-file" } +] +misc: [ + "a-file" { "../../a-file" } +] +### +hellow +### opam install eskape-rel-dotdot-exists | unordered +FILE(config) Read ${BASEDIR}/OPAM/config in 0.000s +SYSTEM LOCK ${BASEDIR}/OPAM/lock (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (read => none) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (read => none) +The following actions will be performed: +=== install 1 package + - install eskape-rel-dotdot-exists 1 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +SYSTEM rmdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1 +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-dotdot-exists/eskape-rel-dotdot-exists.1/files/eskape-rel-dotdot-exists.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/eskape-rel-dotdot-exists.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-dotdot-exists/eskape-rel-dotdot-exists.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/a-file +[WARNING] Errors in ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/eskape-rel-dotdot-exists.install, some fields have been ignored: + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/eskape-rel-dotdot-exists.install:2:14-2:28:: + ../../a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/eskape-rel-dotdot-exists.install:11:14-11:28:: + ../../a-file is not an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/eskape-rel-dotdot-exists.install:8:14-8:28:: + ../../a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-dotdot-exists.1/eskape-rel-dotdot-exists.install:5:14-5:28:: + ../../a-file references its parent directory. + +-> installed eskape-rel-dotdot-exists.1 +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-dotdot-exists.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-dotdot-exists.1/files +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-dotdot-exists/eskape-rel-dotdot-exists.1/files/eskape-rel-dotdot-exists.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-dotdot-exists.1/files/eskape-rel-dotdot-exists.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-dotdot-exists/eskape-rel-dotdot-exists.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-dotdot-exists.1/files/a-file +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (write => none) +Done. +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (write => none) +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/backup/state-today.export +SYSTEM LOCK ${BASEDIR}/OPAM/repo/lock (none => none) +SYSTEM LOCK ${BASEDIR}/OPAM/config.lock (none => none) +### ocaml cat.ml escapability eskape-rel-dotdot-exists +==> eskape-rel-dotdot-exists installed file +Not found: ${BASEDIR}/OPAM/escapability/share/eskape-rel-dotdot-exists/a-file +==> eskape-rel-dotdot-exists changes +opam-version: "2.0" +### : Testing escapability with a relative path containing '..' in the middle, that does not exist and doesn't escape +### +opam-version: "2.0" +install: [ "echo" "hellow" ] +### +lib: [ + "a-file" { "tmp/../middle/a-file" } +] +bin: [ + "a-file" { "tmp/../middle/a-file" } +] +etc: [ + "a-file" { "tmp/../middle/a-file" } +] +share: [ + "a-file" { "tmp/../middle/a-file" } +] +misc: [ + "a-file" { "tmp/../middle/a-file" } +] +### +hellow +### opam install eskape-rel-middotdot-notexists | unordered +FILE(config) Read ${BASEDIR}/OPAM/config in 0.000s +SYSTEM LOCK ${BASEDIR}/OPAM/lock (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (read => none) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (read => none) +The following actions will be performed: +=== install 1 package + - install eskape-rel-middotdot-notexists 1 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +SYSTEM rmdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1 +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-middotdot-notexists/eskape-rel-middotdot-notexists.1/files/eskape-rel-middotdot-notexists.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-middotdot-notexists/eskape-rel-middotdot-notexists.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/a-file +[WARNING] Errors in ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install, some fields have been ignored: + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install:2:13-2:35:: + tmp/../middle/a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install:5:13-5:35:: + tmp/../middle/a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install:14:13-14:35:: + tmp/../middle/a-file is not an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install:11:13-11:35:: + tmp/../middle/a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-rel-middotdot-notexists.1/eskape-rel-middotdot-notexists.install:8:13-8:35:: + tmp/../middle/a-file references its parent directory. + +-> installed eskape-rel-middotdot-notexists.1 +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-middotdot-notexists.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-middotdot-notexists.1/files +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-middotdot-notexists/eskape-rel-middotdot-notexists.1/files/eskape-rel-middotdot-notexists.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-middotdot-notexists.1/files/eskape-rel-middotdot-notexists.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-rel-middotdot-notexists/eskape-rel-middotdot-notexists.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-rel-middotdot-notexists.1/files/a-file +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (write => none) +Done. +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (write => none) +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/backup/state-today.export +SYSTEM LOCK ${BASEDIR}/OPAM/repo/lock (none => none) +SYSTEM LOCK ${BASEDIR}/OPAM/config.lock (none => none) +### ocaml cat.ml escapability eskape-rel-middotdot-notexists +==> eskape-rel-middotdot-notexists installed file +Not found: ${BASEDIR}/OPAM/escapability/share/eskape-rel-middotdot-notexists/a-file +==> eskape-rel-middotdot-notexists changes +opam-version: "2.0" +### : Testing escapability with a relative path containing '..' in the middle, that does not exist and does escape +### +opam-version: "2.0" +install: [ "echo" "hellow" ] +### +lib: [ + "a-file" { "tmp/../../../../middle/a-file" } +] +bin: [ + "a-file" { "tmp/../../../middle/a-file" } +] +etc: [ + "a-file" { "tmp/../../../../middle/a-file" } +] +share: [ + "a-file" { "tmp/../../../../middle/a-file" } +] +misc: [ + "a-file" { "tmp/../../../../middle/a-file" } +] +### +hellow +### opam install realeskape-rel-middotdot-notexists | unordered +FILE(config) Read ${BASEDIR}/OPAM/config in 0.000s +SYSTEM LOCK ${BASEDIR}/OPAM/lock (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (read => none) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (read => none) +The following actions will be performed: +=== install 1 package + - install realeskape-rel-middotdot-notexists 1 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +SYSTEM rmdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1 +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/realeskape-rel-middotdot-notexists/realeskape-rel-middotdot-notexists.1/files/realeskape-rel-middotdot-notexists.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/realeskape-rel-middotdot-notexists/realeskape-rel-middotdot-notexists.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/a-file +[WARNING] Errors in ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install, some fields have been ignored: + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install:2:13-2:44:: + tmp/../../../../middle/a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install:5:13-5:41:: + tmp/../../../middle/a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install:14:13-14:44:: + tmp/../../../../middle/a-file is not an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install:11:13-11:44:: + tmp/../../../../middle/a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/realeskape-rel-middotdot-notexists.1/realeskape-rel-middotdot-notexists.install:8:13-8:44:: + tmp/../../../../middle/a-file references its parent directory. + +-> installed realeskape-rel-middotdot-notexists.1 +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/realeskape-rel-middotdot-notexists.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/realeskape-rel-middotdot-notexists.1/files +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/realeskape-rel-middotdot-notexists/realeskape-rel-middotdot-notexists.1/files/realeskape-rel-middotdot-notexists.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/realeskape-rel-middotdot-notexists.1/files/realeskape-rel-middotdot-notexists.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/realeskape-rel-middotdot-notexists/realeskape-rel-middotdot-notexists.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/realeskape-rel-middotdot-notexists.1/files/a-file +Done. +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (write => none) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (write => none) +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/backup/state-today.export +SYSTEM LOCK ${BASEDIR}/OPAM/repo/lock (none => none) +SYSTEM LOCK ${BASEDIR}/OPAM/config.lock (none => none) +### ocaml cat.ml escapability realeskape-rel-middotdot-notexists +==> realeskape-rel-middotdot-notexists installed file +Not found: ${BASEDIR}/OPAM/escapability/share/realeskape-rel-middotdot-notexists/a-file +==> realeskape-rel-middotdot-notexists changes +opam-version: "2.0" +### : Testing escapability with an absolute path +### +opam-version: "2.0" +install: [ "echo" "hellow" ] +### +lib: [ + "fichier" { "/ab/so/lute/path/fichier" } +] +bin: [ + "fichier" { "/ab/so/lute/path/fichier" } +] +etc: [ + "fichier" { "/ab/so/lute/path/fichier" } +] +share: [ + "fichier" { "/ab/so/lute/path/fichier" } +] +### +hellow +### opam install eskape-abs | unordered +FILE(config) Read ${BASEDIR}/OPAM/config in 0.000s +SYSTEM LOCK ${BASEDIR}/OPAM/lock (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (read => none) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (read => none) +The following actions will be performed: +=== install 1 package + - install eskape-abs 1 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +SYSTEM rmdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1 +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-abs/eskape-abs.1/files/eskape-abs.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/eskape-abs.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-abs/eskape-abs.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/a-file +[WARNING] Errors in ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/eskape-abs.install, some fields have been ignored: + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/eskape-abs.install:2:14-2:40:: + /ab/so/lute/path/fichier is an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/eskape-abs.install:5:14-5:40:: + /ab/so/lute/path/fichier is an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/eskape-abs.install:11:14-11:40:: + /ab/so/lute/path/fichier is an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape-abs.1/eskape-abs.install:8:14-8:40:: + /ab/so/lute/path/fichier is an absolute filename. + +-> installed eskape-abs.1 +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-abs.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-abs.1/files +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-abs/eskape-abs.1/files/eskape-abs.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-abs.1/files/eskape-abs.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape-abs/eskape-abs.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape-abs.1/files/a-file +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (write => none) +Done. +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (write => none) +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/backup/state-today.export +SYSTEM LOCK ${BASEDIR}/OPAM/repo/lock (none => none) +SYSTEM LOCK ${BASEDIR}/OPAM/config.lock (none => none) +### ocaml cat.ml escapability eskape-abs +==> eskape-abs installed file +Not found: ${BASEDIR}/OPAM/escapability/share/eskape-abs/a-file +==> eskape-abs changes +opam-version: "2.0"