standard_lib/fs/path/
abs.rs

1use std::env;
2use std::ffi::{CString, OsStr, OsString};
3use std::io::RawOsError;
4use std::marker::PhantomData;
5use std::mem::MaybeUninit;
6
7use libc::stat as Stat;
8
9use super::{OwnedPath, Path, PathState, Rel};
10use crate::fs::error::{ExcessiveLinksError, MetadataOverflowError, MissingComponentError, NoSearchError, NonDirComponentError, OOMError, PathLengthError};
11use crate::fs::panic::{BadFdPanic, BadStackAddrPanic, Panic, UnexpectedErrorPanic};
12use crate::fs::path::{PathError, PathOrMetadataError};
13use crate::fs::Metadata;
14use crate::fs::file::MetadataError;
15use crate::util::{self, sealed::Sealed};
16
17#[derive(Debug)]
18pub enum Abs {}
19
20impl Sealed for Abs {}
21
22impl PathState for Abs {}
23
24impl OwnedPath<Abs> {
25    pub fn root() -> OwnedPath<Abs> {
26        OwnedPath::<Abs> {
27            _state: PhantomData,
28            inner: OsString::from("/"),
29        }
30    }
31
32    pub fn home() -> Option<OwnedPath<Abs>> {
33        // TODO: This is a terrible implementation, it copies an owned PathBuf. Also, I'd like to
34        // avoid env::home_dir().
35        env::home_dir().map(|dir| OwnedPath::<Abs>::from(dir.as_os_str()))
36    }
37
38    pub fn cwd() -> Option<OwnedPath<Abs>> {
39        // libc::getcwd()
40        env::current_dir().ok().map(|dir| OwnedPath::<Abs>::from(dir.as_os_str()))
41    }
42}
43
44impl Path<Abs> {
45    pub fn read_all_links(&self) -> Result<OwnedPath<Abs>, RawOsError> {
46        todo!("canonicalize with many readlink calls, needs to handle nonexistence")
47    }
48
49    pub fn normalize_lexically(&self) -> OwnedPath<Abs> {
50        todo!("use components iter and collect")
51    }
52
53    pub fn make_relative<P: AsRef<Path<Abs>>>(&self, from: P) -> OwnedPath<Rel> {
54        // TODO: Include ../.. etc.
55        todo!("{:?}", &from.as_ref())
56    }
57
58    // no follow with O_NOFOLLOW
59
60    // read_* shortcuts for file
61
62    pub(crate) fn match_metadata_error() -> Result<(), PathOrMetadataError> {
63        match util::fs::err_no() {
64            libc::EACCES => Err(PathError::from(NoSearchError))?,
65            libc::EBADF => BadFdPanic.panic(),
66            libc::EFAULT => BadStackAddrPanic.panic(),
67            libc::ELOOP => Err(PathError::from(ExcessiveLinksError))?,
68            libc::ENAMETOOLONG => Err(PathError::from(PathLengthError))?,
69            libc::ENOENT => Err(PathError::from(MissingComponentError))?,
70            libc::ENOMEM => Err(MetadataError::from(OOMError))?,
71            libc::ENOTDIR => Err(PathError::from(NonDirComponentError))?,
72            libc::EOVERFLOW => Err(MetadataError::from(MetadataOverflowError))?,
73            e => UnexpectedErrorPanic(e).panic(),
74        }
75    }
76
77    pub fn metadata(&self) -> Result<Metadata, PathOrMetadataError> {
78        // FIXME: Copy here feels bad.
79        let pathname = CString::from(self.to_owned());
80
81        let mut raw_meta: MaybeUninit<Stat> = MaybeUninit::uninit();
82        if unsafe { libc::stat(pathname.as_ptr().cast(), raw_meta.as_mut_ptr()) } == -1 {
83            Self::match_metadata_error()?
84        }
85        // SAFETY: stat either initializes raw_meta or returns an error and diverges.
86        let raw = unsafe { raw_meta.assume_init() };
87
88        Ok(Metadata::from_stat(raw))
89    }
90
91    pub fn metadata_no_follow(&self) -> Result<Metadata, PathOrMetadataError> {
92        let pathname = CString::from(self.to_owned());
93
94        let mut raw_meta: MaybeUninit<Stat> = MaybeUninit::uninit();
95        if unsafe { libc::lstat(pathname.as_ptr().cast(), raw_meta.as_mut_ptr()) } == -1 {
96            Self::match_metadata_error()?
97        }
98        // SAFETY: stat either initializes raw_meta or returns an error and diverges.
99        let raw = unsafe { raw_meta.assume_init() };
100
101        Ok(Metadata::from_stat(raw))
102    }
103
104    // NOTE: Symlinks can't be opened, so all symlink-related APIs need to be handled here.
105
106    // create_symlink
107    // read_link
108    // is_symlink
109    // create_hardlink
110
111    // rename
112    // move_dir
113    // remove (unlink)
114    // rmdir
115    // copy (sendfile)
116    // chmod
117    // chown
118    // exists
119    // try_exists
120    // access
121
122    // set_cwd
123}
124
125impl<O: AsRef<OsStr>> From<O> for OwnedPath<Abs> {
126    fn from(value: O) -> Self {
127        Self::from_os_str_sanitized(value.as_ref())
128    }
129}