1 | //! Unix-specific extensions to primitives in the [`std::fs`] module. |
2 | //! |
3 | //! [`std::fs`]: crate::fs |
4 | |
5 | #![stable (feature = "rust1" , since = "1.0.0" )] |
6 | |
7 | #[allow (unused_imports)] |
8 | use io::{Read, Write}; |
9 | |
10 | use super::platform::fs::MetadataExt as _; |
11 | // Used for `File::read` on intra-doc links |
12 | use crate::ffi::OsStr; |
13 | use crate::fs::{self, OpenOptions, Permissions}; |
14 | use crate::os::unix::io::{AsFd, AsRawFd}; |
15 | use crate::path::Path; |
16 | use crate::sealed::Sealed; |
17 | use crate::sys_common::{AsInner, AsInnerMut, FromInner}; |
18 | use crate::{io, sys}; |
19 | |
20 | // Tests for this module |
21 | #[cfg (test)] |
22 | mod tests; |
23 | |
24 | /// Unix-specific extensions to [`fs::File`]. |
25 | #[stable (feature = "file_offset" , since = "1.15.0" )] |
26 | pub trait FileExt { |
27 | /// Reads a number of bytes starting from a given offset. |
28 | /// |
29 | /// Returns the number of bytes read. |
30 | /// |
31 | /// The offset is relative to the start of the file and thus independent |
32 | /// from the current cursor. |
33 | /// |
34 | /// The current file cursor is not affected by this function. |
35 | /// |
36 | /// Note that similar to [`File::read`], it is not an error to return with a |
37 | /// short read. |
38 | /// |
39 | /// [`File::read`]: fs::File::read |
40 | /// |
41 | /// # Examples |
42 | /// |
43 | /// ```no_run |
44 | /// use std::io; |
45 | /// use std::fs::File; |
46 | /// use std::os::unix::prelude::FileExt; |
47 | /// |
48 | /// fn main() -> io::Result<()> { |
49 | /// let mut buf = [0u8; 8]; |
50 | /// let file = File::open("foo.txt" )?; |
51 | /// |
52 | /// // We now read 8 bytes from the offset 10. |
53 | /// let num_bytes_read = file.read_at(&mut buf, 10)?; |
54 | /// println!("read {num_bytes_read} bytes: {buf:?}" ); |
55 | /// Ok(()) |
56 | /// } |
57 | /// ``` |
58 | #[stable (feature = "file_offset" , since = "1.15.0" )] |
59 | fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; |
60 | |
61 | /// Like `read_at`, except that it reads into a slice of buffers. |
62 | /// |
63 | /// Data is copied to fill each buffer in order, with the final buffer |
64 | /// written to possibly being only partially filled. This method must behave |
65 | /// equivalently to a single call to read with concatenated buffers. |
66 | #[unstable (feature = "unix_file_vectored_at" , issue = "89517" )] |
67 | fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { |
68 | io::default_read_vectored(|b| self.read_at(b, offset), bufs) |
69 | } |
70 | |
71 | /// Reads the exact number of bytes required to fill `buf` from the given offset. |
72 | /// |
73 | /// The offset is relative to the start of the file and thus independent |
74 | /// from the current cursor. |
75 | /// |
76 | /// The current file cursor is not affected by this function. |
77 | /// |
78 | /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`. |
79 | /// |
80 | /// [`read_at`]: FileExt::read_at |
81 | /// |
82 | /// # Errors |
83 | /// |
84 | /// If this function encounters an error of the kind |
85 | /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation |
86 | /// will continue. |
87 | /// |
88 | /// If this function encounters an "end of file" before completely filling |
89 | /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`]. |
90 | /// The contents of `buf` are unspecified in this case. |
91 | /// |
92 | /// If any other read error is encountered then this function immediately |
93 | /// returns. The contents of `buf` are unspecified in this case. |
94 | /// |
95 | /// If this function returns an error, it is unspecified how many bytes it |
96 | /// has read, but it will never read more than would be necessary to |
97 | /// completely fill the buffer. |
98 | /// |
99 | /// # Examples |
100 | /// |
101 | /// ```no_run |
102 | /// use std::io; |
103 | /// use std::fs::File; |
104 | /// use std::os::unix::prelude::FileExt; |
105 | /// |
106 | /// fn main() -> io::Result<()> { |
107 | /// let mut buf = [0u8; 8]; |
108 | /// let file = File::open("foo.txt" )?; |
109 | /// |
110 | /// // We now read exactly 8 bytes from the offset 10. |
111 | /// file.read_exact_at(&mut buf, 10)?; |
112 | /// println!("read {} bytes: {:?}" , buf.len(), buf); |
113 | /// Ok(()) |
114 | /// } |
115 | /// ``` |
116 | #[stable (feature = "rw_exact_all_at" , since = "1.33.0" )] |
117 | fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { |
118 | while !buf.is_empty() { |
119 | match self.read_at(buf, offset) { |
120 | Ok(0) => break, |
121 | Ok(n) => { |
122 | let tmp = buf; |
123 | buf = &mut tmp[n..]; |
124 | offset += n as u64; |
125 | } |
126 | Err(ref e) if e.is_interrupted() => {} |
127 | Err(e) => return Err(e), |
128 | } |
129 | } |
130 | if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } |
131 | } |
132 | |
133 | /// Writes a number of bytes starting from a given offset. |
134 | /// |
135 | /// Returns the number of bytes written. |
136 | /// |
137 | /// The offset is relative to the start of the file and thus independent |
138 | /// from the current cursor. |
139 | /// |
140 | /// The current file cursor is not affected by this function. |
141 | /// |
142 | /// When writing beyond the end of the file, the file is appropriately |
143 | /// extended and the intermediate bytes are initialized with the value 0. |
144 | /// |
145 | /// Note that similar to [`File::write`], it is not an error to return a |
146 | /// short write. |
147 | /// |
148 | /// # Bug |
149 | /// On some systems, `write_at` utilises [`pwrite64`] to write to files. |
150 | /// However, this syscall has a [bug] where files opened with the `O_APPEND` |
151 | /// flag fail to respect the offset parameter, always appending to the end |
152 | /// of the file instead. |
153 | /// |
154 | /// It is possible to inadvertently set this flag, like in the example below. |
155 | /// Therefore, it is important to be vigilant while changing options to mitigate |
156 | /// unexpected behavior. |
157 | /// |
158 | /// ```no_run |
159 | /// use std::fs::File; |
160 | /// use std::io; |
161 | /// use std::os::unix::prelude::FileExt; |
162 | /// |
163 | /// fn main() -> io::Result<()> { |
164 | /// // Open a file with the append option (sets the `O_APPEND` flag) |
165 | /// let file = File::options().append(true).open("foo.txt" )?; |
166 | /// |
167 | /// // We attempt to write at offset 10; instead appended to EOF |
168 | /// file.write_at(b"sushi" , 10)?; |
169 | /// |
170 | /// // foo.txt is 5 bytes long instead of 15 |
171 | /// Ok(()) |
172 | /// } |
173 | /// ``` |
174 | /// |
175 | /// [`File::write`]: fs::File::write |
176 | /// [`pwrite64`]: https://man7.org/linux/man-pages/man2/pwrite.2.html |
177 | /// [bug]: https://man7.org/linux/man-pages/man2/pwrite.2.html#BUGS |
178 | /// |
179 | /// # Examples |
180 | /// |
181 | /// ```no_run |
182 | /// use std::fs::File; |
183 | /// use std::io; |
184 | /// use std::os::unix::prelude::FileExt; |
185 | /// |
186 | /// fn main() -> io::Result<()> { |
187 | /// let file = File::create("foo.txt" )?; |
188 | /// |
189 | /// // We now write at the offset 10. |
190 | /// file.write_at(b"sushi" , 10)?; |
191 | /// Ok(()) |
192 | /// } |
193 | /// ``` |
194 | #[stable (feature = "file_offset" , since = "1.15.0" )] |
195 | fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; |
196 | |
197 | /// Like `write_at`, except that it writes from a slice of buffers. |
198 | /// |
199 | /// Data is copied from each buffer in order, with the final buffer read |
200 | /// from possibly being only partially consumed. This method must behave as |
201 | /// a call to `write_at` with the buffers concatenated would. |
202 | #[unstable (feature = "unix_file_vectored_at" , issue = "89517" )] |
203 | fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> { |
204 | io::default_write_vectored(|b| self.write_at(b, offset), bufs) |
205 | } |
206 | |
207 | /// Attempts to write an entire buffer starting from a given offset. |
208 | /// |
209 | /// The offset is relative to the start of the file and thus independent |
210 | /// from the current cursor. |
211 | /// |
212 | /// The current file cursor is not affected by this function. |
213 | /// |
214 | /// This method will continuously call [`write_at`] until there is no more data |
215 | /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is |
216 | /// returned. This method will not return until the entire buffer has been |
217 | /// successfully written or such an error occurs. The first error that is |
218 | /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be |
219 | /// returned. |
220 | /// |
221 | /// # Errors |
222 | /// |
223 | /// This function will return the first error of |
224 | /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns. |
225 | /// |
226 | /// [`write_at`]: FileExt::write_at |
227 | /// |
228 | /// # Examples |
229 | /// |
230 | /// ```no_run |
231 | /// use std::fs::File; |
232 | /// use std::io; |
233 | /// use std::os::unix::prelude::FileExt; |
234 | /// |
235 | /// fn main() -> io::Result<()> { |
236 | /// let file = File::open("foo.txt" )?; |
237 | /// |
238 | /// // We now write at the offset 10. |
239 | /// file.write_all_at(b"sushi" , 10)?; |
240 | /// Ok(()) |
241 | /// } |
242 | /// ``` |
243 | #[stable (feature = "rw_exact_all_at" , since = "1.33.0" )] |
244 | fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { |
245 | while !buf.is_empty() { |
246 | match self.write_at(buf, offset) { |
247 | Ok(0) => { |
248 | return Err(io::Error::WRITE_ALL_EOF); |
249 | } |
250 | Ok(n) => { |
251 | buf = &buf[n..]; |
252 | offset += n as u64 |
253 | } |
254 | Err(ref e) if e.is_interrupted() => {} |
255 | Err(e) => return Err(e), |
256 | } |
257 | } |
258 | Ok(()) |
259 | } |
260 | } |
261 | |
262 | #[stable (feature = "file_offset" , since = "1.15.0" )] |
263 | impl FileExt for fs::File { |
264 | fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { |
265 | self.as_inner().read_at(buf, offset) |
266 | } |
267 | fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { |
268 | self.as_inner().read_vectored_at(bufs, offset) |
269 | } |
270 | fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
271 | self.as_inner().write_at(buf, offset) |
272 | } |
273 | fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> { |
274 | self.as_inner().write_vectored_at(bufs, offset) |
275 | } |
276 | } |
277 | |
278 | /// Unix-specific extensions to [`fs::Permissions`]. |
279 | /// |
280 | /// # Examples |
281 | /// |
282 | /// ```no_run |
283 | /// use std::fs::{File, Permissions}; |
284 | /// use std::io::{ErrorKind, Result as IoResult}; |
285 | /// use std::os::unix::fs::PermissionsExt; |
286 | /// |
287 | /// fn main() -> IoResult<()> { |
288 | /// let name = "test_file_for_permissions" ; |
289 | /// |
290 | /// // make sure file does not exist |
291 | /// let _ = std::fs::remove_file(name); |
292 | /// assert_eq!( |
293 | /// File::open(name).unwrap_err().kind(), |
294 | /// ErrorKind::NotFound, |
295 | /// "file already exists" |
296 | /// ); |
297 | /// |
298 | /// // full read/write/execute mode bits for owner of file |
299 | /// // that we want to add to existing mode bits |
300 | /// let my_mode = 0o700; |
301 | /// |
302 | /// // create new file with specified permissions |
303 | /// { |
304 | /// let file = File::create(name)?; |
305 | /// let mut permissions = file.metadata()?.permissions(); |
306 | /// eprintln!("Current permissions: {:o}" , permissions.mode()); |
307 | /// |
308 | /// // make sure new permissions are not already set |
309 | /// assert!( |
310 | /// permissions.mode() & my_mode != my_mode, |
311 | /// "permissions already set" |
312 | /// ); |
313 | /// |
314 | /// // either use `set_mode` to change an existing Permissions struct |
315 | /// permissions.set_mode(permissions.mode() | my_mode); |
316 | /// |
317 | /// // or use `from_mode` to construct a new Permissions struct |
318 | /// permissions = Permissions::from_mode(permissions.mode() | my_mode); |
319 | /// |
320 | /// // write new permissions to file |
321 | /// file.set_permissions(permissions)?; |
322 | /// } |
323 | /// |
324 | /// let permissions = File::open(name)?.metadata()?.permissions(); |
325 | /// eprintln!("New permissions: {:o}" , permissions.mode()); |
326 | /// |
327 | /// // assert new permissions were set |
328 | /// assert_eq!( |
329 | /// permissions.mode() & my_mode, |
330 | /// my_mode, |
331 | /// "new permissions not set" |
332 | /// ); |
333 | /// Ok(()) |
334 | /// } |
335 | /// ``` |
336 | /// |
337 | /// ```no_run |
338 | /// use std::fs::Permissions; |
339 | /// use std::os::unix::fs::PermissionsExt; |
340 | /// |
341 | /// // read/write for owner and read for others |
342 | /// let my_mode = 0o644; |
343 | /// let mut permissions = Permissions::from_mode(my_mode); |
344 | /// assert_eq!(permissions.mode(), my_mode); |
345 | /// |
346 | /// // read/write/execute for owner |
347 | /// let other_mode = 0o700; |
348 | /// permissions.set_mode(other_mode); |
349 | /// assert_eq!(permissions.mode(), other_mode); |
350 | /// ``` |
351 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
352 | pub trait PermissionsExt { |
353 | /// Returns the mode permission bits |
354 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
355 | fn mode(&self) -> u32; |
356 | |
357 | /// Sets the mode permission bits. |
358 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
359 | fn set_mode(&mut self, mode: u32); |
360 | |
361 | /// Creates a new instance from the given mode permission bits. |
362 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
363 | #[cfg_attr (not(test), rustc_diagnostic_item = "permissions_from_mode" )] |
364 | fn from_mode(mode: u32) -> Self; |
365 | } |
366 | |
367 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
368 | impl PermissionsExt for Permissions { |
369 | fn mode(&self) -> u32 { |
370 | self.as_inner().mode() |
371 | } |
372 | |
373 | fn set_mode(&mut self, mode: u32) { |
374 | *self = Permissions::from_inner(FromInner::from_inner(mode)); |
375 | } |
376 | |
377 | fn from_mode(mode: u32) -> Permissions { |
378 | Permissions::from_inner(FromInner::from_inner(mode)) |
379 | } |
380 | } |
381 | |
382 | /// Unix-specific extensions to [`fs::OpenOptions`]. |
383 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
384 | pub trait OpenOptionsExt { |
385 | /// Sets the mode bits that a new file will be created with. |
386 | /// |
387 | /// If a new file is created as part of an `OpenOptions::open` call then this |
388 | /// specified `mode` will be used as the permission bits for the new file. |
389 | /// If no `mode` is set, the default of `0o666` will be used. |
390 | /// The operating system masks out bits with the system's `umask`, to produce |
391 | /// the final permissions. |
392 | /// |
393 | /// # Examples |
394 | /// |
395 | /// ```no_run |
396 | /// use std::fs::OpenOptions; |
397 | /// use std::os::unix::fs::OpenOptionsExt; |
398 | /// |
399 | /// # fn main() { |
400 | /// let mut options = OpenOptions::new(); |
401 | /// options.mode(0o644); // Give read/write for owner and read for others. |
402 | /// let file = options.open("foo.txt" ); |
403 | /// # } |
404 | /// ``` |
405 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
406 | fn mode(&mut self, mode: u32) -> &mut Self; |
407 | |
408 | /// Pass custom flags to the `flags` argument of `open`. |
409 | /// |
410 | /// The bits that define the access mode are masked out with `O_ACCMODE`, to |
411 | /// ensure they do not interfere with the access mode set by Rusts options. |
412 | /// |
413 | /// Custom flags can only set flags, not remove flags set by Rusts options. |
414 | /// This options overwrites any previously set custom flags. |
415 | /// |
416 | /// # Examples |
417 | /// |
418 | /// ```no_run |
419 | /// # #![feature (rustc_private)] |
420 | /// use std::fs::OpenOptions; |
421 | /// use std::os::unix::fs::OpenOptionsExt; |
422 | /// |
423 | /// # fn main() { |
424 | /// let mut options = OpenOptions::new(); |
425 | /// options.write(true); |
426 | /// if cfg!(unix) { |
427 | /// options.custom_flags(libc::O_NOFOLLOW); |
428 | /// } |
429 | /// let file = options.open("foo.txt" ); |
430 | /// # } |
431 | /// ``` |
432 | #[stable (feature = "open_options_ext" , since = "1.10.0" )] |
433 | fn custom_flags(&mut self, flags: i32) -> &mut Self; |
434 | } |
435 | |
436 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
437 | impl OpenOptionsExt for OpenOptions { |
438 | fn mode(&mut self, mode: u32) -> &mut OpenOptions { |
439 | self.as_inner_mut().mode(mode); |
440 | self |
441 | } |
442 | |
443 | fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { |
444 | self.as_inner_mut().custom_flags(flags); |
445 | self |
446 | } |
447 | } |
448 | |
449 | /// Unix-specific extensions to [`fs::Metadata`]. |
450 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
451 | pub trait MetadataExt { |
452 | /// Returns the ID of the device containing the file. |
453 | /// |
454 | /// # Examples |
455 | /// |
456 | /// ```no_run |
457 | /// use std::io; |
458 | /// use std::fs; |
459 | /// use std::os::unix::fs::MetadataExt; |
460 | /// |
461 | /// fn main() -> io::Result<()> { |
462 | /// let meta = fs::metadata("some_file" )?; |
463 | /// let dev_id = meta.dev(); |
464 | /// Ok(()) |
465 | /// } |
466 | /// ``` |
467 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
468 | fn dev(&self) -> u64; |
469 | /// Returns the inode number. |
470 | /// |
471 | /// # Examples |
472 | /// |
473 | /// ```no_run |
474 | /// use std::fs; |
475 | /// use std::os::unix::fs::MetadataExt; |
476 | /// use std::io; |
477 | /// |
478 | /// fn main() -> io::Result<()> { |
479 | /// let meta = fs::metadata("some_file" )?; |
480 | /// let inode = meta.ino(); |
481 | /// Ok(()) |
482 | /// } |
483 | /// ``` |
484 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
485 | fn ino(&self) -> u64; |
486 | /// Returns the rights applied to this file. |
487 | /// |
488 | /// # Examples |
489 | /// |
490 | /// ```no_run |
491 | /// use std::fs; |
492 | /// use std::os::unix::fs::MetadataExt; |
493 | /// use std::io; |
494 | /// |
495 | /// fn main() -> io::Result<()> { |
496 | /// let meta = fs::metadata("some_file" )?; |
497 | /// let mode = meta.mode(); |
498 | /// let user_has_write_access = mode & 0o200; |
499 | /// let user_has_read_write_access = mode & 0o600; |
500 | /// let group_has_read_access = mode & 0o040; |
501 | /// let others_have_exec_access = mode & 0o001; |
502 | /// Ok(()) |
503 | /// } |
504 | /// ``` |
505 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
506 | fn mode(&self) -> u32; |
507 | /// Returns the number of hard links pointing to this file. |
508 | /// |
509 | /// # Examples |
510 | /// |
511 | /// ```no_run |
512 | /// use std::fs; |
513 | /// use std::os::unix::fs::MetadataExt; |
514 | /// use std::io; |
515 | /// |
516 | /// fn main() -> io::Result<()> { |
517 | /// let meta = fs::metadata("some_file" )?; |
518 | /// let nb_hard_links = meta.nlink(); |
519 | /// Ok(()) |
520 | /// } |
521 | /// ``` |
522 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
523 | fn nlink(&self) -> u64; |
524 | /// Returns the user ID of the owner of this file. |
525 | /// |
526 | /// # Examples |
527 | /// |
528 | /// ```no_run |
529 | /// use std::fs; |
530 | /// use std::os::unix::fs::MetadataExt; |
531 | /// use std::io; |
532 | /// |
533 | /// fn main() -> io::Result<()> { |
534 | /// let meta = fs::metadata("some_file" )?; |
535 | /// let user_id = meta.uid(); |
536 | /// Ok(()) |
537 | /// } |
538 | /// ``` |
539 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
540 | fn uid(&self) -> u32; |
541 | /// Returns the group ID of the owner of this file. |
542 | /// |
543 | /// # Examples |
544 | /// |
545 | /// ```no_run |
546 | /// use std::fs; |
547 | /// use std::os::unix::fs::MetadataExt; |
548 | /// use std::io; |
549 | /// |
550 | /// fn main() -> io::Result<()> { |
551 | /// let meta = fs::metadata("some_file" )?; |
552 | /// let group_id = meta.gid(); |
553 | /// Ok(()) |
554 | /// } |
555 | /// ``` |
556 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
557 | fn gid(&self) -> u32; |
558 | /// Returns the device ID of this file (if it is a special one). |
559 | /// |
560 | /// # Examples |
561 | /// |
562 | /// ```no_run |
563 | /// use std::fs; |
564 | /// use std::os::unix::fs::MetadataExt; |
565 | /// use std::io; |
566 | /// |
567 | /// fn main() -> io::Result<()> { |
568 | /// let meta = fs::metadata("some_file" )?; |
569 | /// let device_id = meta.rdev(); |
570 | /// Ok(()) |
571 | /// } |
572 | /// ``` |
573 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
574 | fn rdev(&self) -> u64; |
575 | /// Returns the total size of this file in bytes. |
576 | /// |
577 | /// # Examples |
578 | /// |
579 | /// ```no_run |
580 | /// use std::fs; |
581 | /// use std::os::unix::fs::MetadataExt; |
582 | /// use std::io; |
583 | /// |
584 | /// fn main() -> io::Result<()> { |
585 | /// let meta = fs::metadata("some_file" )?; |
586 | /// let file_size = meta.size(); |
587 | /// Ok(()) |
588 | /// } |
589 | /// ``` |
590 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
591 | fn size(&self) -> u64; |
592 | /// Returns the last access time of the file, in seconds since Unix Epoch. |
593 | /// |
594 | /// # Examples |
595 | /// |
596 | /// ```no_run |
597 | /// use std::fs; |
598 | /// use std::os::unix::fs::MetadataExt; |
599 | /// use std::io; |
600 | /// |
601 | /// fn main() -> io::Result<()> { |
602 | /// let meta = fs::metadata("some_file" )?; |
603 | /// let last_access_time = meta.atime(); |
604 | /// Ok(()) |
605 | /// } |
606 | /// ``` |
607 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
608 | fn atime(&self) -> i64; |
609 | /// Returns the last access time of the file, in nanoseconds since [`atime`]. |
610 | /// |
611 | /// [`atime`]: MetadataExt::atime |
612 | /// |
613 | /// # Examples |
614 | /// |
615 | /// ```no_run |
616 | /// use std::fs; |
617 | /// use std::os::unix::fs::MetadataExt; |
618 | /// use std::io; |
619 | /// |
620 | /// fn main() -> io::Result<()> { |
621 | /// let meta = fs::metadata("some_file" )?; |
622 | /// let nano_last_access_time = meta.atime_nsec(); |
623 | /// Ok(()) |
624 | /// } |
625 | /// ``` |
626 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
627 | fn atime_nsec(&self) -> i64; |
628 | /// Returns the last modification time of the file, in seconds since Unix Epoch. |
629 | /// |
630 | /// # Examples |
631 | /// |
632 | /// ```no_run |
633 | /// use std::fs; |
634 | /// use std::os::unix::fs::MetadataExt; |
635 | /// use std::io; |
636 | /// |
637 | /// fn main() -> io::Result<()> { |
638 | /// let meta = fs::metadata("some_file" )?; |
639 | /// let last_modification_time = meta.mtime(); |
640 | /// Ok(()) |
641 | /// } |
642 | /// ``` |
643 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
644 | fn mtime(&self) -> i64; |
645 | /// Returns the last modification time of the file, in nanoseconds since [`mtime`]. |
646 | /// |
647 | /// [`mtime`]: MetadataExt::mtime |
648 | /// |
649 | /// # Examples |
650 | /// |
651 | /// ```no_run |
652 | /// use std::fs; |
653 | /// use std::os::unix::fs::MetadataExt; |
654 | /// use std::io; |
655 | /// |
656 | /// fn main() -> io::Result<()> { |
657 | /// let meta = fs::metadata("some_file" )?; |
658 | /// let nano_last_modification_time = meta.mtime_nsec(); |
659 | /// Ok(()) |
660 | /// } |
661 | /// ``` |
662 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
663 | fn mtime_nsec(&self) -> i64; |
664 | /// Returns the last status change time of the file, in seconds since Unix Epoch. |
665 | /// |
666 | /// # Examples |
667 | /// |
668 | /// ```no_run |
669 | /// use std::fs; |
670 | /// use std::os::unix::fs::MetadataExt; |
671 | /// use std::io; |
672 | /// |
673 | /// fn main() -> io::Result<()> { |
674 | /// let meta = fs::metadata("some_file" )?; |
675 | /// let last_status_change_time = meta.ctime(); |
676 | /// Ok(()) |
677 | /// } |
678 | /// ``` |
679 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
680 | fn ctime(&self) -> i64; |
681 | /// Returns the last status change time of the file, in nanoseconds since [`ctime`]. |
682 | /// |
683 | /// [`ctime`]: MetadataExt::ctime |
684 | /// |
685 | /// # Examples |
686 | /// |
687 | /// ```no_run |
688 | /// use std::fs; |
689 | /// use std::os::unix::fs::MetadataExt; |
690 | /// use std::io; |
691 | /// |
692 | /// fn main() -> io::Result<()> { |
693 | /// let meta = fs::metadata("some_file" )?; |
694 | /// let nano_last_status_change_time = meta.ctime_nsec(); |
695 | /// Ok(()) |
696 | /// } |
697 | /// ``` |
698 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
699 | fn ctime_nsec(&self) -> i64; |
700 | /// Returns the block size for filesystem I/O. |
701 | /// |
702 | /// # Examples |
703 | /// |
704 | /// ```no_run |
705 | /// use std::fs; |
706 | /// use std::os::unix::fs::MetadataExt; |
707 | /// use std::io; |
708 | /// |
709 | /// fn main() -> io::Result<()> { |
710 | /// let meta = fs::metadata("some_file" )?; |
711 | /// let block_size = meta.blksize(); |
712 | /// Ok(()) |
713 | /// } |
714 | /// ``` |
715 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
716 | fn blksize(&self) -> u64; |
717 | /// Returns the number of blocks allocated to the file, in 512-byte units. |
718 | /// |
719 | /// Please note that this may be smaller than `st_size / 512` when the file has holes. |
720 | /// |
721 | /// # Examples |
722 | /// |
723 | /// ```no_run |
724 | /// use std::fs; |
725 | /// use std::os::unix::fs::MetadataExt; |
726 | /// use std::io; |
727 | /// |
728 | /// fn main() -> io::Result<()> { |
729 | /// let meta = fs::metadata("some_file" )?; |
730 | /// let blocks = meta.blocks(); |
731 | /// Ok(()) |
732 | /// } |
733 | /// ``` |
734 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
735 | fn blocks(&self) -> u64; |
736 | #[cfg (target_os = "vxworks" )] |
737 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
738 | fn attrib(&self) -> u8; |
739 | } |
740 | |
741 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
742 | impl MetadataExt for fs::Metadata { |
743 | fn dev(&self) -> u64 { |
744 | self.st_dev() |
745 | } |
746 | fn ino(&self) -> u64 { |
747 | self.st_ino() |
748 | } |
749 | fn mode(&self) -> u32 { |
750 | self.st_mode() |
751 | } |
752 | fn nlink(&self) -> u64 { |
753 | self.st_nlink() |
754 | } |
755 | fn uid(&self) -> u32 { |
756 | self.st_uid() |
757 | } |
758 | fn gid(&self) -> u32 { |
759 | self.st_gid() |
760 | } |
761 | fn rdev(&self) -> u64 { |
762 | self.st_rdev() |
763 | } |
764 | fn size(&self) -> u64 { |
765 | self.st_size() |
766 | } |
767 | fn atime(&self) -> i64 { |
768 | self.st_atime() |
769 | } |
770 | fn atime_nsec(&self) -> i64 { |
771 | self.st_atime_nsec() |
772 | } |
773 | fn mtime(&self) -> i64 { |
774 | self.st_mtime() |
775 | } |
776 | fn mtime_nsec(&self) -> i64 { |
777 | self.st_mtime_nsec() |
778 | } |
779 | fn ctime(&self) -> i64 { |
780 | self.st_ctime() |
781 | } |
782 | fn ctime_nsec(&self) -> i64 { |
783 | self.st_ctime_nsec() |
784 | } |
785 | fn blksize(&self) -> u64 { |
786 | self.st_blksize() |
787 | } |
788 | fn blocks(&self) -> u64 { |
789 | self.st_blocks() |
790 | } |
791 | #[cfg (target_os = "vxworks" )] |
792 | fn attrib(&self) -> u8 { |
793 | self.st_attrib() |
794 | } |
795 | } |
796 | |
797 | /// Unix-specific extensions for [`fs::FileType`]. |
798 | /// |
799 | /// Adds support for special Unix file types such as block/character devices, |
800 | /// pipes, and sockets. |
801 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
802 | pub trait FileTypeExt { |
803 | /// Returns `true` if this file type is a block device. |
804 | /// |
805 | /// # Examples |
806 | /// |
807 | /// ```no_run |
808 | /// use std::fs; |
809 | /// use std::os::unix::fs::FileTypeExt; |
810 | /// use std::io; |
811 | /// |
812 | /// fn main() -> io::Result<()> { |
813 | /// let meta = fs::metadata("block_device_file" )?; |
814 | /// let file_type = meta.file_type(); |
815 | /// assert!(file_type.is_block_device()); |
816 | /// Ok(()) |
817 | /// } |
818 | /// ``` |
819 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
820 | fn is_block_device(&self) -> bool; |
821 | /// Returns `true` if this file type is a char device. |
822 | /// |
823 | /// # Examples |
824 | /// |
825 | /// ```no_run |
826 | /// use std::fs; |
827 | /// use std::os::unix::fs::FileTypeExt; |
828 | /// use std::io; |
829 | /// |
830 | /// fn main() -> io::Result<()> { |
831 | /// let meta = fs::metadata("char_device_file" )?; |
832 | /// let file_type = meta.file_type(); |
833 | /// assert!(file_type.is_char_device()); |
834 | /// Ok(()) |
835 | /// } |
836 | /// ``` |
837 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
838 | fn is_char_device(&self) -> bool; |
839 | /// Returns `true` if this file type is a fifo. |
840 | /// |
841 | /// # Examples |
842 | /// |
843 | /// ```no_run |
844 | /// use std::fs; |
845 | /// use std::os::unix::fs::FileTypeExt; |
846 | /// use std::io; |
847 | /// |
848 | /// fn main() -> io::Result<()> { |
849 | /// let meta = fs::metadata("fifo_file" )?; |
850 | /// let file_type = meta.file_type(); |
851 | /// assert!(file_type.is_fifo()); |
852 | /// Ok(()) |
853 | /// } |
854 | /// ``` |
855 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
856 | fn is_fifo(&self) -> bool; |
857 | /// Returns `true` if this file type is a socket. |
858 | /// |
859 | /// # Examples |
860 | /// |
861 | /// ```no_run |
862 | /// use std::fs; |
863 | /// use std::os::unix::fs::FileTypeExt; |
864 | /// use std::io; |
865 | /// |
866 | /// fn main() -> io::Result<()> { |
867 | /// let meta = fs::metadata("unix.socket" )?; |
868 | /// let file_type = meta.file_type(); |
869 | /// assert!(file_type.is_socket()); |
870 | /// Ok(()) |
871 | /// } |
872 | /// ``` |
873 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
874 | fn is_socket(&self) -> bool; |
875 | } |
876 | |
877 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
878 | impl FileTypeExt for fs::FileType { |
879 | fn is_block_device(&self) -> bool { |
880 | self.as_inner().is(mode:libc::S_IFBLK) |
881 | } |
882 | fn is_char_device(&self) -> bool { |
883 | self.as_inner().is(mode:libc::S_IFCHR) |
884 | } |
885 | fn is_fifo(&self) -> bool { |
886 | self.as_inner().is(mode:libc::S_IFIFO) |
887 | } |
888 | fn is_socket(&self) -> bool { |
889 | self.as_inner().is(mode:libc::S_IFSOCK) |
890 | } |
891 | } |
892 | |
893 | /// Unix-specific extension methods for [`fs::DirEntry`]. |
894 | #[stable (feature = "dir_entry_ext" , since = "1.1.0" )] |
895 | pub trait DirEntryExt { |
896 | /// Returns the underlying `d_ino` field in the contained `dirent` |
897 | /// structure. |
898 | /// |
899 | /// # Examples |
900 | /// |
901 | /// ``` |
902 | /// use std::fs; |
903 | /// use std::os::unix::fs::DirEntryExt; |
904 | /// |
905 | /// if let Ok(entries) = fs::read_dir("." ) { |
906 | /// for entry in entries { |
907 | /// if let Ok(entry) = entry { |
908 | /// // Here, `entry` is a `DirEntry`. |
909 | /// println!("{:?}: {}" , entry.file_name(), entry.ino()); |
910 | /// } |
911 | /// } |
912 | /// } |
913 | /// ``` |
914 | #[stable (feature = "dir_entry_ext" , since = "1.1.0" )] |
915 | fn ino(&self) -> u64; |
916 | } |
917 | |
918 | #[stable (feature = "dir_entry_ext" , since = "1.1.0" )] |
919 | impl DirEntryExt for fs::DirEntry { |
920 | fn ino(&self) -> u64 { |
921 | self.as_inner().ino() |
922 | } |
923 | } |
924 | |
925 | /// Sealed Unix-specific extension methods for [`fs::DirEntry`]. |
926 | #[unstable (feature = "dir_entry_ext2" , issue = "85573" )] |
927 | pub trait DirEntryExt2: Sealed { |
928 | /// Returns a reference to the underlying `OsStr` of this entry's filename. |
929 | /// |
930 | /// # Examples |
931 | /// |
932 | /// ``` |
933 | /// #![feature(dir_entry_ext2)] |
934 | /// use std::os::unix::fs::DirEntryExt2; |
935 | /// use std::{fs, io}; |
936 | /// |
937 | /// fn main() -> io::Result<()> { |
938 | /// let mut entries = fs::read_dir("." )?.collect::<Result<Vec<_>, io::Error>>()?; |
939 | /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref())); |
940 | /// |
941 | /// for p in entries { |
942 | /// println!("{p:?}" ); |
943 | /// } |
944 | /// |
945 | /// Ok(()) |
946 | /// } |
947 | /// ``` |
948 | fn file_name_ref(&self) -> &OsStr; |
949 | } |
950 | |
951 | /// Allows extension traits within `std`. |
952 | #[unstable (feature = "sealed" , issue = "none" )] |
953 | impl Sealed for fs::DirEntry {} |
954 | |
955 | #[unstable (feature = "dir_entry_ext2" , issue = "85573" )] |
956 | impl DirEntryExt2 for fs::DirEntry { |
957 | fn file_name_ref(&self) -> &OsStr { |
958 | self.as_inner().file_name_os_str() |
959 | } |
960 | } |
961 | |
962 | /// Creates a new symbolic link on the filesystem. |
963 | /// |
964 | /// The `link` path will be a symbolic link pointing to the `original` path. |
965 | /// |
966 | /// # Examples |
967 | /// |
968 | /// ```no_run |
969 | /// use std::os::unix::fs; |
970 | /// |
971 | /// fn main() -> std::io::Result<()> { |
972 | /// fs::symlink("a.txt" , "b.txt" )?; |
973 | /// Ok(()) |
974 | /// } |
975 | /// ``` |
976 | #[stable (feature = "symlink" , since = "1.1.0" )] |
977 | pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> { |
978 | sys::fs::symlink(original.as_ref(), link.as_ref()) |
979 | } |
980 | |
981 | /// Unix-specific extensions to [`fs::DirBuilder`]. |
982 | #[stable (feature = "dir_builder" , since = "1.6.0" )] |
983 | pub trait DirBuilderExt { |
984 | /// Sets the mode to create new directories with. This option defaults to |
985 | /// 0o777. |
986 | /// |
987 | /// # Examples |
988 | /// |
989 | /// ```no_run |
990 | /// use std::fs::DirBuilder; |
991 | /// use std::os::unix::fs::DirBuilderExt; |
992 | /// |
993 | /// let mut builder = DirBuilder::new(); |
994 | /// builder.mode(0o755); |
995 | /// ``` |
996 | #[stable (feature = "dir_builder" , since = "1.6.0" )] |
997 | fn mode(&mut self, mode: u32) -> &mut Self; |
998 | } |
999 | |
1000 | #[stable (feature = "dir_builder" , since = "1.6.0" )] |
1001 | impl DirBuilderExt for fs::DirBuilder { |
1002 | fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { |
1003 | self.as_inner_mut().set_mode(mode); |
1004 | self |
1005 | } |
1006 | } |
1007 | |
1008 | /// Change the owner and group of the specified path. |
1009 | /// |
1010 | /// Specifying either the uid or gid as `None` will leave it unchanged. |
1011 | /// |
1012 | /// Changing the owner typically requires privileges, such as root or a specific capability. |
1013 | /// Changing the group typically requires either being the owner and a member of the group, or |
1014 | /// having privileges. |
1015 | /// |
1016 | /// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases |
1017 | /// according to POSIX, usually even if the user is root. The sgid is not cleared when |
1018 | /// the file is non-group-executable. See: <https://www.man7.org/linux/man-pages/man2/chown.2.html> |
1019 | /// This call may also clear file capabilities, if there was any. |
1020 | /// |
1021 | /// If called on a symbolic link, this will change the owner and group of the link target. To |
1022 | /// change the owner and group of the link itself, see [`lchown`]. |
1023 | /// |
1024 | /// # Examples |
1025 | /// |
1026 | /// ```no_run |
1027 | /// use std::os::unix::fs; |
1028 | /// |
1029 | /// fn main() -> std::io::Result<()> { |
1030 | /// fs::chown("/sandbox" , Some(0), Some(0))?; |
1031 | /// Ok(()) |
1032 | /// } |
1033 | /// ``` |
1034 | #[stable (feature = "unix_chown" , since = "1.73.0" )] |
1035 | pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { |
1036 | sys::fs::chown(path:dir.as_ref(), uid.unwrap_or(default:u32::MAX), gid.unwrap_or(default:u32::MAX)) |
1037 | } |
1038 | |
1039 | /// Change the owner and group of the file referenced by the specified open file descriptor. |
1040 | /// |
1041 | /// For semantics and required privileges, see [`chown`]. |
1042 | /// |
1043 | /// # Examples |
1044 | /// |
1045 | /// ```no_run |
1046 | /// use std::os::unix::fs; |
1047 | /// |
1048 | /// fn main() -> std::io::Result<()> { |
1049 | /// let f = std::fs::File::open("/file" )?; |
1050 | /// fs::fchown(&f, Some(0), Some(0))?; |
1051 | /// Ok(()) |
1052 | /// } |
1053 | /// ``` |
1054 | #[stable (feature = "unix_chown" , since = "1.73.0" )] |
1055 | pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { |
1056 | sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(default:u32::MAX), gid.unwrap_or(default:u32::MAX)) |
1057 | } |
1058 | |
1059 | /// Change the owner and group of the specified path, without dereferencing symbolic links. |
1060 | /// |
1061 | /// Identical to [`chown`], except that if called on a symbolic link, this will change the owner |
1062 | /// and group of the link itself rather than the owner and group of the link target. |
1063 | /// |
1064 | /// # Examples |
1065 | /// |
1066 | /// ```no_run |
1067 | /// use std::os::unix::fs; |
1068 | /// |
1069 | /// fn main() -> std::io::Result<()> { |
1070 | /// fs::lchown("/symlink" , Some(0), Some(0))?; |
1071 | /// Ok(()) |
1072 | /// } |
1073 | /// ``` |
1074 | #[stable (feature = "unix_chown" , since = "1.73.0" )] |
1075 | pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { |
1076 | sys::fs::lchown(path:dir.as_ref(), uid.unwrap_or(default:u32::MAX), gid.unwrap_or(default:u32::MAX)) |
1077 | } |
1078 | |
1079 | /// Change the root directory of the current process to the specified path. |
1080 | /// |
1081 | /// This typically requires privileges, such as root or a specific capability. |
1082 | /// |
1083 | /// This does not change the current working directory; you should call |
1084 | /// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards. |
1085 | /// |
1086 | /// # Examples |
1087 | /// |
1088 | /// ```no_run |
1089 | /// use std::os::unix::fs; |
1090 | /// |
1091 | /// fn main() -> std::io::Result<()> { |
1092 | /// fs::chroot("/sandbox" )?; |
1093 | /// std::env::set_current_dir("/" )?; |
1094 | /// // continue working in sandbox |
1095 | /// Ok(()) |
1096 | /// } |
1097 | /// ``` |
1098 | #[stable (feature = "unix_chroot" , since = "1.56.0" )] |
1099 | #[cfg (not(target_os = "fuchsia" ))] |
1100 | pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> { |
1101 | sys::fs::chroot(dir.as_ref()) |
1102 | } |
1103 | |