]>
Commit | Line | Data |
---|---|---|
d9579d0f AL |
1 | //! Unix-specific extensions to primitives in the `std::fs` module. |
2 | ||
3 | #![stable(feature = "rust1", since = "1.0.0")] | |
4 | ||
cdc7bbd5 | 5 | use super::platform::fs::MetadataExt as _; |
60c5eb7d | 6 | use crate::fs::{self, OpenOptions, Permissions}; |
532ac7d7 XL |
7 | use crate::io; |
8 | use crate::path::Path; | |
9 | use crate::sys; | |
60c5eb7d | 10 | use crate::sys_common::{AsInner, AsInnerMut, FromInner}; |
1b1a35ee | 11 | // Used for `File::read` on intra-doc links |
136023e0 XL |
12 | use crate::ffi::OsStr; |
13 | use crate::sealed::Sealed; | |
1b1a35ee XL |
14 | #[allow(unused_imports)] |
15 | use io::{Read, Write}; | |
d9579d0f | 16 | |
3dfed10e | 17 | /// Unix-specific extensions to [`fs::File`]. |
476ff2be | 18 | #[stable(feature = "file_offset", since = "1.15.0")] |
c30ab7b3 SL |
19 | pub trait FileExt { |
20 | /// Reads a number of bytes starting from a given offset. | |
21 | /// | |
22 | /// Returns the number of bytes read. | |
23 | /// | |
24 | /// The offset is relative to the start of the file and thus independent | |
25 | /// from the current cursor. | |
26 | /// | |
27 | /// The current file cursor is not affected by this function. | |
28 | /// | |
abe05a73 | 29 | /// Note that similar to [`File::read`], it is not an error to return with a |
c30ab7b3 | 30 | /// short read. |
abe05a73 | 31 | /// |
1b1a35ee | 32 | /// [`File::read`]: fs::File::read |
abe05a73 XL |
33 | /// |
34 | /// # Examples | |
35 | /// | |
0531ce1d XL |
36 | /// ```no_run |
37 | /// use std::io; | |
abe05a73 | 38 | /// use std::fs::File; |
0531ce1d | 39 | /// use std::os::unix::prelude::FileExt; |
abe05a73 | 40 | /// |
0531ce1d XL |
41 | /// fn main() -> io::Result<()> { |
42 | /// let mut buf = [0u8; 8]; | |
43 | /// let file = File::open("foo.txt")?; | |
abe05a73 | 44 | /// |
0531ce1d XL |
45 | /// // We now read 8 bytes from the offset 10. |
46 | /// let num_bytes_read = file.read_at(&mut buf, 10)?; | |
47 | /// println!("read {} bytes: {:?}", num_bytes_read, buf); | |
48 | /// Ok(()) | |
49 | /// } | |
abe05a73 | 50 | /// ``` |
476ff2be | 51 | #[stable(feature = "file_offset", since = "1.15.0")] |
c30ab7b3 SL |
52 | fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; |
53 | ||
8faf50e0 XL |
54 | /// Reads the exact number of byte required to fill `buf` from the given offset. |
55 | /// | |
56 | /// The offset is relative to the start of the file and thus independent | |
57 | /// from the current cursor. | |
58 | /// | |
59 | /// The current file cursor is not affected by this function. | |
60 | /// | |
3dfed10e | 61 | /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`. |
8faf50e0 | 62 | /// |
3dfed10e | 63 | /// [`read_at`]: FileExt::read_at |
8faf50e0 XL |
64 | /// |
65 | /// # Errors | |
66 | /// | |
67 | /// If this function encounters an error of the kind | |
3dfed10e | 68 | /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation |
8faf50e0 XL |
69 | /// will continue. |
70 | /// | |
71 | /// If this function encounters an "end of file" before completely filling | |
3dfed10e | 72 | /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`]. |
8faf50e0 XL |
73 | /// The contents of `buf` are unspecified in this case. |
74 | /// | |
75 | /// If any other read error is encountered then this function immediately | |
76 | /// returns. The contents of `buf` are unspecified in this case. | |
77 | /// | |
78 | /// If this function returns an error, it is unspecified how many bytes it | |
79 | /// has read, but it will never read more than would be necessary to | |
80 | /// completely fill the buffer. | |
81 | /// | |
8faf50e0 XL |
82 | /// # Examples |
83 | /// | |
84 | /// ```no_run | |
8faf50e0 XL |
85 | /// use std::io; |
86 | /// use std::fs::File; | |
87 | /// use std::os::unix::prelude::FileExt; | |
88 | /// | |
89 | /// fn main() -> io::Result<()> { | |
90 | /// let mut buf = [0u8; 8]; | |
91 | /// let file = File::open("foo.txt")?; | |
92 | /// | |
93 | /// // We now read exactly 8 bytes from the offset 10. | |
94 | /// file.read_exact_at(&mut buf, 10)?; | |
95 | /// println!("read {} bytes: {:?}", buf.len(), buf); | |
96 | /// Ok(()) | |
97 | /// } | |
98 | /// ``` | |
0731742a | 99 | #[stable(feature = "rw_exact_all_at", since = "1.33.0")] |
8faf50e0 XL |
100 | fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { |
101 | while !buf.is_empty() { | |
102 | match self.read_at(buf, offset) { | |
103 | Ok(0) => break, | |
104 | Ok(n) => { | |
105 | let tmp = buf; | |
106 | buf = &mut tmp[n..]; | |
107 | offset += n as u64; | |
108 | } | |
109 | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} | |
110 | Err(e) => return Err(e), | |
111 | } | |
112 | } | |
113 | if !buf.is_empty() { | |
cdc7bbd5 | 114 | Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer")) |
8faf50e0 XL |
115 | } else { |
116 | Ok(()) | |
117 | } | |
118 | } | |
119 | ||
c30ab7b3 SL |
120 | /// Writes a number of bytes starting from a given offset. |
121 | /// | |
122 | /// Returns the number of bytes written. | |
123 | /// | |
124 | /// The offset is relative to the start of the file and thus independent | |
125 | /// from the current cursor. | |
126 | /// | |
127 | /// The current file cursor is not affected by this function. | |
128 | /// | |
3b2f2976 | 129 | /// When writing beyond the end of the file, the file is appropriately |
c30ab7b3 SL |
130 | /// extended and the intermediate bytes are initialized with the value 0. |
131 | /// | |
abe05a73 | 132 | /// Note that similar to [`File::write`], it is not an error to return a |
c30ab7b3 | 133 | /// short write. |
abe05a73 | 134 | /// |
1b1a35ee | 135 | /// [`File::write`]: fs::File::write |
abe05a73 XL |
136 | /// |
137 | /// # Examples | |
138 | /// | |
0531ce1d | 139 | /// ```no_run |
abe05a73 | 140 | /// use std::fs::File; |
0531ce1d XL |
141 | /// use std::io; |
142 | /// use std::os::unix::prelude::FileExt; | |
abe05a73 | 143 | /// |
0531ce1d XL |
144 | /// fn main() -> io::Result<()> { |
145 | /// let file = File::open("foo.txt")?; | |
abe05a73 | 146 | /// |
0531ce1d XL |
147 | /// // We now write at the offset 10. |
148 | /// file.write_at(b"sushi", 10)?; | |
149 | /// Ok(()) | |
150 | /// } | |
abe05a73 | 151 | /// ``` |
476ff2be | 152 | #[stable(feature = "file_offset", since = "1.15.0")] |
c30ab7b3 | 153 | fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; |
8faf50e0 XL |
154 | |
155 | /// Attempts to write an entire buffer starting from a given offset. | |
156 | /// | |
157 | /// The offset is relative to the start of the file and thus independent | |
158 | /// from the current cursor. | |
159 | /// | |
160 | /// The current file cursor is not affected by this function. | |
161 | /// | |
162 | /// This method will continuously call [`write_at`] until there is no more data | |
3dfed10e | 163 | /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is |
8faf50e0 XL |
164 | /// returned. This method will not return until the entire buffer has been |
165 | /// successfully written or such an error occurs. The first error that is | |
3dfed10e | 166 | /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be |
8faf50e0 XL |
167 | /// returned. |
168 | /// | |
169 | /// # Errors | |
170 | /// | |
171 | /// This function will return the first error of | |
3dfed10e | 172 | /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns. |
8faf50e0 | 173 | /// |
3dfed10e | 174 | /// [`write_at`]: FileExt::write_at |
8faf50e0 XL |
175 | /// |
176 | /// # Examples | |
177 | /// | |
178 | /// ```no_run | |
8faf50e0 XL |
179 | /// use std::fs::File; |
180 | /// use std::io; | |
181 | /// use std::os::unix::prelude::FileExt; | |
182 | /// | |
183 | /// fn main() -> io::Result<()> { | |
184 | /// let file = File::open("foo.txt")?; | |
185 | /// | |
186 | /// // We now write at the offset 10. | |
187 | /// file.write_all_at(b"sushi", 10)?; | |
188 | /// Ok(()) | |
189 | /// } | |
190 | /// ``` | |
0731742a | 191 | #[stable(feature = "rw_exact_all_at", since = "1.33.0")] |
8faf50e0 XL |
192 | fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { |
193 | while !buf.is_empty() { | |
194 | match self.write_at(buf, offset) { | |
60c5eb7d | 195 | Ok(0) => { |
cdc7bbd5 | 196 | return Err(io::Error::new_const( |
60c5eb7d | 197 | io::ErrorKind::WriteZero, |
cdc7bbd5 | 198 | &"failed to write whole buffer", |
60c5eb7d XL |
199 | )); |
200 | } | |
8faf50e0 XL |
201 | Ok(n) => { |
202 | buf = &buf[n..]; | |
203 | offset += n as u64 | |
204 | } | |
205 | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} | |
206 | Err(e) => return Err(e), | |
207 | } | |
208 | } | |
209 | Ok(()) | |
210 | } | |
c30ab7b3 SL |
211 | } |
212 | ||
476ff2be | 213 | #[stable(feature = "file_offset", since = "1.15.0")] |
c30ab7b3 SL |
214 | impl FileExt for fs::File { |
215 | fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { | |
216 | self.as_inner().read_at(buf, offset) | |
217 | } | |
218 | fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { | |
219 | self.as_inner().write_at(buf, offset) | |
220 | } | |
221 | } | |
222 | ||
83c7162d | 223 | /// Unix-specific extensions to [`fs::Permissions`]. |
d9579d0f AL |
224 | #[stable(feature = "fs_ext", since = "1.1.0")] |
225 | pub trait PermissionsExt { | |
ea8adc8c XL |
226 | /// Returns the underlying raw `st_mode` bits that contain the standard |
227 | /// Unix permissions for this file. | |
5bcae85e SL |
228 | /// |
229 | /// # Examples | |
230 | /// | |
041b39d2 | 231 | /// ```no_run |
5bcae85e SL |
232 | /// use std::fs::File; |
233 | /// use std::os::unix::fs::PermissionsExt; | |
234 | /// | |
0531ce1d XL |
235 | /// fn main() -> std::io::Result<()> { |
236 | /// let f = File::create("foo.txt")?; | |
237 | /// let metadata = f.metadata()?; | |
238 | /// let permissions = metadata.permissions(); | |
5bcae85e | 239 | /// |
dc9dc135 | 240 | /// println!("permissions: {:o}", permissions.mode()); |
f035d41b XL |
241 | /// Ok(()) |
242 | /// } | |
5bcae85e | 243 | /// ``` |
d9579d0f | 244 | #[stable(feature = "fs_ext", since = "1.1.0")] |
7453a54e | 245 | fn mode(&self) -> u32; |
d9579d0f | 246 | |
7453a54e | 247 | /// Sets the underlying raw bits for this set of permissions. |
5bcae85e SL |
248 | /// |
249 | /// # Examples | |
250 | /// | |
041b39d2 | 251 | /// ```no_run |
5bcae85e SL |
252 | /// use std::fs::File; |
253 | /// use std::os::unix::fs::PermissionsExt; | |
254 | /// | |
0531ce1d XL |
255 | /// fn main() -> std::io::Result<()> { |
256 | /// let f = File::create("foo.txt")?; | |
257 | /// let metadata = f.metadata()?; | |
258 | /// let mut permissions = metadata.permissions(); | |
5bcae85e | 259 | /// |
0531ce1d XL |
260 | /// permissions.set_mode(0o644); // Read/write for owner and read for others. |
261 | /// assert_eq!(permissions.mode(), 0o644); | |
f035d41b XL |
262 | /// Ok(()) |
263 | /// } | |
5bcae85e | 264 | /// ``` |
d9579d0f | 265 | #[stable(feature = "fs_ext", since = "1.1.0")] |
7453a54e | 266 | fn set_mode(&mut self, mode: u32); |
d9579d0f AL |
267 | |
268 | /// Creates a new instance of `Permissions` from the given set of Unix | |
269 | /// permission bits. | |
5bcae85e SL |
270 | /// |
271 | /// # Examples | |
272 | /// | |
041b39d2 | 273 | /// ``` |
5bcae85e SL |
274 | /// use std::fs::Permissions; |
275 | /// use std::os::unix::fs::PermissionsExt; | |
276 | /// | |
277 | /// // Read/write for owner and read for others. | |
278 | /// let permissions = Permissions::from_mode(0o644); | |
279 | /// assert_eq!(permissions.mode(), 0o644); | |
280 | /// ``` | |
d9579d0f | 281 | #[stable(feature = "fs_ext", since = "1.1.0")] |
7453a54e | 282 | fn from_mode(mode: u32) -> Self; |
d9579d0f AL |
283 | } |
284 | ||
285 | #[stable(feature = "fs_ext", since = "1.1.0")] | |
286 | impl PermissionsExt for Permissions { | |
7453a54e SL |
287 | fn mode(&self) -> u32 { |
288 | self.as_inner().mode() | |
289 | } | |
d9579d0f | 290 | |
7453a54e SL |
291 | fn set_mode(&mut self, mode: u32) { |
292 | *self = Permissions::from_inner(FromInner::from_inner(mode)); | |
d9579d0f AL |
293 | } |
294 | ||
7453a54e SL |
295 | fn from_mode(mode: u32) -> Permissions { |
296 | Permissions::from_inner(FromInner::from_inner(mode)) | |
d9579d0f AL |
297 | } |
298 | } | |
299 | ||
83c7162d | 300 | /// Unix-specific extensions to [`fs::OpenOptions`]. |
d9579d0f AL |
301 | #[stable(feature = "fs_ext", since = "1.1.0")] |
302 | pub trait OpenOptionsExt { | |
303 | /// Sets the mode bits that a new file will be created with. | |
304 | /// | |
60c5eb7d | 305 | /// If a new file is created as part of an `OpenOptions::open` call then this |
d9579d0f | 306 | /// specified `mode` will be used as the permission bits for the new file. |
7453a54e | 307 | /// If no `mode` is set, the default of `0o666` will be used. |
60c5eb7d | 308 | /// The operating system masks out bits with the system's `umask`, to produce |
7453a54e | 309 | /// the final permissions. |
5bcae85e SL |
310 | /// |
311 | /// # Examples | |
312 | /// | |
041b39d2 | 313 | /// ```no_run |
5bcae85e SL |
314 | /// use std::fs::OpenOptions; |
315 | /// use std::os::unix::fs::OpenOptionsExt; | |
316 | /// | |
041b39d2 | 317 | /// # fn main() { |
5bcae85e SL |
318 | /// let mut options = OpenOptions::new(); |
319 | /// options.mode(0o644); // Give read/write for owner and read for others. | |
320 | /// let file = options.open("foo.txt"); | |
041b39d2 | 321 | /// # } |
5bcae85e | 322 | /// ``` |
d9579d0f | 323 | #[stable(feature = "fs_ext", since = "1.1.0")] |
7453a54e SL |
324 | fn mode(&mut self, mode: u32) -> &mut Self; |
325 | ||
3b2f2976 | 326 | /// Pass custom flags to the `flags` argument of `open`. |
7453a54e SL |
327 | /// |
328 | /// The bits that define the access mode are masked out with `O_ACCMODE`, to | |
329 | /// ensure they do not interfere with the access mode set by Rusts options. | |
330 | /// | |
331 | /// Custom flags can only set flags, not remove flags set by Rusts options. | |
332 | /// This options overwrites any previously set custom flags. | |
333 | /// | |
334 | /// # Examples | |
335 | /// | |
041b39d2 | 336 | /// ```no_run |
0731742a | 337 | /// # #![feature(rustc_private)] |
7453a54e SL |
338 | /// extern crate libc; |
339 | /// use std::fs::OpenOptions; | |
340 | /// use std::os::unix::fs::OpenOptionsExt; | |
341 | /// | |
041b39d2 | 342 | /// # fn main() { |
7453a54e SL |
343 | /// let mut options = OpenOptions::new(); |
344 | /// options.write(true); | |
345 | /// if cfg!(unix) { | |
346 | /// options.custom_flags(libc::O_NOFOLLOW); | |
347 | /// } | |
348 | /// let file = options.open("foo.txt"); | |
041b39d2 | 349 | /// # } |
7453a54e | 350 | /// ``` |
a7813a04 | 351 | #[stable(feature = "open_options_ext", since = "1.10.0")] |
7453a54e | 352 | fn custom_flags(&mut self, flags: i32) -> &mut Self; |
d9579d0f AL |
353 | } |
354 | ||
355 | #[stable(feature = "fs_ext", since = "1.1.0")] | |
356 | impl OpenOptionsExt for OpenOptions { | |
7453a54e | 357 | fn mode(&mut self, mode: u32) -> &mut OpenOptions { |
60c5eb7d XL |
358 | self.as_inner_mut().mode(mode); |
359 | self | |
d9579d0f | 360 | } |
7453a54e SL |
361 | |
362 | fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { | |
60c5eb7d XL |
363 | self.as_inner_mut().custom_flags(flags); |
364 | self | |
7453a54e | 365 | } |
d9579d0f AL |
366 | } |
367 | ||
83c7162d | 368 | /// Unix-specific extensions to [`fs::Metadata`]. |
d9579d0f AL |
369 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
370 | pub trait MetadataExt { | |
abe05a73 XL |
371 | /// Returns the ID of the device containing the file. |
372 | /// | |
373 | /// # Examples | |
374 | /// | |
375 | /// ```no_run | |
0531ce1d | 376 | /// use std::io; |
abe05a73 XL |
377 | /// use std::fs; |
378 | /// use std::os::unix::fs::MetadataExt; | |
379 | /// | |
0531ce1d XL |
380 | /// fn main() -> io::Result<()> { |
381 | /// let meta = fs::metadata("some_file")?; | |
382 | /// let dev_id = meta.dev(); | |
383 | /// Ok(()) | |
384 | /// } | |
abe05a73 | 385 | /// ``` |
d9579d0f | 386 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 387 | fn dev(&self) -> u64; |
abe05a73 XL |
388 | /// Returns the inode number. |
389 | /// | |
390 | /// # Examples | |
391 | /// | |
392 | /// ```no_run | |
393 | /// use std::fs; | |
394 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 395 | /// use std::io; |
abe05a73 | 396 | /// |
0531ce1d XL |
397 | /// fn main() -> io::Result<()> { |
398 | /// let meta = fs::metadata("some_file")?; | |
399 | /// let inode = meta.ino(); | |
400 | /// Ok(()) | |
401 | /// } | |
abe05a73 | 402 | /// ``` |
d9579d0f | 403 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 404 | fn ino(&self) -> u64; |
abe05a73 XL |
405 | /// Returns the rights applied to this file. |
406 | /// | |
407 | /// # Examples | |
408 | /// | |
409 | /// ```no_run | |
410 | /// use std::fs; | |
411 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d XL |
412 | /// use std::io; |
413 | /// | |
414 | /// fn main() -> io::Result<()> { | |
415 | /// let meta = fs::metadata("some_file")?; | |
416 | /// let mode = meta.mode(); | |
417 | /// let user_has_write_access = mode & 0o200; | |
418 | /// let user_has_read_write_access = mode & 0o600; | |
419 | /// let group_has_read_access = mode & 0o040; | |
420 | /// let others_have_exec_access = mode & 0o001; | |
421 | /// Ok(()) | |
422 | /// } | |
abe05a73 | 423 | /// ``` |
d9579d0f | 424 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 425 | fn mode(&self) -> u32; |
abe05a73 XL |
426 | /// Returns the number of hard links pointing to this file. |
427 | /// | |
428 | /// # Examples | |
429 | /// | |
430 | /// ```no_run | |
431 | /// use std::fs; | |
432 | /// use std::os::unix::fs::MetadataExt; | |
1b1a35ee | 433 | /// use std::io; |
abe05a73 | 434 | /// |
0531ce1d XL |
435 | /// fn main() -> io::Result<()> { |
436 | /// let meta = fs::metadata("some_file")?; | |
437 | /// let nb_hard_links = meta.nlink(); | |
438 | /// Ok(()) | |
439 | /// } | |
abe05a73 | 440 | /// ``` |
d9579d0f | 441 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 442 | fn nlink(&self) -> u64; |
abe05a73 XL |
443 | /// Returns the user ID of the owner of this file. |
444 | /// | |
445 | /// # Examples | |
446 | /// | |
447 | /// ```no_run | |
448 | /// use std::fs; | |
449 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 450 | /// use std::io; |
abe05a73 | 451 | /// |
0531ce1d XL |
452 | /// fn main() -> io::Result<()> { |
453 | /// let meta = fs::metadata("some_file")?; | |
454 | /// let user_id = meta.uid(); | |
455 | /// Ok(()) | |
456 | /// } | |
abe05a73 | 457 | /// ``` |
d9579d0f | 458 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 459 | fn uid(&self) -> u32; |
abe05a73 XL |
460 | /// Returns the group ID of the owner of this file. |
461 | /// | |
462 | /// # Examples | |
463 | /// | |
464 | /// ```no_run | |
465 | /// use std::fs; | |
466 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 467 | /// use std::io; |
abe05a73 | 468 | /// |
0531ce1d XL |
469 | /// fn main() -> io::Result<()> { |
470 | /// let meta = fs::metadata("some_file")?; | |
471 | /// let group_id = meta.gid(); | |
472 | /// Ok(()) | |
473 | /// } | |
abe05a73 | 474 | /// ``` |
d9579d0f | 475 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 476 | fn gid(&self) -> u32; |
abe05a73 XL |
477 | /// Returns the device ID of this file (if it is a special one). |
478 | /// | |
479 | /// # Examples | |
480 | /// | |
481 | /// ```no_run | |
482 | /// use std::fs; | |
483 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 484 | /// use std::io; |
abe05a73 | 485 | /// |
0531ce1d XL |
486 | /// fn main() -> io::Result<()> { |
487 | /// let meta = fs::metadata("some_file")?; | |
488 | /// let device_id = meta.rdev(); | |
489 | /// Ok(()) | |
490 | /// } | |
abe05a73 | 491 | /// ``` |
d9579d0f | 492 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 493 | fn rdev(&self) -> u64; |
abe05a73 XL |
494 | /// Returns the total size of this file in bytes. |
495 | /// | |
496 | /// # Examples | |
497 | /// | |
498 | /// ```no_run | |
499 | /// use std::fs; | |
500 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 501 | /// use std::io; |
abe05a73 | 502 | /// |
0531ce1d XL |
503 | /// fn main() -> io::Result<()> { |
504 | /// let meta = fs::metadata("some_file")?; | |
505 | /// let file_size = meta.size(); | |
506 | /// Ok(()) | |
507 | /// } | |
abe05a73 | 508 | /// ``` |
d9579d0f | 509 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 510 | fn size(&self) -> u64; |
a1dfa0c6 | 511 | /// Returns the last access time of the file, in seconds since Unix Epoch. |
abe05a73 XL |
512 | /// |
513 | /// # Examples | |
514 | /// | |
515 | /// ```no_run | |
516 | /// use std::fs; | |
517 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 518 | /// use std::io; |
abe05a73 | 519 | /// |
0531ce1d XL |
520 | /// fn main() -> io::Result<()> { |
521 | /// let meta = fs::metadata("some_file")?; | |
522 | /// let last_access_time = meta.atime(); | |
523 | /// Ok(()) | |
524 | /// } | |
abe05a73 | 525 | /// ``` |
d9579d0f | 526 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 527 | fn atime(&self) -> i64; |
a1dfa0c6 XL |
528 | /// Returns the last access time of the file, in nanoseconds since [`atime`]. |
529 | /// | |
3dfed10e | 530 | /// [`atime`]: MetadataExt::atime |
abe05a73 XL |
531 | /// |
532 | /// # Examples | |
533 | /// | |
534 | /// ```no_run | |
535 | /// use std::fs; | |
536 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 537 | /// use std::io; |
abe05a73 | 538 | /// |
0531ce1d XL |
539 | /// fn main() -> io::Result<()> { |
540 | /// let meta = fs::metadata("some_file")?; | |
541 | /// let nano_last_access_time = meta.atime_nsec(); | |
542 | /// Ok(()) | |
543 | /// } | |
abe05a73 | 544 | /// ``` |
d9579d0f | 545 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 546 | fn atime_nsec(&self) -> i64; |
a1dfa0c6 | 547 | /// Returns the last modification time of the file, in seconds since Unix Epoch. |
abe05a73 XL |
548 | /// |
549 | /// # Examples | |
550 | /// | |
551 | /// ```no_run | |
552 | /// use std::fs; | |
553 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 554 | /// use std::io; |
abe05a73 | 555 | /// |
0531ce1d XL |
556 | /// fn main() -> io::Result<()> { |
557 | /// let meta = fs::metadata("some_file")?; | |
558 | /// let last_modification_time = meta.mtime(); | |
559 | /// Ok(()) | |
560 | /// } | |
abe05a73 | 561 | /// ``` |
d9579d0f | 562 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 563 | fn mtime(&self) -> i64; |
a1dfa0c6 XL |
564 | /// Returns the last modification time of the file, in nanoseconds since [`mtime`]. |
565 | /// | |
3dfed10e | 566 | /// [`mtime`]: MetadataExt::mtime |
abe05a73 XL |
567 | /// |
568 | /// # Examples | |
569 | /// | |
570 | /// ```no_run | |
571 | /// use std::fs; | |
572 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 573 | /// use std::io; |
abe05a73 | 574 | /// |
0531ce1d XL |
575 | /// fn main() -> io::Result<()> { |
576 | /// let meta = fs::metadata("some_file")?; | |
577 | /// let nano_last_modification_time = meta.mtime_nsec(); | |
578 | /// Ok(()) | |
579 | /// } | |
abe05a73 | 580 | /// ``` |
d9579d0f | 581 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 582 | fn mtime_nsec(&self) -> i64; |
a1dfa0c6 | 583 | /// Returns the last status change time of the file, in seconds since Unix Epoch. |
abe05a73 XL |
584 | /// |
585 | /// # Examples | |
586 | /// | |
587 | /// ```no_run | |
588 | /// use std::fs; | |
589 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 590 | /// use std::io; |
abe05a73 | 591 | /// |
0531ce1d XL |
592 | /// fn main() -> io::Result<()> { |
593 | /// let meta = fs::metadata("some_file")?; | |
594 | /// let last_status_change_time = meta.ctime(); | |
595 | /// Ok(()) | |
596 | /// } | |
abe05a73 | 597 | /// ``` |
d9579d0f | 598 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 599 | fn ctime(&self) -> i64; |
a1dfa0c6 XL |
600 | /// Returns the last status change time of the file, in nanoseconds since [`ctime`]. |
601 | /// | |
3dfed10e | 602 | /// [`ctime`]: MetadataExt::ctime |
abe05a73 XL |
603 | /// |
604 | /// # Examples | |
605 | /// | |
606 | /// ```no_run | |
607 | /// use std::fs; | |
608 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 609 | /// use std::io; |
abe05a73 | 610 | /// |
0531ce1d XL |
611 | /// fn main() -> io::Result<()> { |
612 | /// let meta = fs::metadata("some_file")?; | |
613 | /// let nano_last_status_change_time = meta.ctime_nsec(); | |
614 | /// Ok(()) | |
615 | /// } | |
abe05a73 | 616 | /// ``` |
d9579d0f | 617 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 618 | fn ctime_nsec(&self) -> i64; |
3dfed10e | 619 | /// Returns the block size for filesystem I/O. |
abe05a73 XL |
620 | /// |
621 | /// # Examples | |
622 | /// | |
623 | /// ```no_run | |
624 | /// use std::fs; | |
625 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 626 | /// use std::io; |
abe05a73 | 627 | /// |
0531ce1d XL |
628 | /// fn main() -> io::Result<()> { |
629 | /// let meta = fs::metadata("some_file")?; | |
3dfed10e | 630 | /// let block_size = meta.blksize(); |
0531ce1d XL |
631 | /// Ok(()) |
632 | /// } | |
abe05a73 | 633 | /// ``` |
d9579d0f | 634 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 635 | fn blksize(&self) -> u64; |
abe05a73 XL |
636 | /// Returns the number of blocks allocated to the file, in 512-byte units. |
637 | /// | |
638 | /// Please note that this may be smaller than `st_size / 512` when the file has holes. | |
639 | /// | |
640 | /// # Examples | |
641 | /// | |
642 | /// ```no_run | |
643 | /// use std::fs; | |
644 | /// use std::os::unix::fs::MetadataExt; | |
0531ce1d | 645 | /// use std::io; |
abe05a73 | 646 | /// |
0531ce1d XL |
647 | /// fn main() -> io::Result<()> { |
648 | /// let meta = fs::metadata("some_file")?; | |
649 | /// let blocks = meta.blocks(); | |
650 | /// Ok(()) | |
651 | /// } | |
abe05a73 | 652 | /// ``` |
d9579d0f | 653 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
7453a54e | 654 | fn blocks(&self) -> u64; |
29967ef6 XL |
655 | #[cfg(target_os = "vxworks")] |
656 | #[stable(feature = "metadata_ext", since = "1.1.0")] | |
657 | fn attrib(&self) -> u8; | |
d9579d0f AL |
658 | } |
659 | ||
92a42be0 | 660 | #[stable(feature = "metadata_ext", since = "1.1.0")] |
d9579d0f | 661 | impl MetadataExt for fs::Metadata { |
60c5eb7d XL |
662 | fn dev(&self) -> u64 { |
663 | self.st_dev() | |
664 | } | |
665 | fn ino(&self) -> u64 { | |
666 | self.st_ino() | |
667 | } | |
668 | fn mode(&self) -> u32 { | |
669 | self.st_mode() | |
670 | } | |
671 | fn nlink(&self) -> u64 { | |
672 | self.st_nlink() | |
673 | } | |
674 | fn uid(&self) -> u32 { | |
675 | self.st_uid() | |
676 | } | |
677 | fn gid(&self) -> u32 { | |
678 | self.st_gid() | |
679 | } | |
680 | fn rdev(&self) -> u64 { | |
681 | self.st_rdev() | |
682 | } | |
683 | fn size(&self) -> u64 { | |
684 | self.st_size() | |
685 | } | |
686 | fn atime(&self) -> i64 { | |
687 | self.st_atime() | |
688 | } | |
689 | fn atime_nsec(&self) -> i64 { | |
690 | self.st_atime_nsec() | |
691 | } | |
692 | fn mtime(&self) -> i64 { | |
693 | self.st_mtime() | |
694 | } | |
695 | fn mtime_nsec(&self) -> i64 { | |
696 | self.st_mtime_nsec() | |
697 | } | |
698 | fn ctime(&self) -> i64 { | |
699 | self.st_ctime() | |
700 | } | |
701 | fn ctime_nsec(&self) -> i64 { | |
702 | self.st_ctime_nsec() | |
703 | } | |
704 | fn blksize(&self) -> u64 { | |
705 | self.st_blksize() | |
706 | } | |
707 | fn blocks(&self) -> u64 { | |
708 | self.st_blocks() | |
709 | } | |
29967ef6 XL |
710 | #[cfg(target_os = "vxworks")] |
711 | fn attrib(&self) -> u8 { | |
712 | self.st_attrib() | |
713 | } | |
d9579d0f AL |
714 | } |
715 | ||
3dfed10e | 716 | /// Unix-specific extensions for [`fs::FileType`]. |
83c7162d XL |
717 | /// |
718 | /// Adds support for special Unix file types such as block/character devices, | |
719 | /// pipes, and sockets. | |
b039eaaf | 720 | #[stable(feature = "file_type_ext", since = "1.5.0")] |
c1a9b12d | 721 | pub trait FileTypeExt { |
9fa01778 | 722 | /// Returns `true` if this file type is a block device. |
abe05a73 XL |
723 | /// |
724 | /// # Examples | |
725 | /// | |
0531ce1d | 726 | /// ```no_run |
abe05a73 XL |
727 | /// use std::fs; |
728 | /// use std::os::unix::fs::FileTypeExt; | |
0531ce1d | 729 | /// use std::io; |
abe05a73 | 730 | /// |
0531ce1d XL |
731 | /// fn main() -> io::Result<()> { |
732 | /// let meta = fs::metadata("block_device_file")?; | |
733 | /// let file_type = meta.file_type(); | |
734 | /// assert!(file_type.is_block_device()); | |
735 | /// Ok(()) | |
736 | /// } | |
abe05a73 | 737 | /// ``` |
b039eaaf | 738 | #[stable(feature = "file_type_ext", since = "1.5.0")] |
c1a9b12d | 739 | fn is_block_device(&self) -> bool; |
9fa01778 | 740 | /// Returns `true` if this file type is a char device. |
abe05a73 XL |
741 | /// |
742 | /// # Examples | |
743 | /// | |
0531ce1d | 744 | /// ```no_run |
abe05a73 XL |
745 | /// use std::fs; |
746 | /// use std::os::unix::fs::FileTypeExt; | |
0531ce1d | 747 | /// use std::io; |
abe05a73 | 748 | /// |
0531ce1d XL |
749 | /// fn main() -> io::Result<()> { |
750 | /// let meta = fs::metadata("char_device_file")?; | |
751 | /// let file_type = meta.file_type(); | |
752 | /// assert!(file_type.is_char_device()); | |
753 | /// Ok(()) | |
754 | /// } | |
abe05a73 | 755 | /// ``` |
b039eaaf | 756 | #[stable(feature = "file_type_ext", since = "1.5.0")] |
c1a9b12d | 757 | fn is_char_device(&self) -> bool; |
9fa01778 | 758 | /// Returns `true` if this file type is a fifo. |
abe05a73 XL |
759 | /// |
760 | /// # Examples | |
761 | /// | |
0531ce1d | 762 | /// ```no_run |
abe05a73 XL |
763 | /// use std::fs; |
764 | /// use std::os::unix::fs::FileTypeExt; | |
0531ce1d | 765 | /// use std::io; |
abe05a73 | 766 | /// |
0531ce1d XL |
767 | /// fn main() -> io::Result<()> { |
768 | /// let meta = fs::metadata("fifo_file")?; | |
769 | /// let file_type = meta.file_type(); | |
770 | /// assert!(file_type.is_fifo()); | |
771 | /// Ok(()) | |
772 | /// } | |
abe05a73 | 773 | /// ``` |
b039eaaf | 774 | #[stable(feature = "file_type_ext", since = "1.5.0")] |
c1a9b12d | 775 | fn is_fifo(&self) -> bool; |
9fa01778 | 776 | /// Returns `true` if this file type is a socket. |
abe05a73 XL |
777 | /// |
778 | /// # Examples | |
779 | /// | |
0531ce1d | 780 | /// ```no_run |
abe05a73 XL |
781 | /// use std::fs; |
782 | /// use std::os::unix::fs::FileTypeExt; | |
0531ce1d | 783 | /// use std::io; |
abe05a73 | 784 | /// |
0531ce1d XL |
785 | /// fn main() -> io::Result<()> { |
786 | /// let meta = fs::metadata("unix.socket")?; | |
787 | /// let file_type = meta.file_type(); | |
788 | /// assert!(file_type.is_socket()); | |
789 | /// Ok(()) | |
790 | /// } | |
abe05a73 | 791 | /// ``` |
b039eaaf | 792 | #[stable(feature = "file_type_ext", since = "1.5.0")] |
c1a9b12d SL |
793 | fn is_socket(&self) -> bool; |
794 | } | |
795 | ||
b039eaaf | 796 | #[stable(feature = "file_type_ext", since = "1.5.0")] |
c1a9b12d | 797 | impl FileTypeExt for fs::FileType { |
60c5eb7d XL |
798 | fn is_block_device(&self) -> bool { |
799 | self.as_inner().is(libc::S_IFBLK) | |
800 | } | |
801 | fn is_char_device(&self) -> bool { | |
802 | self.as_inner().is(libc::S_IFCHR) | |
803 | } | |
804 | fn is_fifo(&self) -> bool { | |
805 | self.as_inner().is(libc::S_IFIFO) | |
806 | } | |
807 | fn is_socket(&self) -> bool { | |
808 | self.as_inner().is(libc::S_IFSOCK) | |
809 | } | |
c1a9b12d SL |
810 | } |
811 | ||
abe05a73 | 812 | /// Unix-specific extension methods for [`fs::DirEntry`]. |
d9579d0f AL |
813 | #[stable(feature = "dir_entry_ext", since = "1.1.0")] |
814 | pub trait DirEntryExt { | |
815 | /// Returns the underlying `d_ino` field in the contained `dirent` | |
816 | /// structure. | |
5bcae85e SL |
817 | /// |
818 | /// # Examples | |
819 | /// | |
820 | /// ``` | |
821 | /// use std::fs; | |
822 | /// use std::os::unix::fs::DirEntryExt; | |
823 | /// | |
824 | /// if let Ok(entries) = fs::read_dir(".") { | |
825 | /// for entry in entries { | |
826 | /// if let Ok(entry) = entry { | |
827 | /// // Here, `entry` is a `DirEntry`. | |
828 | /// println!("{:?}: {}", entry.file_name(), entry.ino()); | |
829 | /// } | |
830 | /// } | |
831 | /// } | |
832 | /// ``` | |
d9579d0f | 833 | #[stable(feature = "dir_entry_ext", since = "1.1.0")] |
7453a54e | 834 | fn ino(&self) -> u64; |
d9579d0f AL |
835 | } |
836 | ||
92a42be0 | 837 | #[stable(feature = "dir_entry_ext", since = "1.1.0")] |
d9579d0f | 838 | impl DirEntryExt for fs::DirEntry { |
60c5eb7d XL |
839 | fn ino(&self) -> u64 { |
840 | self.as_inner().ino() | |
841 | } | |
d9579d0f AL |
842 | } |
843 | ||
136023e0 XL |
844 | /// Sealed Unix-specific extension methods for [`fs::DirEntry`]. |
845 | #[unstable(feature = "dir_entry_ext2", issue = "85573")] | |
846 | pub trait DirEntryExt2: Sealed { | |
847 | /// Returns a reference to the underlying `OsStr` of this entry's filename. | |
848 | /// | |
849 | /// # Examples | |
850 | /// | |
851 | /// ``` | |
852 | /// #![feature(dir_entry_ext2)] | |
853 | /// use std::os::unix::fs::DirEntryExt2; | |
854 | /// use std::{fs, io}; | |
855 | /// | |
856 | /// fn main() -> io::Result<()> { | |
857 | /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?; | |
858 | /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref())); | |
859 | /// | |
860 | /// for p in entries { | |
861 | /// println!("{:?}", p); | |
862 | /// } | |
863 | /// | |
864 | /// Ok(()) | |
865 | /// } | |
866 | /// ``` | |
867 | fn file_name_ref(&self) -> &OsStr; | |
868 | } | |
869 | ||
870 | /// Allows extension traits within `std`. | |
871 | #[unstable(feature = "sealed", issue = "none")] | |
872 | impl Sealed for fs::DirEntry {} | |
873 | ||
874 | #[unstable(feature = "dir_entry_ext2", issue = "85573")] | |
875 | impl DirEntryExt2 for fs::DirEntry { | |
876 | fn file_name_ref(&self) -> &OsStr { | |
877 | self.as_inner().file_name_os_str() | |
878 | } | |
879 | } | |
880 | ||
d9579d0f AL |
881 | /// Creates a new symbolic link on the filesystem. |
882 | /// | |
fc512014 | 883 | /// The `link` path will be a symbolic link pointing to the `original` path. |
d9579d0f | 884 | /// |
d9579d0f AL |
885 | /// # Examples |
886 | /// | |
0531ce1d | 887 | /// ```no_run |
d9579d0f AL |
888 | /// use std::os::unix::fs; |
889 | /// | |
0531ce1d XL |
890 | /// fn main() -> std::io::Result<()> { |
891 | /// fs::symlink("a.txt", "b.txt")?; | |
892 | /// Ok(()) | |
893 | /// } | |
d9579d0f | 894 | /// ``` |
62682a34 | 895 | #[stable(feature = "symlink", since = "1.1.0")] |
fc512014 XL |
896 | pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> { |
897 | sys::fs::symlink(original.as_ref(), link.as_ref()) | |
d9579d0f AL |
898 | } |
899 | ||
83c7162d | 900 | /// Unix-specific extensions to [`fs::DirBuilder`]. |
83c7162d | 901 | #[stable(feature = "dir_builder", since = "1.6.0")] |
d9579d0f AL |
902 | pub trait DirBuilderExt { |
903 | /// Sets the mode to create new directories with. This option defaults to | |
904 | /// 0o777. | |
5bcae85e SL |
905 | /// |
906 | /// # Examples | |
907 | /// | |
041b39d2 | 908 | /// ```no_run |
5bcae85e SL |
909 | /// use std::fs::DirBuilder; |
910 | /// use std::os::unix::fs::DirBuilderExt; | |
911 | /// | |
912 | /// let mut builder = DirBuilder::new(); | |
913 | /// builder.mode(0o755); | |
914 | /// ``` | |
92a42be0 | 915 | #[stable(feature = "dir_builder", since = "1.6.0")] |
7453a54e | 916 | fn mode(&mut self, mode: u32) -> &mut Self; |
d9579d0f AL |
917 | } |
918 | ||
92a42be0 | 919 | #[stable(feature = "dir_builder", since = "1.6.0")] |
d9579d0f | 920 | impl DirBuilderExt for fs::DirBuilder { |
7453a54e | 921 | fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { |
d9579d0f AL |
922 | self.as_inner_mut().set_mode(mode); |
923 | self | |
924 | } | |
925 | } | |
cdc7bbd5 XL |
926 | |
927 | /// Change the root directory of the current process to the specified path. | |
928 | /// | |
929 | /// This typically requires privileges, such as root or a specific capability. | |
930 | /// | |
931 | /// This does not change the current working directory; you should call | |
932 | /// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards. | |
933 | /// | |
934 | /// # Examples | |
935 | /// | |
936 | /// ```no_run | |
cdc7bbd5 XL |
937 | /// use std::os::unix::fs; |
938 | /// | |
939 | /// fn main() -> std::io::Result<()> { | |
940 | /// fs::chroot("/sandbox")?; | |
941 | /// std::env::set_current_dir("/")?; | |
942 | /// // continue working in sandbox | |
943 | /// Ok(()) | |
944 | /// } | |
945 | /// ``` | |
94222f64 | 946 | #[stable(feature = "unix_chroot", since = "1.56.0")] |
17df50a5 | 947 | #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] |
cdc7bbd5 XL |
948 | pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> { |
949 | sys::fs::chroot(dir.as_ref()) | |
950 | } |