standard_lib/fs/file/
options.rs1use std::fmt;
2use std::ffi::CString;
3use std::fmt::{Debug, Formatter};
4use std::io::RawOsError;
5use std::marker::PhantomData;
6
7use libc::{O_APPEND, O_CREAT, O_EXCL, O_NOATIME, O_NOFOLLOW, O_SYNC, O_TRUNC, c_int};
8
9use super::{File, AccessMode};
10use crate::fs::dir::DirEntry;
11use crate::fs::path::{Abs, Path};
12use crate::fs::{Directory, Fd, Rel};
13use crate::util;
14
15#[derive(Clone)]
19pub struct OpenOptions<Access: AccessMode> {
20 pub(crate) _access: PhantomData<fn() -> Access>,
21 pub create: Option<Create>,
22 pub mode: Option<u16>,
23 pub append: Option<bool>,
24 pub force_sync: Option<bool>,
25 pub update_access_time: Option<bool>,
26 pub follow_links: Option<bool>,
27 pub extra_flags: Option<i32>,
28}
29
30#[derive(Debug, Clone, Copy, Default)]
31pub enum Create {
32 No,
33 #[default]
34 IfAbsent,
35 OrClear,
36 Require,
37}
38
39impl<A: AccessMode> OpenOptions<A> {
40 pub(crate) fn flags(&self) -> c_int {
41 let mut flags = A::FLAGS;
42 match &self.create.unwrap_or_default() {
43 Create::No => (),
44 Create::IfAbsent => flags |= O_CREAT,
45 Create::OrClear => flags |= O_CREAT | O_TRUNC,
46 Create::Require => flags |= O_CREAT | O_EXCL,
47 }
48 if self.append.unwrap_or(false) {
49 flags |= O_APPEND;
50 }
51 if self.force_sync.unwrap_or(false) {
52 flags |= O_SYNC;
53 }
54 if !self.update_access_time.unwrap_or(true) {
55 flags |= O_NOATIME;
56 }
57 if !self.follow_links.unwrap_or(true) {
58 flags |= O_NOFOLLOW;
59 }
60 flags | self.extra_flags.unwrap_or_default()
61 }
62
63 pub fn new() -> OpenOptions<A> {
64 OpenOptions::<A>::default()
65 }
66
67 pub fn open<P: AsRef<Path<Abs>>>(&self, file_path: P) -> Result<File<A>, RawOsError> {
68 let pathname = CString::from(file_path.as_ref().to_owned());
69 let mode = self.mode.unwrap_or(0o644) as c_int;
71
72 match unsafe { libc::open(pathname.as_ptr().cast(), self.flags(), mode) } {
73 -1 => Err(util::fs::err_no()),
74 fd => Ok(File::<A> {
75 _access: PhantomData,
76 fd: Fd(fd),
77 }),
78 }
79 }
80
81 pub fn open_rel<P: AsRef<Path<Rel>>>(
82 &self,
83 relative_to: &Directory,
84 file_path: P
85 ) -> Result<File<A>, RawOsError> {
86 let pathname = CString::from(file_path.as_ref().to_owned());
87 let mode = self.mode.unwrap_or(0o644) as c_int;
88
89 match unsafe { libc::openat(
90 *relative_to.fd,
91 pathname.as_ptr().add(1).cast(),
93 self.flags(),
94 mode
95 ) } {
96 -1 => Err(util::fs::err_no()),
97 fd => Ok(File::<A> {
98 _access: PhantomData,
99 fd: Fd(fd),
100 }),
101 }
102 }
103
104 pub fn open_dir_entry(&self, dir_ent: &DirEntry) -> Result<File<A>, RawOsError> {
105 self.open_rel(dir_ent.parent, &dir_ent.path)
106 }
107
108 pub const fn create_mode(&mut self, value: Create) -> &mut Self {
109 self.create = Some(value);
110 self
111 }
112
113 pub const fn no_create(&mut self) -> &mut Self {
114 self.create = Some(Create::No);
115 self
116 }
117
118 pub const fn create_if_absent(&mut self) -> &mut Self {
119 self.create = Some(Create::IfAbsent);
120 self
121 }
122
123 pub const fn create_or_clear(&mut self) -> &mut Self {
124 self.create = Some(Create::OrClear);
125 self
126 }
127
128 pub const fn create_only(&mut self) -> &mut Self {
129 self.create = Some(Create::Require);
130 self
131 }
132
133 pub const fn mode(&mut self, value: u16) -> &mut Self {
134 self.mode = Some(value);
135 self
136 }
137
138 pub const fn append(&mut self, value: bool) -> &mut Self {
139 self.append = Some(value);
140 self
141 }
142
143 pub const fn force_sync(&mut self, value: bool) -> &mut Self {
144 self.force_sync = Some(value);
145 self
146 }
147
148 pub const fn update_access_time(&mut self, value: bool) -> &mut Self {
149 self.update_access_time = Some(value);
150 self
151 }
152
153 pub const fn follow_links(&mut self, value: bool) -> &mut Self {
154 self.follow_links = Some(value);
155 self
156 }
157
158 pub const fn extra_flags(&mut self, value: i32) -> &mut Self {
159 self.extra_flags = Some(value);
160 self
161 }
162}
163
164impl<A: AccessMode> Default for OpenOptions<A> {
166 fn default() -> Self {
167 Self {
168 _access: Default::default(),
169 create: Default::default(),
170 mode: Default::default(),
171 append: Default::default(),
172 force_sync: Default::default(),
173 update_access_time: Default::default(),
174 follow_links: Default::default(),
175 extra_flags: Default::default()
176 }
177 }
178}
179
180impl<A: AccessMode> Debug for OpenOptions<A> {
181 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
182 f.debug_struct("OpenOptions")
183 .field("<access>", &util::fmt::raw_type_name::<A>())
184 .field("create", &self.create)
185 .field("mode", &self.mode)
186 .field("append", &self.append)
187 .field("force_sync", &self.force_sync)
188 .field("update_access_time", &self.update_access_time)
189 .field("follow_links", &self.follow_links)
190 .field("extra_flags", &self.extra_flags)
191 .finish()
192 }
193}