1use crate::fs::{Metadata, OpenOptions, Permissions};
2use cap_primitives::fs::{is_file_read_write, open_ambient};
3use cap_primitives::AmbientAuthority;
4#[cfg(not(windows))]
5use io_extras::os::rustix::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
6#[cfg(not(windows))]
7use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
8#[cfg(windows)]
9use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
10use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
11use std::path::Path;
12use std::{fmt, fs, process};
13#[cfg(windows)]
14use {
15 io_extras::os::windows::{
16 AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket,
17 OwnedHandleOrSocket, RawHandleOrSocket,
18 },
19 std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
20};
21
22pub struct File {
34 pub(crate) std: fs::File,
35}
36
37impl File {
38 #[inline]
43 pub fn from_std(std: fs::File) -> Self {
44 Self { std }
45 }
46
47 #[inline]
49 pub fn into_std(self) -> fs::File {
50 self.std
51 }
52
53 #[inline]
57 pub fn sync_all(&self) -> io::Result<()> {
58 self.std.sync_all()
59 }
60
61 #[inline]
66 pub fn sync_data(&self) -> io::Result<()> {
67 self.std.sync_data()
68 }
69
70 #[inline]
75 pub fn set_len(&self, size: u64) -> io::Result<()> {
76 self.std.set_len(size)
77 }
78
79 #[inline]
83 pub fn metadata(&self) -> io::Result<Metadata> {
84 metadata_from(&self.std)
85 }
86
87 #[inline]
92 pub fn try_clone(&self) -> io::Result<Self> {
93 let file = self.std.try_clone()?;
94 Ok(Self::from_std(file))
95 }
96
97 #[inline]
101 pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
102 self.std
103 .set_permissions(permissions_into_std(&self.std, perm)?)
104 }
105
106 #[inline]
114 pub fn open_ambient<P: AsRef<Path>>(
115 path: P,
116 ambient_authority: AmbientAuthority,
117 ) -> io::Result<Self> {
118 let std = open_ambient(
119 path.as_ref(),
120 OpenOptions::new().read(true),
121 ambient_authority,
122 )?;
123 Ok(Self::from_std(std))
124 }
125
126 #[inline]
135 pub fn create_ambient<P: AsRef<Path>>(
136 path: P,
137 ambient_authority: AmbientAuthority,
138 ) -> io::Result<Self> {
139 let std = open_ambient(
140 path.as_ref(),
141 OpenOptions::new().write(true).create(true).truncate(true),
142 ambient_authority,
143 )?;
144 Ok(Self::from_std(std))
145 }
146
147 #[inline]
156 pub fn open_ambient_with<P: AsRef<Path>>(
157 path: P,
158 options: &OpenOptions,
159 ambient_authority: AmbientAuthority,
160 ) -> io::Result<Self> {
161 let std = open_ambient(path.as_ref(), options, ambient_authority)?;
162 Ok(Self::from_std(std))
163 }
164
165 #[must_use]
169 #[inline]
170 pub fn options() -> OpenOptions {
171 OpenOptions::new()
172 }
173}
174
175#[inline]
176fn metadata_from(file: &fs::File) -> io::Result<Metadata> {
177 Metadata::from_file(file)
178}
179
180#[inline]
181fn permissions_into_std(file: &fs::File, permissions: Permissions) -> io::Result<fs::Permissions> {
182 permissions.into_std(file)
183}
184
185unsafe impl io_lifetimes::views::FilelikeViewType for File {}
187
188#[cfg(not(windows))]
189impl FromRawFd for File {
190 #[inline]
191 unsafe fn from_raw_fd(fd: RawFd) -> Self {
192 Self::from_std(fs::File::from_raw_fd(fd))
193 }
194}
195
196#[cfg(not(windows))]
197impl From<OwnedFd> for File {
198 #[inline]
199 fn from(fd: OwnedFd) -> Self {
200 Self::from_std(fs::File::from(fd))
201 }
202}
203
204#[cfg(windows)]
205impl FromRawHandle for File {
206 #[inline]
207 unsafe fn from_raw_handle(handle: RawHandle) -> Self {
208 Self::from_std(fs::File::from_raw_handle(handle))
209 }
210}
211
212#[cfg(windows)]
213impl From<OwnedHandle> for File {
214 #[inline]
215 fn from(handle: OwnedHandle) -> Self {
216 Self::from_std(fs::File::from(handle))
217 }
218}
219
220#[cfg(not(windows))]
221impl AsRawFd for File {
222 #[inline]
223 fn as_raw_fd(&self) -> RawFd {
224 self.std.as_raw_fd()
225 }
226}
227
228#[cfg(not(windows))]
229impl AsFd for File {
230 #[inline]
231 fn as_fd(&self) -> BorrowedFd<'_> {
232 self.std.as_fd()
233 }
234}
235
236#[cfg(windows)]
237impl AsRawHandle for File {
238 #[inline]
239 fn as_raw_handle(&self) -> RawHandle {
240 self.std.as_raw_handle()
241 }
242}
243
244#[cfg(windows)]
245impl AsHandle for File {
246 #[inline]
247 fn as_handle(&self) -> BorrowedHandle<'_> {
248 self.std.as_handle()
249 }
250}
251
252#[cfg(windows)]
253impl AsRawHandleOrSocket for File {
254 #[inline]
255 fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
256 self.std.as_raw_handle_or_socket()
257 }
258}
259
260#[cfg(windows)]
261impl AsHandleOrSocket for File {
262 #[inline]
263 fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
264 self.std.as_handle_or_socket()
265 }
266}
267
268#[cfg(not(windows))]
269impl IntoRawFd for File {
270 #[inline]
271 fn into_raw_fd(self) -> RawFd {
272 self.std.into_raw_fd()
273 }
274}
275
276#[cfg(not(windows))]
277impl From<File> for OwnedFd {
278 #[inline]
279 fn from(file: File) -> OwnedFd {
280 file.std.into()
281 }
282}
283
284#[cfg(windows)]
285impl IntoRawHandle for File {
286 #[inline]
287 fn into_raw_handle(self) -> RawHandle {
288 self.std.into_raw_handle()
289 }
290}
291
292#[cfg(windows)]
293impl From<File> for OwnedHandle {
294 #[inline]
295 fn from(file: File) -> OwnedHandle {
296 file.std.into()
297 }
298}
299
300#[cfg(windows)]
301impl IntoRawHandleOrSocket for File {
302 #[inline]
303 fn into_raw_handle_or_socket(self) -> RawHandleOrSocket {
304 self.std.into_raw_handle_or_socket()
305 }
306}
307
308#[cfg(windows)]
309impl From<File> for OwnedHandleOrSocket {
310 #[inline]
311 fn from(file: File) -> Self {
312 file.std.into()
313 }
314}
315
316impl Read for File {
317 #[inline]
318 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
319 self.std.read(buf)
320 }
321
322 #[inline]
323 fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
324 self.std.read_vectored(bufs)
325 }
326
327 #[inline]
328 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
329 self.std.read_exact(buf)
330 }
331
332 #[inline]
333 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
334 self.std.read_to_end(buf)
335 }
336
337 #[inline]
338 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
339 self.std.read_to_string(buf)
340 }
341
342 #[cfg(can_vector)]
343 #[inline]
344 fn is_read_vectored(&self) -> bool {
345 self.std.is_read_vectored()
346 }
347}
348
349impl Read for &File {
350 #[inline]
351 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
352 (&mut &self.std).read(buf)
353 }
354
355 #[inline]
356 fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
357 (&mut &self.std).read_vectored(bufs)
358 }
359
360 #[inline]
361 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
362 (&mut &self.std).read_exact(buf)
363 }
364
365 #[inline]
366 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
367 (&mut &self.std).read_to_end(buf)
368 }
369
370 #[inline]
371 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
372 (&mut &self.std).read_to_string(buf)
373 }
374
375 #[cfg(can_vector)]
376 #[inline]
377 fn is_read_vectored(&self) -> bool {
378 self.std.is_read_vectored()
379 }
380}
381
382impl Write for File {
383 #[inline]
384 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
385 self.std.write(buf)
386 }
387
388 #[inline]
389 fn flush(&mut self) -> io::Result<()> {
390 self.std.flush()
391 }
392
393 #[inline]
394 fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result<usize> {
395 self.std.write_vectored(bufs)
396 }
397
398 #[inline]
399 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
400 self.std.write_all(buf)
401 }
402
403 #[cfg(can_vector)]
404 #[inline]
405 fn is_write_vectored(&self) -> bool {
406 self.std.is_write_vectored()
407 }
408
409 #[cfg(write_all_vectored)]
410 #[inline]
411 fn write_all_vectored(&mut self, bufs: &mut [IoSlice]) -> io::Result<()> {
412 self.std.write_all_vectored(bufs)
413 }
414}
415
416impl Write for &File {
417 #[inline]
418 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
419 (&mut &self.std).write(buf)
420 }
421
422 #[inline]
423 fn flush(&mut self) -> io::Result<()> {
424 (&mut &self.std).flush()
425 }
426
427 #[inline]
428 fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result<usize> {
429 (&mut &self.std).write_vectored(bufs)
430 }
431
432 #[inline]
433 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
434 (&mut &self.std).write_all(buf)
435 }
436
437 #[cfg(can_vector)]
438 #[inline]
439 fn is_write_vectored(&self) -> bool {
440 self.std.is_write_vectored()
441 }
442
443 #[cfg(write_all_vectored)]
444 #[inline]
445 fn write_all_vectored(&mut self, bufs: &mut [IoSlice]) -> io::Result<()> {
446 (&mut &self.std).write_all_vectored(bufs)
447 }
448}
449
450impl Seek for File {
451 #[inline]
452 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
453 self.std.seek(pos)
454 }
455
456 #[inline]
457 fn stream_position(&mut self) -> io::Result<u64> {
458 self.std.stream_position()
459 }
460}
461
462impl Seek for &File {
463 #[inline]
464 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
465 (&mut &self.std).seek(pos)
466 }
467
468 #[inline]
469 fn stream_position(&mut self) -> io::Result<u64> {
470 (&mut &self.std).stream_position()
471 }
472}
473
474impl From<File> for process::Stdio {
475 #[inline]
476 fn from(file: File) -> Self {
477 From::<fs::File>::from(file.std)
478 }
479}
480
481#[cfg(unix)]
482impl crate::fs::FileExt for File {
483 #[inline]
484 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
485 std::os::unix::fs::FileExt::read_at(&self.std, buf, offset)
486 }
487
488 #[inline]
489 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
490 std::os::unix::fs::FileExt::write_at(&self.std, buf, offset)
491 }
492
493 #[inline]
494 fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
495 std::os::unix::fs::FileExt::read_exact_at(&self.std, buf, offset)
496 }
497
498 #[inline]
499 fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
500 std::os::unix::fs::FileExt::write_all_at(&self.std, buf, offset)
501 }
502}
503
504#[cfg(target_os = "wasi")]
505impl crate::fs::FileExt for File {
506 #[inline]
507 fn read_at(&self, bufs: &mut [u8], offset: u64) -> io::Result<usize> {
508 std::os::wasi::fs::FileExt::read_at(&self.std, bufs, offset)
509 }
510
511 #[inline]
512 fn write_at(&self, bufs: &[u8], offset: u64) -> io::Result<usize> {
513 std::os::wasi::fs::FileExt::write_at(&self.std, bufs, offset)
514 }
515
516 #[inline]
517 fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
518 std::os::wasi::fs::FileExt::read_vectored_at(&self.std, bufs, offset)
519 }
520
521 #[inline]
522 fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
523 std::os::wasi::fs::FileExt::write_vectored_at(&self.std, bufs, offset)
524 }
525
526 #[inline]
527 fn tell(&self) -> std::result::Result<u64, io::Error> {
528 std::os::wasi::fs::FileExt::tell(&self.std)
529 }
530
531 #[inline]
532 fn fdstat_set_flags(&self, flags: u16) -> std::result::Result<(), io::Error> {
533 std::os::wasi::fs::FileExt::fdstat_set_flags(&self.std, flags)
534 }
535
536 #[inline]
537 fn fdstat_set_rights(
538 &self,
539 rights: u64,
540 inheriting: u64,
541 ) -> std::result::Result<(), io::Error> {
542 std::os::wasi::fs::FileExt::fdstat_set_rights(&self.std, rights, inheriting)
543 }
544
545 #[inline]
546 fn advise(&self, offset: u64, len: u64, advice: u8) -> std::result::Result<(), io::Error> {
547 std::os::wasi::fs::FileExt::advise(&self.std, offset, len, advice)
548 }
549
550 #[inline]
551 fn allocate(&self, offset: u64, len: u64) -> std::result::Result<(), io::Error> {
552 std::os::wasi::fs::FileExt::allocate(&self.std, offset, len)
553 }
554
555 #[inline]
556 fn create_directory<P: AsRef<Path>>(&self, dir: P) -> std::result::Result<(), io::Error> {
557 std::os::wasi::fs::FileExt::create_directory(&self.std, dir)
558 }
559
560 #[inline]
561 fn read_link<P: AsRef<Path>>(
562 &self,
563 path: P,
564 ) -> std::result::Result<std::path::PathBuf, io::Error> {
565 std::os::wasi::fs::FileExt::read_link(&self.std, path)
566 }
567
568 #[inline]
569 fn metadata_at<P: AsRef<Path>>(
570 &self,
571 lookup_flags: u32,
572 path: P,
573 ) -> std::result::Result<std::fs::Metadata, io::Error> {
574 std::os::wasi::fs::FileExt::metadata_at(&self.std, lookup_flags, path)
575 }
576
577 #[inline]
578 fn remove_file<P: AsRef<Path>>(&self, path: P) -> std::result::Result<(), io::Error> {
579 std::os::wasi::fs::FileExt::remove_file(&self.std, path)
580 }
581
582 #[inline]
583 fn remove_directory<P: AsRef<Path>>(&self, path: P) -> std::result::Result<(), io::Error> {
584 std::os::wasi::fs::FileExt::remove_directory(&self.std, path)
585 }
586}
587
588#[cfg(windows)]
589impl crate::fs::FileExt for File {
590 #[inline]
591 fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
592 std::os::windows::fs::FileExt::seek_read(&self.std, buf, offset)
593 }
594
595 #[inline]
596 fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
597 std::os::windows::fs::FileExt::seek_write(&self.std, buf, offset)
598 }
599}
600
601impl fmt::Debug for File {
602 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
604 let mut b = f.debug_struct("File");
605 #[cfg(not(windows))]
606 b.field("fd", &self.std.as_raw_fd());
607 #[cfg(windows)]
608 b.field("handle", &self.std.as_raw_handle());
609 if let Ok((read, write)) = is_file_read_write(&self.std) {
610 b.field("read", &read).field("write", &write);
611 }
612 b.finish()
613 }
614}