Skip to main content

path_extra/std/
path.rs

1use std::{
2    borrow::Cow,
3    ffi::OsStr,
4    fs::{self, File, Metadata, ReadDir},
5    io::{self, Write},
6    path::{self, Path, PathBuf},
7};
8#[cfg(unix)]
9use std::{
10    fs::Permissions,
11    os::unix::{self, fs::PermissionsExt as _},
12};
13
14#[cfg(unix)]
15use pathdiff::diff_paths;
16
17use super::temp_path::TempPath;
18
19pub trait PathExt {
20    fn base(&self) -> io::Result<&Path>;
21    fn with_base(&self, base: impl AsRef<Path>) -> Cow<'_, Path>;
22
23    fn file_suffix(&self) -> Option<&OsStr>;
24
25    fn absolute(&self) -> io::Result<PathBuf>;
26
27    fn metadata(&self) -> io::Result<Metadata>;
28    fn symlink_metadata(&self) -> io::Result<Metadata>;
29    fn canonicalize(&self) -> io::Result<PathBuf>;
30    fn read_link(&self) -> io::Result<PathBuf>;
31    fn read_dir(&self) -> io::Result<ReadDir>;
32
33    fn try_exists(&self) -> io::Result<bool>;
34
35    fn try_is_file(&self) -> io::Result<bool>;
36    fn try_is_dir(&self) -> io::Result<bool>;
37    fn try_is_symlink(&self) -> io::Result<bool>;
38
39    fn metadata_if_exists(&self) -> io::Result<Option<Metadata>>;
40    fn symlink_metadata_if_exists(&self) -> io::Result<Option<Metadata>>;
41    fn canonicalize_if_exists(&self) -> io::Result<Option<PathBuf>>;
42    fn read_link_if_exists(&self) -> io::Result<Option<PathBuf>>;
43    fn read_dir_if_exists(&self) -> io::Result<Option<ReadDir>>;
44
45    fn exists_nofollow(&self) -> bool;
46    fn is_file_nofollow(&self) -> bool;
47    fn is_dir_nofollow(&self) -> bool;
48
49    fn try_exists_nofollow(&self) -> io::Result<bool>;
50    fn try_is_file_nofollow(&self) -> io::Result<bool>;
51    fn try_is_dir_nofollow(&self) -> io::Result<bool>;
52
53    fn try_is_read_dir_empty(&self) -> io::Result<bool>;
54    fn try_is_read_dir_empty_if_exists(&self) -> io::Result<Option<bool>>;
55
56    fn read(&self) -> io::Result<Vec<u8>>;
57    fn read_if_exists(&self) -> io::Result<Option<Vec<u8>>>;
58
59    fn read_to_string(&self) -> io::Result<String>;
60    fn read_to_string_if_exists(&self) -> io::Result<Option<String>>;
61
62    fn create_dir_all(self) -> io::Result<Self>
63    where
64        Self: Sized;
65
66    fn create_dir(self) -> io::Result<Self>
67    where
68        Self: Sized;
69    fn create_dir_if_not_exists(self) -> io::Result<Option<Self>>
70    where
71        Self: Sized;
72
73    fn write_new(self, contents: impl AsRef<[u8]>) -> io::Result<Self>
74    where
75        Self: Sized;
76    fn write_new_if_not_exists(self, contents: impl AsRef<[u8]>) -> io::Result<Option<Self>>
77    where
78        Self: Sized;
79
80    fn write(self, contents: impl AsRef<[u8]>) -> io::Result<Self>
81    where
82        Self: Sized;
83    fn write_if_exists(self, contents: impl AsRef<[u8]>) -> io::Result<Option<Self>>
84    where
85        Self: Sized;
86
87    fn append(self, contents: impl AsRef<[u8]>) -> io::Result<Self>
88    where
89        Self: Sized;
90    fn append_if_exists(self, contents: impl AsRef<[u8]>) -> io::Result<Option<Self>>
91    where
92        Self: Sized;
93
94    fn copy(self, to: impl AsRef<Path>) -> io::Result<Self>
95    where
96        Self: Sized;
97    fn copy_if_exists(self, to: impl AsRef<Path>) -> io::Result<Option<Self>>
98    where
99        Self: Sized;
100
101    fn rename(self, to: impl AsRef<Path>) -> io::Result<Self>
102    where
103        Self: Sized;
104    fn rename_if_exists(self, to: impl AsRef<Path>) -> io::Result<Option<Self>>
105    where
106        Self: Sized;
107
108    fn remove_file(self) -> io::Result<Self>
109    where
110        Self: Sized;
111    fn remove_file_if_exists(self) -> io::Result<Option<Self>>
112    where
113        Self: Sized;
114
115    fn remove_dir(self) -> io::Result<Self>
116    where
117        Self: Sized;
118    fn remove_dir_if_exists(self) -> io::Result<Option<Self>>
119    where
120        Self: Sized;
121
122    fn remove_dir_all(self) -> io::Result<Self>
123    where
124        Self: Sized;
125    fn remove_dir_all_if_exists(self) -> io::Result<Option<Self>>
126    where
127        Self: Sized;
128
129    fn hard_link(self, link: impl AsRef<Path>) -> io::Result<Self>
130    where
131        Self: Sized;
132    fn hard_link_atomic(self, link: impl AsRef<Path>) -> io::Result<Self>
133    where
134        Self: Sized;
135
136    #[cfg(unix)]
137    fn symlink(self, link: impl AsRef<Path>) -> io::Result<Self>
138    where
139        Self: Sized;
140    #[cfg(unix)]
141    fn symlink_atomic(self, link: impl AsRef<Path>) -> io::Result<Self>
142    where
143        Self: Sized;
144
145    #[cfg(unix)]
146    fn symlink_absolute(self, link: impl AsRef<Path>) -> io::Result<Self>
147    where
148        Self: Sized;
149    #[cfg(unix)]
150    fn symlink_absolute_atomic(self, link: impl AsRef<Path>) -> io::Result<Self>
151    where
152        Self: Sized;
153
154    #[cfg(unix)]
155    fn symlink_relative(self, link: impl AsRef<Path>) -> io::Result<Self>
156    where
157        Self: Sized;
158    #[cfg(unix)]
159    fn symlink_relative_atomic(self, link: impl AsRef<Path>) -> io::Result<Self>
160    where
161        Self: Sized;
162
163    #[cfg(unix)]
164    fn set_permissions(self, permissions: Permissions) -> io::Result<Self>
165    where
166        Self: Sized;
167
168    #[cfg(unix)]
169    fn set_permissions_mode(self, permissions_mode: u32) -> io::Result<Self>
170    where
171        Self: Sized;
172    #[cfg(unix)]
173    fn add_permissions_mode(self, permissions_mode: u32) -> io::Result<Self>
174    where
175        Self: Sized;
176    #[cfg(unix)]
177    fn remove_permissions_mode(self, permissions_mode: u32) -> io::Result<Self>
178    where
179        Self: Sized;
180}
181
182impl<T: AsRef<Path>> PathExt for T {
183    #[inline]
184    fn base(&self) -> io::Result<&Path> {
185        self.as_ref()
186            .parent()
187            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Path has no parent"))
188    }
189
190    #[inline]
191    fn with_base(&self, base: impl AsRef<Path>) -> Cow<'_, Path> {
192        if self.as_ref().is_relative() {
193            let path = base.as_ref().join(self);
194
195            Cow::Owned(path)
196        } else {
197            Cow::Borrowed(self.as_ref())
198        }
199    }
200
201    #[inline]
202    fn file_suffix(&self) -> Option<&OsStr> {
203        let file_name = self.as_ref().file_name()?;
204        let file_prefix = self.as_ref().file_prefix()?;
205
206        let bytes = file_name.as_encoded_bytes();
207
208        let start = file_prefix.as_encoded_bytes().len() + 1;
209
210        if start <= bytes.len() {
211            let slice = &bytes[start..];
212
213            let os_str = unsafe { OsStr::from_encoded_bytes_unchecked(slice) };
214
215            Some(os_str)
216        } else {
217            None
218        }
219    }
220
221    #[inline]
222    fn absolute(&self) -> io::Result<PathBuf> {
223        path::absolute(self)
224    }
225
226    #[inline]
227    fn metadata(&self) -> io::Result<Metadata> {
228        self.as_ref().metadata()
229    }
230
231    #[inline]
232    fn symlink_metadata(&self) -> io::Result<Metadata> {
233        self.as_ref().symlink_metadata()
234    }
235
236    #[inline]
237    fn canonicalize(&self) -> io::Result<PathBuf> {
238        self.as_ref().canonicalize()
239    }
240
241    #[inline]
242    fn read_link(&self) -> io::Result<PathBuf> {
243        self.as_ref().read_link()
244    }
245
246    #[inline]
247    fn read_dir(&self) -> io::Result<ReadDir> {
248        self.as_ref().read_dir()
249    }
250
251    #[inline]
252    fn try_exists(&self) -> io::Result<bool> {
253        self.as_ref().try_exists()
254    }
255
256    #[inline]
257    fn try_is_file(&self) -> io::Result<bool> {
258        self.metadata_if_exists().map(|metadata_opt| {
259            metadata_opt
260                .map(|metadata| metadata.is_file())
261                .unwrap_or(false)
262        })
263    }
264
265    #[inline]
266    fn try_is_dir(&self) -> io::Result<bool> {
267        self.metadata_if_exists().map(|metadata_opt| {
268            metadata_opt
269                .map(|metadata| metadata.is_dir())
270                .unwrap_or(false)
271        })
272    }
273
274    #[inline]
275    fn try_is_symlink(&self) -> io::Result<bool> {
276        self.symlink_metadata_if_exists().map(|metadata_opt| {
277            metadata_opt
278                .map(|metadata| metadata.is_symlink())
279                .unwrap_or(false)
280        })
281    }
282
283    #[inline]
284    fn metadata_if_exists(&self) -> io::Result<Option<Metadata>> {
285        match self.metadata() {
286            Ok(metadata) => Ok(Some(metadata)),
287            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
288            Err(err) => Err(err),
289        }
290    }
291
292    #[inline]
293    fn symlink_metadata_if_exists(&self) -> io::Result<Option<Metadata>> {
294        match self.symlink_metadata() {
295            Ok(metadata) => Ok(Some(metadata)),
296            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
297            Err(err) => Err(err),
298        }
299    }
300
301    #[inline]
302    fn canonicalize_if_exists(&self) -> io::Result<Option<PathBuf>> {
303        match self.canonicalize() {
304            Ok(path) => Ok(Some(path)),
305            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
306            Err(err) => Err(err),
307        }
308    }
309
310    #[inline]
311    fn read_link_if_exists(&self) -> io::Result<Option<PathBuf>> {
312        match self.read_link() {
313            Ok(path) => Ok(Some(path)),
314            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
315            Err(err) => Err(err),
316        }
317    }
318
319    #[inline]
320    fn read_dir_if_exists(&self) -> io::Result<Option<ReadDir>> {
321        match self.read_dir() {
322            Ok(entries) => Ok(Some(entries)),
323            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
324            Err(err) => Err(err),
325        }
326    }
327
328    #[inline]
329    fn exists_nofollow(&self) -> bool {
330        self.symlink_metadata().is_ok()
331    }
332
333    #[inline]
334    fn is_file_nofollow(&self) -> bool {
335        self.symlink_metadata()
336            .map(|metadata| metadata.is_file())
337            .unwrap_or(false)
338    }
339
340    #[inline]
341    fn is_dir_nofollow(&self) -> bool {
342        self.symlink_metadata()
343            .map(|metadata| metadata.is_dir())
344            .unwrap_or(false)
345    }
346
347    #[inline]
348    fn try_exists_nofollow(&self) -> io::Result<bool> {
349        self.symlink_metadata_if_exists()
350            .map(|metadata_opt| metadata_opt.is_some())
351    }
352
353    #[inline]
354    fn try_is_file_nofollow(&self) -> io::Result<bool> {
355        self.symlink_metadata_if_exists().map(|metadata_opt| {
356            metadata_opt
357                .map(|metadata| metadata.is_file())
358                .unwrap_or(false)
359        })
360    }
361
362    #[inline]
363    fn try_is_dir_nofollow(&self) -> io::Result<bool> {
364        self.symlink_metadata_if_exists().map(|metadata_opt| {
365            metadata_opt
366                .map(|metadata| metadata.is_dir())
367                .unwrap_or(false)
368        })
369    }
370
371    #[inline]
372    fn try_is_read_dir_empty(&self) -> io::Result<bool> {
373        let mut entries = self.read_dir()?;
374
375        entries
376            .next()
377            .transpose()
378            .map(|entry_opt| entry_opt.is_none())
379    }
380
381    #[inline]
382    fn try_is_read_dir_empty_if_exists(&self) -> io::Result<Option<bool>> {
383        match self.try_is_read_dir_empty() {
384            Ok(is_empty) => Ok(Some(is_empty)),
385            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
386            Err(err) => Err(err),
387        }
388    }
389
390    #[inline]
391    fn read(&self) -> io::Result<Vec<u8>> {
392        fs::read(self)
393    }
394
395    #[inline]
396    fn read_if_exists(&self) -> io::Result<Option<Vec<u8>>> {
397        match self.read() {
398            Ok(bytes) => Ok(Some(bytes)),
399            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
400            Err(err) => Err(err),
401        }
402    }
403
404    #[inline]
405    fn read_to_string(&self) -> io::Result<String> {
406        fs::read_to_string(self)
407    }
408
409    #[inline]
410    fn read_to_string_if_exists(&self) -> io::Result<Option<String>> {
411        match self.read_to_string() {
412            Ok(string) => Ok(Some(string)),
413            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
414            Err(err) => Err(err),
415        }
416    }
417
418    #[inline]
419    fn create_dir_all(self) -> io::Result<Self> {
420        fs::create_dir_all(self.as_ref())?;
421
422        Ok(self)
423    }
424
425    #[inline]
426    fn create_dir(self) -> io::Result<Self> {
427        fs::create_dir(self.as_ref())?;
428
429        Ok(self)
430    }
431
432    #[inline]
433    fn create_dir_if_not_exists(self) -> io::Result<Option<Self>> {
434        match self.as_ref().create_dir() {
435            Ok(_) => Ok(Some(self)),
436            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
437            Err(err) => Err(err),
438        }
439    }
440
441    #[inline]
442    fn write_new(self, contents: impl AsRef<[u8]>) -> io::Result<Self> {
443        let mut options = File::options();
444
445        options.write(true).create_new(true);
446
447        let mut file = options.open(self.as_ref())?;
448
449        file.write_all(contents.as_ref())?;
450
451        Ok(self)
452    }
453
454    #[inline]
455    fn write_new_if_not_exists(self, contents: impl AsRef<[u8]>) -> io::Result<Option<Self>> {
456        match self.as_ref().write_new(contents) {
457            Ok(_) => Ok(Some(self)),
458            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
459            Err(err) => Err(err),
460        }
461    }
462
463    #[inline]
464    fn write(self, contents: impl AsRef<[u8]>) -> io::Result<Self> {
465        fs::write(self.as_ref(), contents)?;
466
467        Ok(self)
468    }
469
470    #[inline]
471    fn write_if_exists(self, contents: impl AsRef<[u8]>) -> io::Result<Option<Self>> {
472        let mut options = File::options();
473
474        options.write(true).truncate(true);
475
476        match options.open(self.as_ref()) {
477            Ok(mut file) => {
478                file.write_all(contents.as_ref())?;
479
480                Ok(Some(self))
481            },
482            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
483            Err(err) => Err(err),
484        }
485    }
486
487    #[inline]
488    fn append(self, contents: impl AsRef<[u8]>) -> io::Result<Self> {
489        let mut options = File::options();
490
491        options.append(true).create(true);
492
493        let mut file = options.open(self.as_ref())?;
494
495        file.write_all(contents.as_ref())?;
496
497        Ok(self)
498    }
499
500    #[inline]
501    fn append_if_exists(self, contents: impl AsRef<[u8]>) -> io::Result<Option<Self>> {
502        let mut options = File::options();
503
504        options.append(true);
505
506        match options.open(self.as_ref()) {
507            Ok(mut file) => {
508                file.write_all(contents.as_ref())?;
509
510                Ok(Some(self))
511            },
512            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
513            Err(err) => Err(err),
514        }
515    }
516
517    #[inline]
518    fn copy(self, to: impl AsRef<Path>) -> io::Result<Self> {
519        fs::copy(self.as_ref(), to)?;
520
521        Ok(self)
522    }
523
524    #[inline]
525    fn copy_if_exists(self, to: impl AsRef<Path>) -> io::Result<Option<Self>> {
526        match self.as_ref().copy(to) {
527            Ok(_) => Ok(Some(self)),
528            Err(err) if err.kind() == io::ErrorKind::NotFound => {
529                if !self.try_exists()? {
530                    Ok(None)
531                } else {
532                    Err(err)
533                }
534            },
535            Err(err) => Err(err),
536        }
537    }
538
539    #[inline]
540    fn rename(self, to: impl AsRef<Path>) -> io::Result<Self> {
541        fs::rename(self.as_ref(), to)?;
542
543        Ok(self)
544    }
545
546    #[inline]
547    fn rename_if_exists(self, to: impl AsRef<Path>) -> io::Result<Option<Self>> {
548        match self.as_ref().rename(to) {
549            Ok(_) => Ok(Some(self)),
550            Err(err) if err.kind() == io::ErrorKind::NotFound => {
551                if !self.try_exists_nofollow()? {
552                    Ok(None)
553                } else {
554                    Err(err)
555                }
556            },
557            Err(err) => Err(err),
558        }
559    }
560
561    #[inline]
562    fn remove_file(self) -> io::Result<Self> {
563        fs::remove_file(self.as_ref())?;
564
565        Ok(self)
566    }
567
568    #[inline]
569    fn remove_file_if_exists(self) -> io::Result<Option<Self>> {
570        match self.as_ref().remove_file() {
571            Ok(_) => Ok(Some(self)),
572            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
573            Err(err) => Err(err),
574        }
575    }
576
577    #[inline]
578    fn remove_dir(self) -> io::Result<Self> {
579        fs::remove_dir(self.as_ref())?;
580
581        Ok(self)
582    }
583
584    #[inline]
585    fn remove_dir_if_exists(self) -> io::Result<Option<Self>> {
586        match self.as_ref().remove_dir() {
587            Ok(_) => Ok(Some(self)),
588            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
589            Err(err) => Err(err),
590        }
591    }
592
593    #[inline]
594    fn remove_dir_all(self) -> io::Result<Self> {
595        fs::remove_dir_all(self.as_ref())?;
596
597        Ok(self)
598    }
599
600    #[inline]
601    fn remove_dir_all_if_exists(self) -> io::Result<Option<Self>> {
602        match self.as_ref().remove_dir_all() {
603            Ok(_) => Ok(Some(self)),
604            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
605            Err(err) => Err(err),
606        }
607    }
608
609    #[inline]
610    fn hard_link(self, link: impl AsRef<Path>) -> io::Result<Self> {
611        fs::hard_link(self.as_ref(), link)?;
612
613        Ok(self)
614    }
615
616    #[inline]
617    fn hard_link_atomic(self, link: impl AsRef<Path>) -> io::Result<Self> {
618        let temp = TempPath::try_from_path(link.as_ref())?;
619
620        self.as_ref().hard_link(temp.path())?;
621
622        temp.persist(link)?;
623
624        Ok(self)
625    }
626
627    #[cfg(unix)]
628    #[inline]
629    fn symlink(self, link: impl AsRef<Path>) -> io::Result<Self> {
630        unix::fs::symlink(self.as_ref(), link)?;
631
632        Ok(self)
633    }
634
635    #[cfg(unix)]
636    #[inline]
637    fn symlink_atomic(self, link: impl AsRef<Path>) -> io::Result<Self> {
638        let temp = TempPath::try_from_path(link.as_ref())?;
639
640        self.as_ref().symlink(temp.path())?;
641
642        temp.persist(link)?;
643
644        Ok(self)
645    }
646
647    #[cfg(unix)]
648    #[inline]
649    fn symlink_absolute(self, link: impl AsRef<Path>) -> io::Result<Self> {
650        #[expect(unstable_name_collisions)]
651        let absolute = self.as_ref().absolute()?;
652
653        absolute.symlink(link)?;
654
655        Ok(self)
656    }
657
658    #[cfg(unix)]
659    #[inline]
660    fn symlink_absolute_atomic(self, link: impl AsRef<Path>) -> io::Result<Self> {
661        #[expect(unstable_name_collisions)]
662        let absolute = self.as_ref().absolute()?;
663
664        absolute.symlink_atomic(link)?;
665
666        Ok(self)
667    }
668
669    #[cfg(unix)]
670    #[inline]
671    fn symlink_relative(self, link: impl AsRef<Path>) -> io::Result<Self> {
672        let base = link.base()?;
673
674        let relative = diff_paths(self.as_ref(), base)
675            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Failed to diff paths"))?;
676
677        relative.symlink(link)?;
678
679        Ok(self)
680    }
681
682    #[cfg(unix)]
683    #[inline]
684    fn symlink_relative_atomic(self, link: impl AsRef<Path>) -> io::Result<Self> {
685        let base = link.base()?;
686
687        let relative = diff_paths(self.as_ref(), base)
688            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Failed to diff paths"))?;
689
690        relative.symlink_atomic(link)?;
691
692        Ok(self)
693    }
694
695    #[cfg(unix)]
696    #[inline]
697    fn set_permissions(self, permissions: Permissions) -> io::Result<Self> {
698        fs::set_permissions(self.as_ref(), permissions)?;
699
700        Ok(self)
701    }
702
703    #[cfg(unix)]
704    #[inline]
705    fn set_permissions_mode(self, permissions_mode: u32) -> io::Result<Self> {
706        let metadata = self.metadata()?;
707
708        let mut permissions = metadata.permissions();
709
710        permissions.set_mode(permissions_mode);
711
712        self.set_permissions(permissions)
713    }
714
715    #[cfg(unix)]
716    #[inline]
717    fn add_permissions_mode(self, permissions_mode: u32) -> io::Result<Self> {
718        let metadata = self.metadata()?;
719
720        let mut permissions = metadata.permissions();
721
722        permissions.set_mode(permissions.mode() | permissions_mode);
723
724        self.set_permissions(permissions)
725    }
726
727    #[cfg(unix)]
728    #[inline]
729    fn remove_permissions_mode(self, permissions_mode: u32) -> io::Result<Self> {
730        let metadata = self.metadata()?;
731
732        let mut permissions = metadata.permissions();
733
734        permissions.set_mode(permissions.mode() & !permissions_mode);
735
736        self.set_permissions(permissions)
737    }
738}
739
740macro_rules! define_option_path_ext {
741    (
742        $(
743            $(#[$meta:meta])*
744            fn $method:ident(self $(, $arg:ident: $ty:ty)* $(,)*) -> $ret:ty;
745        )*
746    ) => {
747        pub trait OptionPathExt<T> {
748            $(
749                $(#[$meta])*
750                fn $method(self $(, $arg: $ty)*) -> $ret;
751            )*
752        }
753
754        impl<T: PathExt> OptionPathExt<T> for Option<T> {
755            $(
756                #[inline]
757                $(#[$meta])*
758                fn $method(self $(, $arg: $ty)*) -> $ret {
759                    match self {
760                        Some(path) => path.$method($($arg),*).map(Some),
761                        None => Ok(None),
762                    }
763                }
764            )*
765        }
766    };
767}
768
769define_option_path_ext! {
770    fn metadata(self) -> io::Result<Option<Metadata>>;
771    fn symlink_metadata(self) -> io::Result<Option<Metadata>>;
772    fn canonicalize(self) -> io::Result<Option<PathBuf>>;
773    fn read_link(self) -> io::Result<Option<PathBuf>>;
774    fn read_dir(self) -> io::Result<Option<ReadDir>>;
775
776    fn try_exists(self) -> io::Result<Option<bool>>;
777
778    fn try_is_file(self) -> io::Result<Option<bool>>;
779    fn try_is_dir(self) -> io::Result<Option<bool>>;
780    fn try_is_symlink(self) -> io::Result<Option<bool>>;
781
782    fn try_exists_nofollow(self) -> io::Result<Option<bool>>;
783    fn try_is_file_nofollow(self) -> io::Result<Option<bool>>;
784    fn try_is_dir_nofollow(self) -> io::Result<Option<bool>>;
785
786    fn try_is_read_dir_empty(self) -> io::Result<Option<bool>>;
787
788    fn read(self) -> io::Result<Option<Vec<u8>>>;
789
790    fn read_to_string(self) -> io::Result<Option<String>>;
791
792    fn create_dir_all(self) -> io::Result<Option<T>>;
793
794    fn create_dir(self) -> io::Result<Option<T>>;
795
796    fn write_new(self, contents: impl AsRef<[u8]>) -> io::Result<Option<T>>;
797
798    fn write(self, contents: impl AsRef<[u8]>) -> io::Result<Option<T>>;
799
800    fn append(self, contents: impl AsRef<[u8]>) -> io::Result<Option<T>>;
801
802    fn copy(self, to: impl AsRef<Path>) -> io::Result<Option<T>>;
803
804    fn rename(self, to: impl AsRef<Path>) -> io::Result<Option<T>>;
805
806    fn remove_file(self) -> io::Result<Option<T>>;
807
808    fn remove_dir(self) -> io::Result<Option<T>>;
809
810    fn remove_dir_all(self) -> io::Result<Option<T>>;
811
812    fn hard_link(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
813    fn hard_link_atomic(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
814
815    #[cfg(unix)]
816    fn symlink(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
817    #[cfg(unix)]
818    fn symlink_atomic(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
819
820    #[cfg(unix)]
821    fn symlink_absolute(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
822    #[cfg(unix)]
823    fn symlink_absolute_atomic(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
824
825    #[cfg(unix)]
826    fn symlink_relative(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
827    #[cfg(unix)]
828    fn symlink_relative_atomic(self, link: impl AsRef<Path>) -> io::Result<Option<T>>;
829
830    #[cfg(unix)]
831    fn set_permissions(self, permissions: Permissions) -> io::Result<Option<T>>;
832
833    #[cfg(unix)]
834    fn set_permissions_mode(self, permissions_mode: u32) -> io::Result<Option<T>>;
835    #[cfg(unix)]
836    fn add_permissions_mode(self, permissions_mode: u32) -> io::Result<Option<T>>;
837    #[cfg(unix)]
838    fn remove_permissions_mode(self, permissions_mode: u32) -> io::Result<Option<T>>;
839}