yash_env/system/
file_system.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2021 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Items about file systems
18
19use super::{Gid, Result, Uid};
20use crate::io::Fd;
21use crate::str::UnixStr;
22use bitflags::bitflags;
23use std::fmt::Debug;
24
25#[cfg(unix)]
26const RAW_AT_FDCWD: i32 = libc::AT_FDCWD;
27#[cfg(not(unix))]
28const RAW_AT_FDCWD: i32 = -100;
29
30/// Sentinel for the current working directory
31///
32/// This value can be passed to system calls named "*at" such as
33/// [`fstatat`](super::System::fstatat).
34pub const AT_FDCWD: Fd = Fd(RAW_AT_FDCWD);
35
36/// Metadata of a file contained in a directory
37///
38/// `DirEntry` objects are enumerated by a [`Dir`] implementor.
39#[derive(Clone, Copy, Debug)]
40#[non_exhaustive]
41pub struct DirEntry<'a> {
42    /// Filename
43    pub name: &'a UnixStr,
44}
45
46/// Trait for enumerating directory entries
47///
48/// An implementor of `Dir` may retain a file descriptor (or any other resource
49/// alike) to access the underlying system and obtain entry information. The
50/// file descriptor is released when the implementor object is dropped.
51pub trait Dir: Debug {
52    /// Returns the next directory entry.
53    fn next(&mut self) -> Result<Option<DirEntry<'_>>>;
54}
55
56#[cfg(unix)]
57type RawModeDef = libc::mode_t;
58#[cfg(not(unix))]
59type RawModeDef = u32;
60
61/// Raw file permission bits type
62///
63/// This is a type alias for the raw file permission bits type `mode_t` declared
64/// in the [`libc`] crate. The exact representation of this type is
65/// platform-dependent while POSIX requires the type to be an integer. On
66/// non-Unix platforms, this type is hard-coded to `u32`.
67///
68/// File permission bits are usually wrapped in the [`Mode`] type for better type
69/// safety, so this type is not used directly in most cases.
70pub type RawMode = RawModeDef;
71
72/// File permission bits
73///
74/// This type implements the new type pattern for the raw file permission bits
75/// type [`RawMode`]. The advantage of using this type is that it is more
76/// type-safe than using the raw integer value directly.
77///
78/// This type only defines the permission bits and does not include the file
79/// type bits (e.g., regular file, directory, symbolic link, etc.). The file
80/// types are represented by the [`FileType`] enum.
81#[derive(Copy, Clone, Eq, Hash, PartialEq)]
82#[repr(transparent)]
83pub struct Mode(RawMode);
84
85bitflags! {
86    impl Mode: RawMode {
87        /// User read permission (`0o400`)
88        const USER_READ = 0o400;
89        /// User write permission (`0o200`)
90        const USER_WRITE = 0o200;
91        /// User execute permission (`0o100`)
92        const USER_EXEC = 0o100;
93        /// User read, write, and execute permissions (`0o700`)
94        const USER_ALL = 0o700;
95        /// Group read permission (`0o040`)
96        const GROUP_READ = 0o040;
97        /// Group write permission (`0o020`)
98        const GROUP_WRITE = 0o020;
99        /// Group execute permission (`0o010`)
100        const GROUP_EXEC = 0o010;
101        /// Group read, write, and execute permissions (`0o070`)
102        const GROUP_ALL = 0o070;
103        /// Other read permission (`0o004`)
104        const OTHER_READ = 0o004;
105        /// Other write permission (`0o002`)
106        const OTHER_WRITE = 0o002;
107        /// Other execute permission (`0o001`)
108        const OTHER_EXEC = 0o001;
109        /// Other read, write, and execute permissions (`0o007`)
110        const OTHER_ALL = 0o007;
111        /// All read permission (`0o444`)
112        const ALL_READ = 0o444;
113        /// All write permission (`0o222`)
114        const ALL_WRITE = 0o222;
115        /// All execute permission (`0o111`)
116        const ALL_EXEC = 0o111;
117        /// All combinations of (user, group, other) × (read, write, execute)
118        ///
119        /// Note that this is equivalent to `Mode::USER_ALL | Mode::GROUP_ALL |
120        /// Mode::OTHER_ALL` and does not include the sticky bit, the
121        /// set-user-ID bit, or the set-group-ID bit.
122        const ALL_9 = 0o777;
123        /// Set-user-ID bit (`0o4000`)
124        const SET_USER_ID = 0o4000;
125        /// Set-group-ID bit (`0o2000`)
126        const SET_GROUP_ID = 0o2000;
127        /// Sticky bit (`0o1000`)
128        const STICKY = 0o1000;
129    }
130}
131
132impl Debug for Mode {
133    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134        write!(f, "Mode({:#o})", self.0)
135    }
136}
137
138/// The default mode is `0o644`, not `0o000`.
139impl Default for Mode {
140    fn default() -> Mode {
141        Mode(0o644)
142    }
143}
144
145/// File type
146#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
147#[non_exhaustive]
148pub enum FileType {
149    /// Regular file
150    Regular,
151    /// Directory
152    Directory,
153    /// Symbolic link
154    Symlink,
155    /// Pipe
156    Fifo,
157    /// Block special device file
158    BlockDevice,
159    /// Character special device file
160    CharacterDevice,
161    /// Socket
162    Socket,
163    /// Other file type, including unknown file types
164    Other,
165}
166
167/// File status
168///
169/// This type is a collection of file status information. It is similar to the
170/// `stat` structure defined in the POSIX standard, but it is simplified and
171/// does not include all fields of the `stat` structure.
172#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
173#[non_exhaustive]
174pub struct Stat {
175    /// Device ID
176    pub dev: u64,
177    /// Inode number
178    pub ino: u64,
179    /// Access permissions
180    ///
181    /// Note that this field does not include the file type bits.
182    /// The file type is stored in the `type` field.
183    pub mode: Mode,
184    /// File type
185    pub r#type: FileType,
186    /// Number of hard links
187    pub nlink: u64,
188    /// User ID of the file owner
189    pub uid: Uid,
190    /// Group ID of the file owner
191    pub gid: Gid,
192    /// Length of the file in bytes
193    pub size: u64,
194    // TODO: atime, mtime, ctime, (birthtime)
195}
196
197impl Stat {
198    /// Returns the device ID and inode number as a tuple
199    ///
200    /// This method is useful for testing whether two `Stat` objects refer to
201    /// the same file.
202    #[inline]
203    #[must_use]
204    pub const fn identity(&self) -> (u64, u64) {
205        (self.dev, self.ino)
206    }
207}