cap_primitives/fs/
open.rs1#[cfg(racy_asserts)]
5use crate::fs::{file_path, open_unchecked, stat_unchecked, Metadata};
6use crate::fs::{open_impl, OpenOptions};
7use std::path::Path;
8use std::{fs, io};
9
10#[cfg_attr(not(racy_asserts), allow(clippy::let_and_return))]
13#[inline]
14pub fn open(start: &fs::File, path: &Path, options: &OpenOptions) -> io::Result<fs::File> {
15 #[cfg(racy_asserts)]
16 let stat_before = stat_unchecked(start, path, options.follow);
17
18 let result = open_impl(start, path, options);
20
21 #[cfg(racy_asserts)]
22 let stat_after = stat_unchecked(start, path, options.follow);
23
24 #[cfg(racy_asserts)]
25 check_open(start, path, options, &stat_before, &result, &stat_after);
26
27 result
28}
29
30#[cfg(racy_asserts)]
31fn check_open(
32 start: &fs::File,
33 path: &Path,
34 options: &OpenOptions,
35 _stat_before: &io::Result<Metadata>,
36 result: &io::Result<fs::File>,
37 _stat_after: &io::Result<Metadata>,
38) {
39 let unchecked_result = open_unchecked(
40 start,
41 path,
42 options
43 .clone()
44 .create(false)
45 .create_new(false)
46 .truncate(false),
47 );
48
49 match (&result, &unchecked_result) {
50 (Ok(result_file), Ok(unchecked_file)) => {
51 assert_same_file!(
52 &result_file,
53 &unchecked_file,
54 "path resolution inconsistency: start='{:?}', path='{}'",
55 start,
56 path.display(),
57 );
58 }
59 (Ok(result_file), Err(unchecked_error)) => {
60 if unchecked_error.kind() == io::ErrorKind::PermissionDenied {
61 assert!(options.create || options.create_new);
62 } else {
63 panic!(
64 "unexpected success opening start='{:?}', path='{}'; expected {:?}; got {:?}",
65 start,
66 path.display(),
67 unchecked_error,
68 result_file
69 );
70 }
71 }
72 (Err(result_error), Ok(_unchecked_file)) => match result_error.kind() {
73 io::ErrorKind::PermissionDenied | io::ErrorKind::InvalidInput => (),
74 io::ErrorKind::AlreadyExists if options.create_new => (),
75 _ => panic!(
76 "unexpected error opening start='{:?}', path='{}': {:?}",
77 start,
78 path.display(),
79 result_error
80 ),
81 },
82 (Err(result_error), Err(_unchecked_error)) => match result_error.kind() {
83 io::ErrorKind::PermissionDenied | io::ErrorKind::InvalidInput => (),
84 _ => {
85 }
91 },
92 }
93
94 if let Ok(result_file) = &result {
97 if let Some(result_path) = file_path(result_file) {
98 if let Some(start_path) = file_path(start) {
99 assert!(
100 result_path.starts_with(start_path),
101 "sandbox escape: start='{:?}' result='{}'",
102 start,
103 result_path.display()
104 );
105 }
106 }
107 }
108}