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() { 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 behaviour. |
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 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
280 | pub trait PermissionsExt { |
281 | /// Returns the underlying raw `st_mode` bits that contain the standard |
282 | /// Unix permissions for this file. |
283 | /// |
284 | /// # Examples |
285 | /// |
286 | /// ```no_run |
287 | /// use std::fs::File; |
288 | /// use std::os::unix::fs::PermissionsExt; |
289 | /// |
290 | /// fn main() -> std::io::Result<()> { |
291 | /// let f = File::create("foo.txt" )?; |
292 | /// let metadata = f.metadata()?; |
293 | /// let permissions = metadata.permissions(); |
294 | /// |
295 | /// println!("permissions: {:o}" , permissions.mode()); |
296 | /// Ok(()) |
297 | /// } |
298 | /// ``` |
299 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
300 | fn mode(&self) -> u32; |
301 | |
302 | /// Sets the underlying raw bits for this set of permissions. |
303 | /// |
304 | /// # Examples |
305 | /// |
306 | /// ```no_run |
307 | /// use std::fs::File; |
308 | /// use std::os::unix::fs::PermissionsExt; |
309 | /// |
310 | /// fn main() -> std::io::Result<()> { |
311 | /// let f = File::create("foo.txt" )?; |
312 | /// let metadata = f.metadata()?; |
313 | /// let mut permissions = metadata.permissions(); |
314 | /// |
315 | /// permissions.set_mode(0o644); // Read/write for owner and read for others. |
316 | /// assert_eq!(permissions.mode(), 0o644); |
317 | /// Ok(()) |
318 | /// } |
319 | /// ``` |
320 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
321 | fn set_mode(&mut self, mode: u32); |
322 | |
323 | /// Creates a new instance of `Permissions` from the given set of Unix |
324 | /// permission bits. |
325 | /// |
326 | /// # Examples |
327 | /// |
328 | /// ``` |
329 | /// use std::fs::Permissions; |
330 | /// use std::os::unix::fs::PermissionsExt; |
331 | /// |
332 | /// // Read/write for owner and read for others. |
333 | /// let permissions = Permissions::from_mode(0o644); |
334 | /// assert_eq!(permissions.mode(), 0o644); |
335 | /// ``` |
336 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
337 | fn from_mode(mode: u32) -> Self; |
338 | } |
339 | |
340 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
341 | impl PermissionsExt for Permissions { |
342 | fn mode(&self) -> u32 { |
343 | self.as_inner().mode() |
344 | } |
345 | |
346 | fn set_mode(&mut self, mode: u32) { |
347 | *self = Permissions::from_inner(FromInner::from_inner(mode)); |
348 | } |
349 | |
350 | fn from_mode(mode: u32) -> Permissions { |
351 | Permissions::from_inner(FromInner::from_inner(mode)) |
352 | } |
353 | } |
354 | |
355 | /// Unix-specific extensions to [`fs::OpenOptions`]. |
356 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
357 | pub trait OpenOptionsExt { |
358 | /// Sets the mode bits that a new file will be created with. |
359 | /// |
360 | /// If a new file is created as part of an `OpenOptions::open` call then this |
361 | /// specified `mode` will be used as the permission bits for the new file. |
362 | /// If no `mode` is set, the default of `0o666` will be used. |
363 | /// The operating system masks out bits with the system's `umask`, to produce |
364 | /// the final permissions. |
365 | /// |
366 | /// # Examples |
367 | /// |
368 | /// ```no_run |
369 | /// use std::fs::OpenOptions; |
370 | /// use std::os::unix::fs::OpenOptionsExt; |
371 | /// |
372 | /// # fn main() { |
373 | /// let mut options = OpenOptions::new(); |
374 | /// options.mode(0o644); // Give read/write for owner and read for others. |
375 | /// let file = options.open("foo.txt" ); |
376 | /// # } |
377 | /// ``` |
378 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
379 | fn mode(&mut self, mode: u32) -> &mut Self; |
380 | |
381 | /// Pass custom flags to the `flags` argument of `open`. |
382 | /// |
383 | /// The bits that define the access mode are masked out with `O_ACCMODE`, to |
384 | /// ensure they do not interfere with the access mode set by Rusts options. |
385 | /// |
386 | /// Custom flags can only set flags, not remove flags set by Rusts options. |
387 | /// This options overwrites any previously set custom flags. |
388 | /// |
389 | /// # Examples |
390 | /// |
391 | /// ```no_run |
392 | /// # #![feature (rustc_private)] |
393 | /// use std::fs::OpenOptions; |
394 | /// use std::os::unix::fs::OpenOptionsExt; |
395 | /// |
396 | /// # fn main() { |
397 | /// let mut options = OpenOptions::new(); |
398 | /// options.write(true); |
399 | /// if cfg!(unix) { |
400 | /// options.custom_flags(libc::O_NOFOLLOW); |
401 | /// } |
402 | /// let file = options.open("foo.txt" ); |
403 | /// # } |
404 | /// ``` |
405 | #[stable (feature = "open_options_ext" , since = "1.10.0" )] |
406 | fn custom_flags(&mut self, flags: i32) -> &mut Self; |
407 | } |
408 | |
409 | #[stable (feature = "fs_ext" , since = "1.1.0" )] |
410 | impl OpenOptionsExt for OpenOptions { |
411 | fn mode(&mut self, mode: u32) -> &mut OpenOptions { |
412 | self.as_inner_mut().mode(mode); |
413 | self |
414 | } |
415 | |
416 | fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { |
417 | self.as_inner_mut().custom_flags(flags); |
418 | self |
419 | } |
420 | } |
421 | |
422 | /// Unix-specific extensions to [`fs::Metadata`]. |
423 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
424 | pub trait MetadataExt { |
425 | /// Returns the ID of the device containing the file. |
426 | /// |
427 | /// # Examples |
428 | /// |
429 | /// ```no_run |
430 | /// use std::io; |
431 | /// use std::fs; |
432 | /// use std::os::unix::fs::MetadataExt; |
433 | /// |
434 | /// fn main() -> io::Result<()> { |
435 | /// let meta = fs::metadata("some_file" )?; |
436 | /// let dev_id = meta.dev(); |
437 | /// Ok(()) |
438 | /// } |
439 | /// ``` |
440 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
441 | fn dev(&self) -> u64; |
442 | /// Returns the inode number. |
443 | /// |
444 | /// # Examples |
445 | /// |
446 | /// ```no_run |
447 | /// use std::fs; |
448 | /// use std::os::unix::fs::MetadataExt; |
449 | /// use std::io; |
450 | /// |
451 | /// fn main() -> io::Result<()> { |
452 | /// let meta = fs::metadata("some_file" )?; |
453 | /// let inode = meta.ino(); |
454 | /// Ok(()) |
455 | /// } |
456 | /// ``` |
457 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
458 | fn ino(&self) -> u64; |
459 | /// Returns the rights applied to this file. |
460 | /// |
461 | /// # Examples |
462 | /// |
463 | /// ```no_run |
464 | /// use std::fs; |
465 | /// use std::os::unix::fs::MetadataExt; |
466 | /// use std::io; |
467 | /// |
468 | /// fn main() -> io::Result<()> { |
469 | /// let meta = fs::metadata("some_file" )?; |
470 | /// let mode = meta.mode(); |
471 | /// let user_has_write_access = mode & 0o200; |
472 | /// let user_has_read_write_access = mode & 0o600; |
473 | /// let group_has_read_access = mode & 0o040; |
474 | /// let others_have_exec_access = mode & 0o001; |
475 | /// Ok(()) |
476 | /// } |
477 | /// ``` |
478 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
479 | fn mode(&self) -> u32; |
480 | /// Returns the number of hard links pointing to this file. |
481 | /// |
482 | /// # Examples |
483 | /// |
484 | /// ```no_run |
485 | /// use std::fs; |
486 | /// use std::os::unix::fs::MetadataExt; |
487 | /// use std::io; |
488 | /// |
489 | /// fn main() -> io::Result<()> { |
490 | /// let meta = fs::metadata("some_file" )?; |
491 | /// let nb_hard_links = meta.nlink(); |
492 | /// Ok(()) |
493 | /// } |
494 | /// ``` |
495 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
496 | fn nlink(&self) -> u64; |
497 | /// Returns the user ID of the owner of this file. |
498 | /// |
499 | /// # Examples |
500 | /// |
501 | /// ```no_run |
502 | /// use std::fs; |
503 | /// use std::os::unix::fs::MetadataExt; |
504 | /// use std::io; |
505 | /// |
506 | /// fn main() -> io::Result<()> { |
507 | /// let meta = fs::metadata("some_file" )?; |
508 | /// let user_id = meta.uid(); |
509 | /// Ok(()) |
510 | /// } |
511 | /// ``` |
512 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
513 | fn uid(&self) -> u32; |
514 | /// Returns the group ID of the owner of this file. |
515 | /// |
516 | /// # Examples |
517 | /// |
518 | /// ```no_run |
519 | /// use std::fs; |
520 | /// use std::os::unix::fs::MetadataExt; |
521 | /// use std::io; |
522 | /// |
523 | /// fn main() -> io::Result<()> { |
524 | /// let meta = fs::metadata("some_file" )?; |
525 | /// let group_id = meta.gid(); |
526 | /// Ok(()) |
527 | /// } |
528 | /// ``` |
529 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
530 | fn gid(&self) -> u32; |
531 | /// Returns the device ID of this file (if it is a special one). |
532 | /// |
533 | /// # Examples |
534 | /// |
535 | /// ```no_run |
536 | /// use std::fs; |
537 | /// use std::os::unix::fs::MetadataExt; |
538 | /// use std::io; |
539 | /// |
540 | /// fn main() -> io::Result<()> { |
541 | /// let meta = fs::metadata("some_file" )?; |
542 | /// let device_id = meta.rdev(); |
543 | /// Ok(()) |
544 | /// } |
545 | /// ``` |
546 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
547 | fn rdev(&self) -> u64; |
548 | /// Returns the total size of this file in bytes. |
549 | /// |
550 | /// # Examples |
551 | /// |
552 | /// ```no_run |
553 | /// use std::fs; |
554 | /// use std::os::unix::fs::MetadataExt; |
555 | /// use std::io; |
556 | /// |
557 | /// fn main() -> io::Result<()> { |
558 | /// let meta = fs::metadata("some_file" )?; |
559 | /// let file_size = meta.size(); |
560 | /// Ok(()) |
561 | /// } |
562 | /// ``` |
563 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
564 | fn size(&self) -> u64; |
565 | /// Returns the last access time of the file, in seconds since Unix Epoch. |
566 | /// |
567 | /// # Examples |
568 | /// |
569 | /// ```no_run |
570 | /// use std::fs; |
571 | /// use std::os::unix::fs::MetadataExt; |
572 | /// use std::io; |
573 | /// |
574 | /// fn main() -> io::Result<()> { |
575 | /// let meta = fs::metadata("some_file" )?; |
576 | /// let last_access_time = meta.atime(); |
577 | /// Ok(()) |
578 | /// } |
579 | /// ``` |
580 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
581 | fn atime(&self) -> i64; |
582 | /// Returns the last access time of the file, in nanoseconds since [`atime`]. |
583 | /// |
584 | /// [`atime`]: MetadataExt::atime |
585 | /// |
586 | /// # Examples |
587 | /// |
588 | /// ```no_run |
589 | /// use std::fs; |
590 | /// use std::os::unix::fs::MetadataExt; |
591 | /// use std::io; |
592 | /// |
593 | /// fn main() -> io::Result<()> { |
594 | /// let meta = fs::metadata("some_file" )?; |
595 | /// let nano_last_access_time = meta.atime_nsec(); |
596 | /// Ok(()) |
597 | /// } |
598 | /// ``` |
599 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
600 | fn atime_nsec(&self) -> i64; |
601 | /// Returns the last modification time of the file, in seconds since Unix Epoch. |
602 | /// |
603 | /// # Examples |
604 | /// |
605 | /// ```no_run |
606 | /// use std::fs; |
607 | /// use std::os::unix::fs::MetadataExt; |
608 | /// use std::io; |
609 | /// |
610 | /// fn main() -> io::Result<()> { |
611 | /// let meta = fs::metadata("some_file" )?; |
612 | /// let last_modification_time = meta.mtime(); |
613 | /// Ok(()) |
614 | /// } |
615 | /// ``` |
616 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
617 | fn mtime(&self) -> i64; |
618 | /// Returns the last modification time of the file, in nanoseconds since [`mtime`]. |
619 | /// |
620 | /// [`mtime`]: MetadataExt::mtime |
621 | /// |
622 | /// # Examples |
623 | /// |
624 | /// ```no_run |
625 | /// use std::fs; |
626 | /// use std::os::unix::fs::MetadataExt; |
627 | /// use std::io; |
628 | /// |
629 | /// fn main() -> io::Result<()> { |
630 | /// let meta = fs::metadata("some_file" )?; |
631 | /// let nano_last_modification_time = meta.mtime_nsec(); |
632 | /// Ok(()) |
633 | /// } |
634 | /// ``` |
635 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
636 | fn mtime_nsec(&self) -> i64; |
637 | /// Returns the last status change time of the file, in seconds since Unix Epoch. |
638 | /// |
639 | /// # Examples |
640 | /// |
641 | /// ```no_run |
642 | /// use std::fs; |
643 | /// use std::os::unix::fs::MetadataExt; |
644 | /// use std::io; |
645 | /// |
646 | /// fn main() -> io::Result<()> { |
647 | /// let meta = fs::metadata("some_file" )?; |
648 | /// let last_status_change_time = meta.ctime(); |
649 | /// Ok(()) |
650 | /// } |
651 | /// ``` |
652 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
653 | fn ctime(&self) -> i64; |
654 | /// Returns the last status change time of the file, in nanoseconds since [`ctime`]. |
655 | /// |
656 | /// [`ctime`]: MetadataExt::ctime |
657 | /// |
658 | /// # Examples |
659 | /// |
660 | /// ```no_run |
661 | /// use std::fs; |
662 | /// use std::os::unix::fs::MetadataExt; |
663 | /// use std::io; |
664 | /// |
665 | /// fn main() -> io::Result<()> { |
666 | /// let meta = fs::metadata("some_file" )?; |
667 | /// let nano_last_status_change_time = meta.ctime_nsec(); |
668 | /// Ok(()) |
669 | /// } |
670 | /// ``` |
671 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
672 | fn ctime_nsec(&self) -> i64; |
673 | /// Returns the block size for filesystem I/O. |
674 | /// |
675 | /// # Examples |
676 | /// |
677 | /// ```no_run |
678 | /// use std::fs; |
679 | /// use std::os::unix::fs::MetadataExt; |
680 | /// use std::io; |
681 | /// |
682 | /// fn main() -> io::Result<()> { |
683 | /// let meta = fs::metadata("some_file" )?; |
684 | /// let block_size = meta.blksize(); |
685 | /// Ok(()) |
686 | /// } |
687 | /// ``` |
688 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
689 | fn blksize(&self) -> u64; |
690 | /// Returns the number of blocks allocated to the file, in 512-byte units. |
691 | /// |
692 | /// Please note that this may be smaller than `st_size / 512` when the file has holes. |
693 | /// |
694 | /// # Examples |
695 | /// |
696 | /// ```no_run |
697 | /// use std::fs; |
698 | /// use std::os::unix::fs::MetadataExt; |
699 | /// use std::io; |
700 | /// |
701 | /// fn main() -> io::Result<()> { |
702 | /// let meta = fs::metadata("some_file" )?; |
703 | /// let blocks = meta.blocks(); |
704 | /// Ok(()) |
705 | /// } |
706 | /// ``` |
707 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
708 | fn blocks(&self) -> u64; |
709 | #[cfg (target_os = "vxworks" )] |
710 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
711 | fn attrib(&self) -> u8; |
712 | } |
713 | |
714 | #[stable (feature = "metadata_ext" , since = "1.1.0" )] |
715 | impl MetadataExt for fs::Metadata { |
716 | fn dev(&self) -> u64 { |
717 | self.st_dev() |
718 | } |
719 | fn ino(&self) -> u64 { |
720 | self.st_ino() |
721 | } |
722 | fn mode(&self) -> u32 { |
723 | self.st_mode() |
724 | } |
725 | fn nlink(&self) -> u64 { |
726 | self.st_nlink() |
727 | } |
728 | fn uid(&self) -> u32 { |
729 | self.st_uid() |
730 | } |
731 | fn gid(&self) -> u32 { |
732 | self.st_gid() |
733 | } |
734 | fn rdev(&self) -> u64 { |
735 | self.st_rdev() |
736 | } |
737 | fn size(&self) -> u64 { |
738 | self.st_size() |
739 | } |
740 | fn atime(&self) -> i64 { |
741 | self.st_atime() |
742 | } |
743 | fn atime_nsec(&self) -> i64 { |
744 | self.st_atime_nsec() |
745 | } |
746 | fn mtime(&self) -> i64 { |
747 | self.st_mtime() |
748 | } |
749 | fn mtime_nsec(&self) -> i64 { |
750 | self.st_mtime_nsec() |
751 | } |
752 | fn ctime(&self) -> i64 { |
753 | self.st_ctime() |
754 | } |
755 | fn ctime_nsec(&self) -> i64 { |
756 | self.st_ctime_nsec() |
757 | } |
758 | fn blksize(&self) -> u64 { |
759 | self.st_blksize() |
760 | } |
761 | fn blocks(&self) -> u64 { |
762 | self.st_blocks() |
763 | } |
764 | #[cfg (target_os = "vxworks" )] |
765 | fn attrib(&self) -> u8 { |
766 | self.st_attrib() |
767 | } |
768 | } |
769 | |
770 | /// Unix-specific extensions for [`fs::FileType`]. |
771 | /// |
772 | /// Adds support for special Unix file types such as block/character devices, |
773 | /// pipes, and sockets. |
774 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
775 | pub trait FileTypeExt { |
776 | /// Returns `true` if this file type is a block device. |
777 | /// |
778 | /// # Examples |
779 | /// |
780 | /// ```no_run |
781 | /// use std::fs; |
782 | /// use std::os::unix::fs::FileTypeExt; |
783 | /// use std::io; |
784 | /// |
785 | /// fn main() -> io::Result<()> { |
786 | /// let meta = fs::metadata("block_device_file" )?; |
787 | /// let file_type = meta.file_type(); |
788 | /// assert!(file_type.is_block_device()); |
789 | /// Ok(()) |
790 | /// } |
791 | /// ``` |
792 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
793 | fn is_block_device(&self) -> bool; |
794 | /// Returns `true` if this file type is a char device. |
795 | /// |
796 | /// # Examples |
797 | /// |
798 | /// ```no_run |
799 | /// use std::fs; |
800 | /// use std::os::unix::fs::FileTypeExt; |
801 | /// use std::io; |
802 | /// |
803 | /// fn main() -> io::Result<()> { |
804 | /// let meta = fs::metadata("char_device_file" )?; |
805 | /// let file_type = meta.file_type(); |
806 | /// assert!(file_type.is_char_device()); |
807 | /// Ok(()) |
808 | /// } |
809 | /// ``` |
810 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
811 | fn is_char_device(&self) -> bool; |
812 | /// Returns `true` if this file type is a fifo. |
813 | /// |
814 | /// # Examples |
815 | /// |
816 | /// ```no_run |
817 | /// use std::fs; |
818 | /// use std::os::unix::fs::FileTypeExt; |
819 | /// use std::io; |
820 | /// |
821 | /// fn main() -> io::Result<()> { |
822 | /// let meta = fs::metadata("fifo_file" )?; |
823 | /// let file_type = meta.file_type(); |
824 | /// assert!(file_type.is_fifo()); |
825 | /// Ok(()) |
826 | /// } |
827 | /// ``` |
828 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
829 | fn is_fifo(&self) -> bool; |
830 | /// Returns `true` if this file type is a socket. |
831 | /// |
832 | /// # Examples |
833 | /// |
834 | /// ```no_run |
835 | /// use std::fs; |
836 | /// use std::os::unix::fs::FileTypeExt; |
837 | /// use std::io; |
838 | /// |
839 | /// fn main() -> io::Result<()> { |
840 | /// let meta = fs::metadata("unix.socket" )?; |
841 | /// let file_type = meta.file_type(); |
842 | /// assert!(file_type.is_socket()); |
843 | /// Ok(()) |
844 | /// } |
845 | /// ``` |
846 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
847 | fn is_socket(&self) -> bool; |
848 | } |
849 | |
850 | #[stable (feature = "file_type_ext" , since = "1.5.0" )] |
851 | impl FileTypeExt for fs::FileType { |
852 | fn is_block_device(&self) -> bool { |
853 | self.as_inner().is(mode:libc::S_IFBLK) |
854 | } |
855 | fn is_char_device(&self) -> bool { |
856 | self.as_inner().is(mode:libc::S_IFCHR) |
857 | } |
858 | fn is_fifo(&self) -> bool { |
859 | self.as_inner().is(mode:libc::S_IFIFO) |
860 | } |
861 | fn is_socket(&self) -> bool { |
862 | self.as_inner().is(mode:libc::S_IFSOCK) |
863 | } |
864 | } |
865 | |
866 | /// Unix-specific extension methods for [`fs::DirEntry`]. |
867 | #[stable (feature = "dir_entry_ext" , since = "1.1.0" )] |
868 | pub trait DirEntryExt { |
869 | /// Returns the underlying `d_ino` field in the contained `dirent` |
870 | /// structure. |
871 | /// |
872 | /// # Examples |
873 | /// |
874 | /// ``` |
875 | /// use std::fs; |
876 | /// use std::os::unix::fs::DirEntryExt; |
877 | /// |
878 | /// if let Ok(entries) = fs::read_dir("." ) { |
879 | /// for entry in entries { |
880 | /// if let Ok(entry) = entry { |
881 | /// // Here, `entry` is a `DirEntry`. |
882 | /// println!("{:?}: {}" , entry.file_name(), entry.ino()); |
883 | /// } |
884 | /// } |
885 | /// } |
886 | /// ``` |
887 | #[stable (feature = "dir_entry_ext" , since = "1.1.0" )] |
888 | fn ino(&self) -> u64; |
889 | } |
890 | |
891 | #[stable (feature = "dir_entry_ext" , since = "1.1.0" )] |
892 | impl DirEntryExt for fs::DirEntry { |
893 | fn ino(&self) -> u64 { |
894 | self.as_inner().ino() |
895 | } |
896 | } |
897 | |
898 | /// Sealed Unix-specific extension methods for [`fs::DirEntry`]. |
899 | #[unstable (feature = "dir_entry_ext2" , issue = "85573" )] |
900 | pub trait DirEntryExt2: Sealed { |
901 | /// Returns a reference to the underlying `OsStr` of this entry's filename. |
902 | /// |
903 | /// # Examples |
904 | /// |
905 | /// ``` |
906 | /// #![feature(dir_entry_ext2)] |
907 | /// use std::os::unix::fs::DirEntryExt2; |
908 | /// use std::{fs, io}; |
909 | /// |
910 | /// fn main() -> io::Result<()> { |
911 | /// let mut entries = fs::read_dir("." )?.collect::<Result<Vec<_>, io::Error>>()?; |
912 | /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref())); |
913 | /// |
914 | /// for p in entries { |
915 | /// println!("{p:?}" ); |
916 | /// } |
917 | /// |
918 | /// Ok(()) |
919 | /// } |
920 | /// ``` |
921 | fn file_name_ref(&self) -> &OsStr; |
922 | } |
923 | |
924 | /// Allows extension traits within `std`. |
925 | #[unstable (feature = "sealed" , issue = "none" )] |
926 | impl Sealed for fs::DirEntry {} |
927 | |
928 | #[unstable (feature = "dir_entry_ext2" , issue = "85573" )] |
929 | impl DirEntryExt2 for fs::DirEntry { |
930 | fn file_name_ref(&self) -> &OsStr { |
931 | self.as_inner().file_name_os_str() |
932 | } |
933 | } |
934 | |
935 | /// Creates a new symbolic link on the filesystem. |
936 | /// |
937 | /// The `link` path will be a symbolic link pointing to the `original` path. |
938 | /// |
939 | /// # Examples |
940 | /// |
941 | /// ```no_run |
942 | /// use std::os::unix::fs; |
943 | /// |
944 | /// fn main() -> std::io::Result<()> { |
945 | /// fs::symlink("a.txt" , "b.txt" )?; |
946 | /// Ok(()) |
947 | /// } |
948 | /// ``` |
949 | #[stable (feature = "symlink" , since = "1.1.0" )] |
950 | pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> { |
951 | sys::fs::symlink(original.as_ref(), link.as_ref()) |
952 | } |
953 | |
954 | /// Unix-specific extensions to [`fs::DirBuilder`]. |
955 | #[stable (feature = "dir_builder" , since = "1.6.0" )] |
956 | pub trait DirBuilderExt { |
957 | /// Sets the mode to create new directories with. This option defaults to |
958 | /// 0o777. |
959 | /// |
960 | /// # Examples |
961 | /// |
962 | /// ```no_run |
963 | /// use std::fs::DirBuilder; |
964 | /// use std::os::unix::fs::DirBuilderExt; |
965 | /// |
966 | /// let mut builder = DirBuilder::new(); |
967 | /// builder.mode(0o755); |
968 | /// ``` |
969 | #[stable (feature = "dir_builder" , since = "1.6.0" )] |
970 | fn mode(&mut self, mode: u32) -> &mut Self; |
971 | } |
972 | |
973 | #[stable (feature = "dir_builder" , since = "1.6.0" )] |
974 | impl DirBuilderExt for fs::DirBuilder { |
975 | fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { |
976 | self.as_inner_mut().set_mode(mode); |
977 | self |
978 | } |
979 | } |
980 | |
981 | /// Change the owner and group of the specified path. |
982 | /// |
983 | /// Specifying either the uid or gid as `None` will leave it unchanged. |
984 | /// |
985 | /// Changing the owner typically requires privileges, such as root or a specific capability. |
986 | /// Changing the group typically requires either being the owner and a member of the group, or |
987 | /// having privileges. |
988 | /// |
989 | /// If called on a symbolic link, this will change the owner and group of the link target. To |
990 | /// change the owner and group of the link itself, see [`lchown`]. |
991 | /// |
992 | /// # Examples |
993 | /// |
994 | /// ```no_run |
995 | /// use std::os::unix::fs; |
996 | /// |
997 | /// fn main() -> std::io::Result<()> { |
998 | /// fs::chown("/sandbox" , Some(0), Some(0))?; |
999 | /// Ok(()) |
1000 | /// } |
1001 | /// ``` |
1002 | #[stable (feature = "unix_chown" , since = "1.73.0" )] |
1003 | pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { |
1004 | sys::fs::chown(path:dir.as_ref(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX)) |
1005 | } |
1006 | |
1007 | /// Change the owner and group of the file referenced by the specified open file descriptor. |
1008 | /// |
1009 | /// For semantics and required privileges, see [`chown`]. |
1010 | /// |
1011 | /// # Examples |
1012 | /// |
1013 | /// ```no_run |
1014 | /// use std::os::unix::fs; |
1015 | /// |
1016 | /// fn main() -> std::io::Result<()> { |
1017 | /// let f = std::fs::File::open("/file" )?; |
1018 | /// fs::fchown(&f, Some(0), Some(0))?; |
1019 | /// Ok(()) |
1020 | /// } |
1021 | /// ``` |
1022 | #[stable (feature = "unix_chown" , since = "1.73.0" )] |
1023 | pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { |
1024 | sys::fs::fchown(fd.as_fd().as_raw_fd(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX)) |
1025 | } |
1026 | |
1027 | /// Change the owner and group of the specified path, without dereferencing symbolic links. |
1028 | /// |
1029 | /// Identical to [`chown`], except that if called on a symbolic link, this will change the owner |
1030 | /// and group of the link itself rather than the owner and group of the link target. |
1031 | /// |
1032 | /// # Examples |
1033 | /// |
1034 | /// ```no_run |
1035 | /// use std::os::unix::fs; |
1036 | /// |
1037 | /// fn main() -> std::io::Result<()> { |
1038 | /// fs::lchown("/symlink" , Some(0), Some(0))?; |
1039 | /// Ok(()) |
1040 | /// } |
1041 | /// ``` |
1042 | #[stable (feature = "unix_chown" , since = "1.73.0" )] |
1043 | pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { |
1044 | sys::fs::lchown(path:dir.as_ref(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX)) |
1045 | } |
1046 | |
1047 | /// Change the root directory of the current process to the specified path. |
1048 | /// |
1049 | /// This typically requires privileges, such as root or a specific capability. |
1050 | /// |
1051 | /// This does not change the current working directory; you should call |
1052 | /// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards. |
1053 | /// |
1054 | /// # Examples |
1055 | /// |
1056 | /// ```no_run |
1057 | /// use std::os::unix::fs; |
1058 | /// |
1059 | /// fn main() -> std::io::Result<()> { |
1060 | /// fs::chroot("/sandbox" )?; |
1061 | /// std::env::set_current_dir("/" )?; |
1062 | /// // continue working in sandbox |
1063 | /// Ok(()) |
1064 | /// } |
1065 | /// ``` |
1066 | #[stable (feature = "unix_chroot" , since = "1.56.0" )] |
1067 | #[cfg (not(any(target_os = "fuchsia" , target_os = "vxworks" )))] |
1068 | pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> { |
1069 | sys::fs::chroot(dir.as_ref()) |
1070 | } |
1071 | |