standard_lib/fs/path/
abs.rs

1use std::env;
2use std::ffi::{CString, OsString};
3use std::io::RawOsError;
4use std::marker::PhantomData;
5use std::mem::MaybeUninit;
6
7use libc::{EACCES, EBADF, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EOVERFLOW, 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        Some(OwnedPath::<Abs>::from(
36            env::home_dir()?.as_os_str()
37        ))
38    }
39
40    pub fn cwd() -> Option<OwnedPath<Abs>> {
41        // libc::getcwd()
42        Some(OwnedPath::<Abs>::from(
43            env::current_dir().ok()?.as_os_str()
44        ))
45    }
46}
47
48impl Path<Abs> {
49    pub fn root() -> &'static Path<Abs> {
50        unsafe { Path::from_unchecked("/") }
51    }
52
53    pub fn read_all_links(&self) -> Result<OwnedPath<Abs>, RawOsError> {
54        // TODO: canonicalize with many readlink calls, needs to handle nonexistence
55        todo!()
56    }
57
58    pub fn normalize_lexically(&self) -> OwnedPath<Abs> {
59        // TODO: use components iter and collect
60        todo!()
61    }
62
63    pub fn make_relative<P: AsRef<Path<Abs>>>(&self, from: P) -> OwnedPath<Rel> {
64        // TODO: Include ../.. etc.
65        todo!("{:?}", &from.as_ref())
66    }
67
68    // no follow with O_NOFOLLOW
69
70    // read_* shortcuts for file
71
72    pub(crate) fn match_metadata_error() -> Result<(), PathOrMetadataError> {
73        match util::fs::err_no() {
74            EACCES       => Err(PathError::from(NoSearchError))?,
75            EBADF        => BadFdPanic.panic(),
76            EFAULT       => BadStackAddrPanic.panic(),
77            ELOOP        => Err(PathError::from(ExcessiveLinksError))?,
78            ENAMETOOLONG => Err(PathError::from(PathLengthError))?,
79            ENOENT       => Err(PathError::from(MissingComponentError))?,
80            ENOMEM       => Err(MetadataError::from(OOMError))?,
81            ENOTDIR      => Err(PathError::from(NonDirComponentError))?,
82            EOVERFLOW    => Err(MetadataError::from(MetadataOverflowError))?,
83            e            => UnexpectedErrorPanic(e).panic(),
84        }
85    }
86
87    pub fn metadata(&self) -> Result<Metadata, PathOrMetadataError> {
88        // FIXME: Copy here feels bad.
89        let pathname = CString::from(self.to_owned());
90
91        let mut raw_meta: MaybeUninit<Stat> = MaybeUninit::uninit();
92        if unsafe { libc::stat(pathname.as_ptr().cast(), raw_meta.as_mut_ptr()) } == -1 {
93            Self::match_metadata_error()?
94        }
95        // SAFETY: stat either initializes raw_meta or returns an error and diverges.
96        let raw = unsafe { raw_meta.assume_init() };
97
98        Ok(Metadata::from_stat(raw))
99    }
100
101    pub fn metadata_no_follow(&self) -> Result<Metadata, PathOrMetadataError> {
102        let pathname = CString::from(self.to_owned());
103
104        let mut raw_meta: MaybeUninit<Stat> = MaybeUninit::uninit();
105        if unsafe { libc::lstat(pathname.as_ptr().cast(), raw_meta.as_mut_ptr()) } == -1 {
106            Self::match_metadata_error()?
107        }
108        // SAFETY: stat either initializes raw_meta or returns an error and diverges.
109        let raw = unsafe { raw_meta.assume_init() };
110
111        Ok(Metadata::from_stat(raw))
112    }
113
114    // NOTE: Symlinks can't be opened, so all symlink-related APIs need to be handled here.
115
116    // create_symlink
117    // read_link
118    // is_symlink
119    // create_hardlink
120
121    // rename
122    // move_dir
123    // remove (unlink)
124    // rmdir
125    // copy (sendfile)
126    // chmod
127    // chown
128    // exists
129    // try_exists
130    // access
131
132    // set_cwd
133}