1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
/// Filesystem attributes.
///
/// Currently not used.
#[non_exhaustive]
pub struct FileSystemInfo;
/// Node (file/directory) attributes.
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct VfsNodeAttr {
/// File permission mode.
mode: VfsNodePerm,
/// File type.
ty: VfsNodeType,
/// Total size, in bytes.
size: u64,
/// Number of 512B blocks allocated.
blocks: u64,
}
bitflags::bitflags! {
/// Node (file/directory) permission mode.
#[derive(Debug, Clone, Copy)]
pub struct VfsNodePerm: u16 {
/// Owner has read permission.
const OWNER_READ = 0o400;
/// Owner has write permission.
const OWNER_WRITE = 0o200;
/// Owner has execute permission.
const OWNER_EXEC = 0o100;
/// Group has read permission.
const GROUP_READ = 0o40;
/// Group has write permission.
const GROUP_WRITE = 0o20;
/// Group has execute permission.
const GROUP_EXEC = 0o10;
/// Others have read permission.
const OTHER_READ = 0o4;
/// Others have write permission.
const OTHER_WRITE = 0o2;
/// Others have execute permission.
const OTHER_EXEC = 0o1;
}
}
/// Node (file/directory) type.
#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum VfsNodeType {
/// FIFO (named pipe)
Fifo = 0o1,
/// Character device
CharDevice = 0o2,
/// Directory
Dir = 0o4,
/// Block device
BlockDevice = 0o6,
/// Regular file
File = 0o10,
/// Symbolic link
SymLink = 0o12,
/// Socket
Socket = 0o14,
}
/// Directory entry.
pub struct VfsDirEntry {
d_type: VfsNodeType,
d_name: [u8; 63],
}
impl VfsNodePerm {
/// Returns the default permission for a file.
///
/// The default permission is `0o666` (owner/group/others can read and write).
pub const fn default_file() -> Self {
Self::from_bits_truncate(0o666)
}
/// Returns the default permission for a directory.
///
/// The default permission is `0o755` (owner can read, write and execute,
/// group/others can read and execute).
pub const fn default_dir() -> Self {
Self::from_bits_truncate(0o755)
}
/// Returns the underlying raw `st_mode` bits that contain the standard
/// Unix permissions for this file.
pub const fn mode(&self) -> u32 {
self.bits() as u32
}
/// Returns a 9-bytes string representation of the permission.
///
/// For example, `0o755` is represented as `rwxr-xr-x`.
pub const fn rwx_buf(&self) -> [u8; 9] {
let mut perm = [b'-'; 9];
if self.contains(Self::OWNER_READ) {
perm[0] = b'r';
}
if self.contains(Self::OWNER_WRITE) {
perm[1] = b'w';
}
if self.contains(Self::OWNER_EXEC) {
perm[2] = b'x';
}
if self.contains(Self::GROUP_READ) {
perm[3] = b'r';
}
if self.contains(Self::GROUP_WRITE) {
perm[4] = b'w';
}
if self.contains(Self::GROUP_EXEC) {
perm[5] = b'x';
}
if self.contains(Self::OTHER_READ) {
perm[6] = b'r';
}
if self.contains(Self::OTHER_WRITE) {
perm[7] = b'w';
}
if self.contains(Self::OTHER_EXEC) {
perm[8] = b'x';
}
perm
}
/// Whether the owner has read permission.
pub const fn owner_readable(&self) -> bool {
self.contains(Self::OWNER_READ)
}
/// Whether the owner has write permission.
pub const fn owner_writable(&self) -> bool {
self.contains(Self::OWNER_WRITE)
}
/// Whether the owner has execute permission.
pub const fn owner_executable(&self) -> bool {
self.contains(Self::OWNER_EXEC)
}
}
impl VfsNodeType {
/// Tests whether this node type represents a regular file.
pub const fn is_file(self) -> bool {
matches!(self, Self::File)
}
/// Tests whether this node type represents a directory.
pub const fn is_dir(self) -> bool {
matches!(self, Self::Dir)
}
/// Tests whether this node type represents a symbolic link.
pub const fn is_symlink(self) -> bool {
matches!(self, Self::SymLink)
}
/// Returns `true` if this node type is a block device.
pub const fn is_block_device(self) -> bool {
matches!(self, Self::BlockDevice)
}
/// Returns `true` if this node type is a char device.
pub const fn is_char_device(self) -> bool {
matches!(self, Self::CharDevice)
}
/// Returns `true` if this node type is a fifo.
pub const fn is_fifo(self) -> bool {
matches!(self, Self::Fifo)
}
/// Returns `true` if this node type is a socket.
pub const fn is_socket(self) -> bool {
matches!(self, Self::Socket)
}
/// Returns a character representation of the node type.
///
/// For example, `d` for directory, `-` for regular file, etc.
pub const fn as_char(self) -> char {
match self {
Self::Fifo => 'p',
Self::CharDevice => 'c',
Self::Dir => 'd',
Self::BlockDevice => 'b',
Self::File => '-',
Self::SymLink => 'l',
Self::Socket => 's',
}
}
}
impl VfsNodeAttr {
/// Creates a new `VfsNodeAttr` with the given permission mode, type, size
/// and number of blocks.
pub const fn new(mode: VfsNodePerm, ty: VfsNodeType, size: u64, blocks: u64) -> Self {
Self {
mode,
ty,
size,
blocks,
}
}
/// Creates a new `VfsNodeAttr` for a file, with the default file permission.
pub const fn new_file(size: u64, blocks: u64) -> Self {
Self {
mode: VfsNodePerm::default_file(),
ty: VfsNodeType::File,
size,
blocks,
}
}
/// Creates a new `VfsNodeAttr` for a directory, with the default directory
/// permission.
pub const fn new_dir(size: u64, blocks: u64) -> Self {
Self {
mode: VfsNodePerm::default_dir(),
ty: VfsNodeType::Dir,
size,
blocks,
}
}
/// Returns the size of the node.
pub const fn size(&self) -> u64 {
self.size
}
/// Returns the number of blocks the node occupies on the disk.
pub const fn blocks(&self) -> u64 {
self.blocks
}
/// Returns the permission of the node.
pub const fn perm(&self) -> VfsNodePerm {
self.mode
}
/// Sets the permission of the node.
pub fn set_perm(&mut self, perm: VfsNodePerm) {
self.mode = perm
}
/// Returns the type of the node.
pub const fn file_type(&self) -> VfsNodeType {
self.ty
}
/// Whether the node is a file.
pub const fn is_file(&self) -> bool {
self.ty.is_file()
}
/// Whether the node is a directory.
pub const fn is_dir(&self) -> bool {
self.ty.is_dir()
}
}
impl VfsDirEntry {
/// Creates an empty `VfsDirEntry`.
pub const fn default() -> Self {
Self {
d_type: VfsNodeType::File,
d_name: [0; 63],
}
}
/// Creates a new `VfsDirEntry` with the given name and type.
pub fn new(name: &str, ty: VfsNodeType) -> Self {
let mut d_name = [0; 63];
if name.len() > d_name.len() {
log::warn!(
"directory entry name too long: {} > {}",
name.len(),
d_name.len()
);
}
d_name[..name.len()].copy_from_slice(name.as_bytes());
Self { d_type: ty, d_name }
}
/// Returns the type of the entry.
pub fn entry_type(&self) -> VfsNodeType {
self.d_type
}
/// Converts the name of the entry to a byte slice.
pub fn name_as_bytes(&self) -> &[u8] {
let len = self
.d_name
.iter()
.position(|&c| c == 0)
.unwrap_or(self.d_name.len());
&self.d_name[..len]
}
}