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