standard_lib/fs/path/
rel.rs1use std::ffi::{CString, OsString};
2use std::marker::PhantomData;
3use std::mem::MaybeUninit;
4
5use libc::{EACCES, EBADF, EFAULT, EINVAL, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EOVERFLOW, c_int, stat as Stat};
6
7use super::{Abs, OwnedPath, Path, PathState};
8use crate::fs::error::{ExcessiveLinksError, MetadataOverflowError, MissingComponentError, NoSearchError, NonDirComponentError, OOMError, PathLengthError};
9use crate::fs::file::MetadataError;
10use crate::fs::panic::{BadFdPanic, BadStackAddrPanic, InvalidOpPanic, Panic, UnexpectedErrorPanic};
11use crate::fs::{Directory, Metadata};
12use crate::fs::path::{PathError, PathOrMetadataError};
13use crate::util::{self, sealed::Sealed};
14
15#[derive(Debug)]
16pub enum Rel {}
17
18impl Sealed for Rel {}
19
20impl PathState for Rel {}
21
22impl OwnedPath<Rel> {
23 pub(crate) unsafe fn dot_slash_dot() -> OwnedPath<Rel> {
25 OwnedPath::<Rel> {
26 _state: PhantomData,
27 inner: OsString::from("/."),
28 }
29 }
30
31 pub fn dot() -> OwnedPath<Rel> {
32 OwnedPath::<Rel> {
33 _state: PhantomData,
34 inner: OsString::from("/"),
35 }
36 }
37
38 pub fn resolve_root(self) -> OwnedPath<Abs> {
39 let OwnedPath { _state, inner } = self;
40 OwnedPath {
41 _state: PhantomData,
42 inner
43 }
44 }
45}
46
47impl Path<Rel> {
48 pub fn dot_slash() -> &'static Path<Rel> {
49 unsafe { Path::from_unchecked("/") }
50 }
51
52 pub fn resolve(&self, mut target: OwnedPath<Abs>) -> OwnedPath<Abs> {
53 target.push(self);
54 target
55 }
56
57 pub fn resolve_root(&self) -> OwnedPath<Abs> {
58 self.resolve(OwnedPath::root())
59 }
60
61 pub fn resolve_home(&self) -> Option<OwnedPath<Abs>> {
62 Some(self.resolve(OwnedPath::home()?))
63 }
64
65 pub fn resolve_cwd(&self) -> Option<OwnedPath<Abs>> {
66 Some(self.resolve(OwnedPath::cwd()?))
67 }
68
69 pub(crate) fn metadata_raw(&self, relative_to: Directory, flags: c_int) -> Result<Metadata, PathOrMetadataError> {
72 let pathname = CString::from(self.to_owned());
74
75 let mut raw_meta: MaybeUninit<Stat> = MaybeUninit::uninit();
76 if unsafe { libc::fstatat(
77 *relative_to.fd,
78 pathname.as_ptr().add(1).cast(),
80 raw_meta.as_mut_ptr(),
81 flags
82 ) } == -1 {
83 match util::fs::err_no() {
84 EACCES => Err(PathError::from(NoSearchError))?,
85 EBADF => BadFdPanic.panic(),
86 EFAULT => BadStackAddrPanic.panic(),
87 EINVAL => InvalidOpPanic.panic(),
88 ELOOP => Err(PathError::from(ExcessiveLinksError))?,
89 ENAMETOOLONG => Err(PathError::from(PathLengthError))?,
90 ENOENT => Err(PathError::from(MissingComponentError))?,
91 ENOMEM => Err(MetadataError::from(OOMError))?,
92 ENOTDIR => Err(PathError::from(NonDirComponentError))?,
93 EOVERFLOW => Err(MetadataError::from(MetadataOverflowError))?,
94 e => UnexpectedErrorPanic(e).panic(),
95 }
96 }
97 let raw = unsafe { raw_meta.assume_init() };
99
100 Ok(Metadata::from_stat(raw))
101 }
102
103 pub fn metadata(&self, relative_to: Directory) -> Result<Metadata, PathOrMetadataError> {
104 self.metadata_raw(relative_to, 0)
105 }
106
107 pub fn metadata_no_follow(&self, relative_to: Directory) -> Result<Metadata, PathOrMetadataError> {
108 self.metadata_raw(relative_to, libc::AT_SYMLINK_NOFOLLOW)
109 }
110}