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