@@ -17,8 +17,10 @@ open Eio.Std
1717
1818let ( / ) = Path.( / )
1919
20- let run fn =
20+ let run ?clear:(paths = []) fn =
2121 Eio_main.run @@ fun env ->
22+ let cwd = Eio.Stdenv.cwd env in
23+ List.iter (fun p -> Eio.Path.rmtree ~missing_ok:true (cwd / p)) paths;
2224 fn env
2325
2426let try_read_file path =
@@ -69,13 +71,26 @@ let try_rmtree ?missing_ok path =
6971let chdir path =
7072 traceln "chdir %S" path;
7173 Unix.chdir path
74+
75+ let try_stat path =
76+ let stat ~follow =
77+ match Eio.Path.stat ~follow path with
78+ | info -> Fmt.str "@[<h>%a@]" Eio.File.Stat.pp_kind info.kind
79+ | exception Eio.Io (e, _) -> Fmt.str "@[<h>%a@]" Eio.Exn.pp_err e
80+ in
81+ let a = stat ~follow:false in
82+ let b = stat ~follow:true in
83+ if a = b then
84+ traceln "%a -> %s" Eio.Path.pp path a
85+ else
86+ traceln "%a -> %s / %s" Eio.Path.pp path a b
7287```
7388
7489# Basic test cases
7590
7691Creating a file and reading it back:
7792``` ocaml
78- # run @@ fun env ->
93+ # run ~clear:["test-file"] @@ fun env ->
7994 let cwd = Eio.Stdenv.cwd env in
8095 Path.save ~create:(`Exclusive 0o666) (cwd / "test-file") "my-data";
8196 traceln "Got %S" @@ Path.load (cwd / "test-file");;
@@ -179,7 +194,7 @@ Appending to an existing file:
179194# Mkdir
180195
181196``` ocaml
182- # run @@ fun env ->
197+ # run ~clear:["subdir"] @@ fun env ->
183198 let cwd = Eio.Stdenv.cwd env in
184199 try_mkdir (cwd / "subdir");
185200 try_mkdir (cwd / "subdir/nested");
@@ -188,19 +203,18 @@ Appending to an existing file:
188203+mkdir <cwd:subdir> -> ok
189204+mkdir <cwd:subdir/nested> -> ok
190205- : unit = ()
191- # Unix.unlink "subdir/nested/test-file"; Unix.rmdir "subdir/nested"; Unix.rmdir "subdir";;
206+ # Unix.unlink "subdir/nested/test-file";
207+ Unix.rmdir "subdir/nested";
208+ Unix.rmdir "subdir";;
192209- : unit = ()
193210```
194211
195212Creating directories with nesting, symlinks, etc:
196213``` ocaml
197- # Unix.symlink "/" "to-root";;
198- - : unit = ()
199- # Unix.symlink "subdir" "to-subdir";;
200- - : unit = ()
201- # Unix.symlink "foo" "dangle";;
202- - : unit = ()
203- # run @@ fun env ->
214+ # run ~clear:["to-subdir"; "to-root"; "dangle"] @@ fun env ->
215+ Unix.symlink "/" "to-root";
216+ Unix.symlink "subdir" "to-subdir";
217+ Unix.symlink "foo" "dangle";
204218 let cwd = Eio.Stdenv.cwd env in
205219 try_mkdir (cwd / "subdir");
206220 try_mkdir (cwd / "to-subdir/nested");
@@ -265,7 +279,7 @@ let split path = Eio.Path.split (fake_dir, path) |> Option.map (fun ((_, dirname
265279Recursively creating directories with ` mkdirs ` .
266280
267281``` ocaml
268- # run @@ fun env ->
282+ # run ~clear:["subdir1"] @@ fun env ->
269283 let cwd = Eio.Stdenv.cwd env in
270284 let nested = cwd / "subdir1" / "subdir2" / "subdir3" in
271285 try_mkdirs nested;
@@ -287,7 +301,7 @@ Recursively creating directories with `mkdirs`.
287301Some edge cases for ` mkdirs ` .
288302
289303``` ocaml
290- # run @@ fun env ->
304+ # run ~clear:["test"] @@ fun env ->
291305 let cwd = Eio.Stdenv.cwd env in
292306 try_mkdirs (cwd / ".");
293307 try_mkdirs (cwd / "././");
@@ -307,7 +321,7 @@ Some edge cases for `mkdirs`.
307321You can remove a file using unlink:
308322
309323``` ocaml
310- # run @@ fun env ->
324+ # run ~clear:["file"; "subdir/file2"] @@ fun env ->
311325 Switch.run @@ fun sw ->
312326 let cwd = Eio.Stdenv.cwd env in
313327 Path.save ~create:(`Exclusive 0o600) (cwd / "file") "data";
@@ -352,12 +366,67 @@ Removing something that doesn't exist or is out of scope:
352366- : unit = ()
353367```
354368
369+ Reads and writes follow symlinks, but unlink operates on the symlink itself:
370+
371+ ``` ocaml
372+ # run ~clear:["link1"; "linkdir"; "linkroot"; "dir1"; "file2"] @@ fun env ->
373+ Switch.run @@ fun sw ->
374+ let cwd = Eio.Stdenv.cwd env in
375+ let fs = Eio.Stdenv.fs env in
376+
377+ try_mkdir (cwd / "dir1");
378+ let file1 = cwd / "dir1" / "file1" in
379+ let file2 = cwd / "file2" in
380+ try_write_file ~create:(`Exclusive 0o600) file1 "data1";
381+ try_write_file ~create:(`Exclusive 0o400) file2 "data2";
382+ Unix.symlink "dir1/file1" "link1";
383+ Unix.symlink "../file2" "dir1/link2";
384+ Unix.symlink "dir1" "linkdir";
385+ Unix.symlink "/" "linkroot";
386+ try_read_file file1;
387+ try_read_file (cwd / "link1");
388+ try_read_file (cwd / "linkdir" / "file1");
389+
390+ try_stat file1;
391+ try_stat (cwd / "link1");
392+ try_stat (cwd / "linkdir");
393+ try_stat (cwd / "linkroot");
394+ try_stat (fs / "linkroot");
395+
396+ Fun.protect ~finally:(fun () -> chdir "..") (fun () ->
397+ chdir "dir1";
398+ try_read_file (cwd / "file1");
399+ (* Should remove link itself even though it's poiting outside of cwd *)
400+ Path.unlink (cwd / "link2")
401+ );
402+ try_read_file file2;
403+ Path.unlink (cwd / "link1");
404+ Path.unlink (cwd / "linkdir");
405+ Path.unlink (cwd / "linkroot")
406+ +mkdir <cwd:dir1> -> ok
407+ +write <cwd:dir1/file1> -> ok
408+ +write <cwd:file2> -> ok
409+ +read <cwd:dir1/file1> -> "data1"
410+ +read <cwd:link1> -> "data1"
411+ +read <cwd:linkdir/file1> -> "data1"
412+ +<cwd:dir1/file1> -> regular file
413+ +<cwd:link1> -> symbolic link / regular file
414+ +<cwd:linkdir> -> symbolic link / directory
415+ +<cwd:linkroot> -> symbolic link / Fs Permission_denied _
416+ +<fs:linkroot> -> symbolic link / directory
417+ +chdir "dir1"
418+ +read <cwd:file1> -> "data1"
419+ +chdir ".."
420+ +read <cwd:file2> -> "data2"
421+ - : unit = ()
422+ ```
423+
355424# Rmdir
356425
357426Similar to ` unlink ` , but works on directories:
358427
359428``` ocaml
360- # run @@ fun env ->
429+ # run ~clear:["d1"; "subdir/d2"; "subdir/d3"] @@ fun env ->
361430 Switch.run @@ fun sw ->
362431 let cwd = Eio.Stdenv.cwd env in
363432 try_mkdir (cwd / "d1");
@@ -405,7 +474,7 @@ Removing something that doesn't exist or is out of scope:
405474# Recursive removal
406475
407476``` ocaml
408- # run @@ fun env ->
477+ # run ~clear:["foo"] @@ fun env ->
409478 Switch.run @@ fun sw ->
410479 let cwd = Eio.Stdenv.cwd env in
411480 let foo = cwd / "foo" in
@@ -431,7 +500,7 @@ Removing something that doesn't exist or is out of scope:
431500
432501Create a sandbox, write a file with it, then read it from outside:
433502``` ocaml
434- # run @@ fun env ->
503+ # run ~clear:["sandbox"] @@ fun env ->
435504 Switch.run @@ fun sw ->
436505 let cwd = Eio.Stdenv.cwd env in
437506 try_mkdir (cwd / "sandbox");
@@ -450,7 +519,7 @@ Create a sandbox, write a file with it, then read it from outside:
450519We create a directory and chdir into it.
451520Using ` cwd ` we can't access the parent, but using ` fs ` we can:
452521``` ocaml
453- # run @@ fun env ->
522+ # run ~clear:["fs-test"; "outside-cwd"] @@ fun env ->
454523 let cwd = Eio.Stdenv.cwd env in
455524 let fs = Eio.Stdenv.fs env in
456525 try_mkdir (cwd / "fs-test");
@@ -476,7 +545,7 @@ Using `cwd` we can't access the parent, but using `fs` we can:
476545Reading directory entries under ` cwd ` and outside of ` cwd ` .
477546
478547``` ocaml
479- # run @@ fun env ->
548+ # run ~clear:["readdir"] @@ fun env ->
480549 let cwd = Eio.Stdenv.cwd env in
481550 try_mkdir (cwd / "readdir");
482551 Path.with_open_dir (cwd / "readdir") @@ fun tmpdir ->
@@ -499,7 +568,8 @@ Reading directory entries under `cwd` and outside of `cwd`.
499568An error from the underlying directory, not the sandbox:
500569
501570``` ocaml
502- # Unix.mkdir "test-no-access" 0;;
571+ # run ~clear:["test-no-access"] @@ fun env ->
572+ Unix.mkdir "test-no-access" 0;;
503573- : unit = ()
504574# run @@ fun env ->
505575 let cwd = Eio.Stdenv.cwd env in
@@ -530,7 +600,7 @@ Exception: Eio.Io Fs Permission_denied _,
530600## Streamling lines
531601
532602``` ocaml
533- # run @@ fun env ->
603+ # run ~clear:["test-data"] @@ fun env ->
534604 let cwd = Eio.Stdenv.cwd env in
535605 Path.save ~create:(`Exclusive 0o600) (cwd / "test-data") "one\ntwo\nthree";
536606 Path.with_lines (cwd / "test-data") (fun lines ->
@@ -609,7 +679,7 @@ let try_rename t =
609679Confined:
610680
611681``` ocaml
612- # run @@ fun env -> try_rename env#cwd;;
682+ # run ~clear:["tmp"; "dir"] @@ fun env -> try_rename env#cwd;;
613683+mkdir <cwd:tmp> -> ok
614684+rename <cwd:tmp> to <cwd:dir> -> ok
615685+write <cwd:foo> -> ok
@@ -639,22 +709,7 @@ Unconfined:
639709# Stat
640710
641711``` ocaml
642- let try_stat path =
643- let stat ~follow =
644- match Eio.Path.stat ~follow path with
645- | info -> Fmt.str "@[<h>%a@]" Eio.File.Stat.pp_kind info.kind
646- | exception Eio.Io (e, _) -> Fmt.str "@[<h>%a@]" Eio.Exn.pp_err e
647- in
648- let a = stat ~follow:false in
649- let b = stat ~follow:true in
650- if a = b then
651- traceln "%a -> %s" Eio.Path.pp path a
652- else
653- traceln "%a -> %s / %s" Eio.Path.pp path a b
654- ```
655-
656- ``` ocaml
657- # run @@ fun env ->
712+ # run ~clear:["stat_subdir"; "stat_reg"] @@ fun env ->
658713 let cwd = Eio.Stdenv.cwd env in
659714 Switch.run @@ fun sw ->
660715 try_mkdir (cwd / "stat_subdir");
@@ -666,10 +721,10 @@ let try_stat path =
666721- : unit = ()
667722```
668723
669- Fstatat:
724+ # Fstatat:
670725
671726``` ocaml
672- # run @@ fun env ->
727+ # run ~clear:["stat_subdir2"; "symlink"; "broken-symlink"; "parent-symlink"] @@ fun env ->
673728 let cwd = Eio.Stdenv.cwd env in
674729 Switch.run @@ fun sw ->
675730 try_mkdir (cwd / "stat_subdir2");
@@ -701,7 +756,7 @@ Fstatat:
701756Check reading and writing vectors at arbitrary offsets:
702757
703758``` ocaml
704- # run @@ fun env ->
759+ # run ~clear:["test.txt"] @@ fun env ->
705760 let cwd = Eio.Stdenv.cwd env in
706761 let path = cwd / "test.txt" in
707762 Path.with_open_out path ~create:(`Exclusive 0o600) @@ fun file ->
@@ -741,7 +796,7 @@ Reading at the end of a file:
741796Ensure reads can be cancelled promptly, even if there is no need to wait:
742797
743798``` ocaml
744- # Eio_main. run @@ fun env ->
799+ # run @@ fun env ->
745800 Eio.Path.with_open_out (env#fs / "/dev/zero") ~create:`Never @@ fun null ->
746801 Fiber.both
747802 (fun () ->
@@ -755,7 +810,7 @@ Exception: Failure "Simulated error".
755810# Native paths
756811
757812``` ocaml
758- # Eio_main. run @@ fun env ->
813+ # run ~clear:["native-sub"] @@ fun env ->
759814 let cwd = Sys.getcwd () ^ "/" in
760815 let test x =
761816 let native = Eio.Path.native x in
@@ -800,7 +855,7 @@ Exception: Failure "Simulated error".
800855# Seek, truncate and sync
801856
802857``` ocaml
803- # Eio_main. run @@ fun env ->
858+ # run @@ fun env ->
804859 Eio.Path.with_open_out (env#cwd / "seek-test") ~create:(`If_missing 0o700) @@ fun file ->
805860 Eio.File.truncate file (Int63.of_int 10);
806861 assert ((Eio.File.stat file).size = (Int63.of_int 10));
0 commit comments