2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2024-02-25 14:09:24 +00:00
|
|
|
use core::{
|
2024-05-22 07:51:48 +00:00
|
|
|
sync::atomic::{AtomicU64, Ordering},
|
2024-02-25 14:09:24 +00:00
|
|
|
time::Duration,
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-19 08:56:42 +00:00
|
|
|
use align_ext::AlignExt;
|
2024-03-20 05:57:49 +00:00
|
|
|
use aster_block::bio::BioWaiter;
|
2024-06-19 08:18:39 +00:00
|
|
|
use aster_util::slot_vec::SlotVec;
|
2024-09-14 07:15:28 +00:00
|
|
|
use hashbrown::HashMap;
|
2024-06-19 08:18:39 +00:00
|
|
|
use ostd::{
|
2025-10-28 08:50:57 +00:00
|
|
|
mm::{io_util::HasVmReaderWriter, HasSize},
|
2024-11-19 10:35:20 +00:00
|
|
|
sync::{PreemptDisabled, RwLockWriteGuard},
|
2024-02-25 14:09:24 +00:00
|
|
|
};
|
2023-01-05 08:55:58 +00:00
|
|
|
|
2025-03-28 06:00:34 +00:00
|
|
|
use super::{xattr::RamXattr, *};
|
2024-02-25 14:09:24 +00:00
|
|
|
use crate::{
|
|
|
|
|
events::IoEvents,
|
|
|
|
|
fs::{
|
|
|
|
|
device::Device,
|
2024-08-16 09:29:01 +00:00
|
|
|
file_handle::FileLike,
|
|
|
|
|
named_pipe::NamedPipe,
|
2025-01-16 08:17:27 +00:00
|
|
|
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
2025-07-17 03:24:21 +00:00
|
|
|
registry::{FsProperties, FsType},
|
2024-02-25 14:09:24 +00:00
|
|
|
utils::{
|
2025-09-21 13:26:39 +00:00
|
|
|
mkmod, CStr256, CachePage, DirentVisitor, Extension, FallocMode, FileSystem, FsFlags,
|
|
|
|
|
Inode, InodeMode, InodeType, IoctlCmd, Metadata, MknodType, PageCache,
|
|
|
|
|
PageCacheBackend, Permission, SuperBlock, XattrName, XattrNamespace, XattrSetFlags,
|
2024-02-25 14:09:24 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
prelude::*,
|
2024-10-24 09:45:47 +00:00
|
|
|
process::{signal::PollHandle, Gid, Uid},
|
2024-06-13 06:53:09 +00:00
|
|
|
time::clocks::RealTimeCoarseClock,
|
2024-02-25 14:09:24 +00:00
|
|
|
vm::vmo::Vmo,
|
2023-01-05 08:55:58 +00:00
|
|
|
};
|
|
|
|
|
|
2023-05-18 08:57:29 +00:00
|
|
|
/// A volatile file system whose data and metadata exists only in memory.
|
2025-09-07 15:36:15 +00:00
|
|
|
pub struct RamFs {
|
2024-05-22 07:51:48 +00:00
|
|
|
/// The super block
|
|
|
|
|
sb: SuperBlock,
|
|
|
|
|
/// Root inode
|
2023-01-05 08:55:58 +00:00
|
|
|
root: Arc<RamInode>,
|
2024-05-22 07:51:48 +00:00
|
|
|
/// An inode allocator
|
|
|
|
|
inode_allocator: AtomicU64,
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
impl RamFs {
|
2023-09-13 04:07:58 +00:00
|
|
|
pub fn new() -> Arc<Self> {
|
2024-05-22 07:51:48 +00:00
|
|
|
Arc::new_cyclic(|weak_fs| Self {
|
|
|
|
|
sb: SuperBlock::new(RAMFS_MAGIC, BLOCK_SIZE, NAME_MAX),
|
|
|
|
|
root: Arc::new_cyclic(|weak_root| RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
inner: Inner::new_dir(weak_root.clone(), weak_root.clone()),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new_dir(
|
2025-09-21 13:26:39 +00:00
|
|
|
mkmod!(a+rx, u+w),
|
2024-05-22 07:51:48 +00:00
|
|
|
Uid::new_root(),
|
|
|
|
|
Gid::new_root(),
|
|
|
|
|
)),
|
|
|
|
|
ino: ROOT_INO,
|
|
|
|
|
typ: InodeType::Dir,
|
|
|
|
|
this: weak_root.clone(),
|
|
|
|
|
fs: weak_fs.clone(),
|
2024-08-09 03:18:50 +00:00
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2024-05-22 07:51:48 +00:00
|
|
|
}),
|
|
|
|
|
inode_allocator: AtomicU64::new(ROOT_INO + 1),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn alloc_id(&self) -> u64 {
|
|
|
|
|
self.inode_allocator.fetch_add(1, Ordering::SeqCst)
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
impl FileSystem for RamFs {
|
2025-10-24 02:36:32 +00:00
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
"ramfs"
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
fn sync(&self) -> Result<()> {
|
|
|
|
|
// do nothing
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn root_inode(&self) -> Arc<dyn Inode> {
|
|
|
|
|
self.root.clone()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn sb(&self) -> SuperBlock {
|
2024-05-22 07:51:48 +00:00
|
|
|
self.sb.clone()
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
/// An inode of `RamFs`.
|
2024-05-22 07:51:48 +00:00
|
|
|
struct RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
/// Inode inner specifics
|
|
|
|
|
inner: Inner,
|
|
|
|
|
/// Inode metadata
|
|
|
|
|
metadata: SpinLock<InodeMeta>,
|
2024-05-22 07:51:48 +00:00
|
|
|
/// Inode number
|
|
|
|
|
ino: u64,
|
|
|
|
|
/// Type of the inode
|
|
|
|
|
typ: InodeType,
|
|
|
|
|
/// Reference to self
|
2023-01-05 08:55:58 +00:00
|
|
|
this: Weak<RamInode>,
|
2024-05-22 07:51:48 +00:00
|
|
|
/// Reference to fs
|
2025-09-07 15:36:15 +00:00
|
|
|
fs: Weak<RamFs>,
|
2024-08-09 03:18:50 +00:00
|
|
|
/// Extensions
|
|
|
|
|
extension: Extension,
|
2025-03-28 06:00:34 +00:00
|
|
|
/// Extended attributes
|
|
|
|
|
xattr: RamXattr,
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
/// Inode inner specifics.
|
|
|
|
|
enum Inner {
|
|
|
|
|
Dir(RwLock<DirEntry>),
|
|
|
|
|
File(PageCache),
|
|
|
|
|
SymLink(SpinLock<String>),
|
|
|
|
|
Device(Arc<dyn Device>),
|
|
|
|
|
Socket,
|
|
|
|
|
NamedPipe(NamedPipe),
|
2024-05-22 07:51:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
impl Inner {
|
|
|
|
|
pub fn new_dir(this: Weak<RamInode>, parent: Weak<RamInode>) -> Self {
|
|
|
|
|
Self::Dir(RwLock::new(DirEntry::new(this, parent)))
|
2023-03-22 04:02:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn new_file(this: Weak<RamInode>) -> Self {
|
|
|
|
|
Self::File(PageCache::new(this).unwrap())
|
2023-03-22 04:02:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn new_symlink() -> Self {
|
|
|
|
|
Self::SymLink(SpinLock::new(String::from("")))
|
2023-03-22 04:02:19 +00:00
|
|
|
}
|
2023-09-13 04:07:58 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn new_device(device: Arc<dyn Device>) -> Self {
|
|
|
|
|
Self::Device(device)
|
2024-07-04 07:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn new_socket() -> Self {
|
|
|
|
|
Self::Socket
|
2024-07-04 07:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn new_named_pipe() -> Self {
|
|
|
|
|
Self::NamedPipe(NamedPipe::new().unwrap())
|
2024-07-04 07:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
fn as_direntry(&self) -> Option<&RwLock<DirEntry>> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Dir(dir_entry) => Some(dir_entry),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
2024-07-04 07:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
fn as_file(&self) -> Option<&PageCache> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::File(page_cache) => Some(page_cache),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
2024-07-04 07:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
fn as_symlink(&self) -> Option<&SpinLock<String>> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::SymLink(link) => Some(link),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
2024-07-04 07:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
fn as_device(&self) -> Option<&Arc<dyn Device>> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Device(device) => Some(device),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2025-10-30 08:12:51 +00:00
|
|
|
fn open(
|
|
|
|
|
&self,
|
|
|
|
|
access_mode: AccessMode,
|
|
|
|
|
status_flags: StatusFlags,
|
|
|
|
|
) -> Option<Result<Arc<dyn FileIo>>> {
|
2024-09-26 12:23:56 +00:00
|
|
|
match self {
|
2025-10-30 08:12:51 +00:00
|
|
|
Self::Device(device) => device.open(),
|
|
|
|
|
Self::NamedPipe(pipe) => Some(pipe.open(access_mode, status_flags)),
|
2024-09-26 12:23:56 +00:00
|
|
|
_ => None,
|
|
|
|
|
}
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
/// Inode metadata.
|
2024-05-22 07:51:48 +00:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
struct InodeMeta {
|
|
|
|
|
size: usize,
|
|
|
|
|
blocks: usize,
|
|
|
|
|
atime: Duration,
|
|
|
|
|
mtime: Duration,
|
|
|
|
|
ctime: Duration,
|
|
|
|
|
mode: InodeMode,
|
|
|
|
|
nlinks: usize,
|
|
|
|
|
uid: Uid,
|
|
|
|
|
gid: Gid,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InodeMeta {
|
|
|
|
|
pub fn new(mode: InodeMode, uid: Uid, gid: Gid) -> Self {
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-05-22 07:51:48 +00:00
|
|
|
Self {
|
|
|
|
|
size: 0,
|
|
|
|
|
blocks: 0,
|
2024-06-13 06:53:09 +00:00
|
|
|
atime: now,
|
|
|
|
|
mtime: now,
|
|
|
|
|
ctime: now,
|
2024-05-22 07:51:48 +00:00
|
|
|
mode,
|
|
|
|
|
nlinks: 1,
|
|
|
|
|
uid,
|
|
|
|
|
gid,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_dir(mode: InodeMode, uid: Uid, gid: Gid) -> Self {
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-05-22 07:51:48 +00:00
|
|
|
Self {
|
2024-09-14 07:15:28 +00:00
|
|
|
size: NUM_SPECIAL_ENTRIES,
|
2024-05-22 07:51:48 +00:00
|
|
|
blocks: 1,
|
2024-06-13 06:53:09 +00:00
|
|
|
atime: now,
|
|
|
|
|
mtime: now,
|
|
|
|
|
ctime: now,
|
2024-05-22 07:51:48 +00:00
|
|
|
mode,
|
2024-09-14 07:15:28 +00:00
|
|
|
nlinks: NUM_SPECIAL_ENTRIES,
|
2024-05-22 07:51:48 +00:00
|
|
|
uid,
|
|
|
|
|
gid,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn resize(&mut self, new_size: usize) {
|
|
|
|
|
self.size = new_size;
|
|
|
|
|
self.blocks = new_size.align_up(BLOCK_SIZE) / BLOCK_SIZE;
|
|
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn inc_size(&mut self) {
|
|
|
|
|
self.size += 1;
|
|
|
|
|
self.blocks = self.size.align_up(BLOCK_SIZE) / BLOCK_SIZE;
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn dec_size(&mut self) {
|
|
|
|
|
debug_assert!(self.size > 0);
|
|
|
|
|
self.size -= 1;
|
|
|
|
|
self.blocks = self.size.align_up(BLOCK_SIZE) / BLOCK_SIZE;
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn set_atime(&mut self, time: Duration) {
|
|
|
|
|
self.atime = time;
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn set_mtime(&mut self, time: Duration) {
|
|
|
|
|
self.mtime = time;
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn set_ctime(&mut self, time: Duration) {
|
|
|
|
|
self.ctime = time;
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
2023-05-18 08:57:29 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn inc_nlinks(&mut self) {
|
|
|
|
|
self.nlinks += 1;
|
2023-05-18 08:57:29 +00:00
|
|
|
}
|
2024-09-02 13:23:46 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
pub fn dec_nlinks(&mut self) {
|
|
|
|
|
debug_assert!(self.nlinks > 0);
|
|
|
|
|
self.nlinks -= 1;
|
2024-09-02 13:23:46 +00:00
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-14 07:15:28 +00:00
|
|
|
/// Represents a directory entry within a `RamInode`.
|
2023-01-05 08:55:58 +00:00
|
|
|
struct DirEntry {
|
2023-09-18 03:47:17 +00:00
|
|
|
children: SlotVec<(CStr256, Arc<RamInode>)>,
|
2024-09-14 07:15:28 +00:00
|
|
|
idx_map: HashMap<CStr256, usize>, // Used to accelerate indexing in `children`
|
2023-01-05 08:55:58 +00:00
|
|
|
this: Weak<RamInode>,
|
|
|
|
|
parent: Weak<RamInode>,
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-14 07:15:28 +00:00
|
|
|
// Every directory has two special entries: "." and "..".
|
|
|
|
|
const NUM_SPECIAL_ENTRIES: usize = 2;
|
|
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
impl DirEntry {
|
2024-05-22 07:51:48 +00:00
|
|
|
fn new(this: Weak<RamInode>, parent: Weak<RamInode>) -> Self {
|
2023-01-05 08:55:58 +00:00
|
|
|
Self {
|
2023-04-18 10:09:57 +00:00
|
|
|
children: SlotVec::new(),
|
2024-09-14 07:15:28 +00:00
|
|
|
idx_map: HashMap::new(),
|
2024-05-22 07:51:48 +00:00
|
|
|
this,
|
|
|
|
|
parent,
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_parent(&mut self, parent: Weak<RamInode>) {
|
|
|
|
|
self.parent = parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn contains_entry(&self, name: &str) -> bool {
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dot_or_dotdot(name) {
|
2023-01-05 08:55:58 +00:00
|
|
|
true
|
|
|
|
|
} else {
|
2024-09-14 07:15:28 +00:00
|
|
|
self.idx_map.contains_key(name.as_bytes())
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_entry(&self, name: &str) -> Option<(usize, Arc<RamInode>)> {
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dot(name) {
|
2023-01-05 08:55:58 +00:00
|
|
|
Some((0, self.this.upgrade().unwrap()))
|
2025-01-16 08:17:27 +00:00
|
|
|
} else if is_dotdot(name) {
|
2023-01-05 08:55:58 +00:00
|
|
|
Some((1, self.parent.upgrade().unwrap()))
|
|
|
|
|
} else {
|
2024-09-14 07:15:28 +00:00
|
|
|
let idx = *self.idx_map.get(name.as_bytes())?;
|
|
|
|
|
let target_inode = self
|
|
|
|
|
.children
|
|
|
|
|
.get(idx)
|
|
|
|
|
.map(|(name_cstr256, inode)| {
|
|
|
|
|
debug_assert_eq!(name, name_cstr256.as_str().unwrap());
|
|
|
|
|
inode.clone()
|
|
|
|
|
})
|
|
|
|
|
.unwrap();
|
|
|
|
|
Some((idx + NUM_SPECIAL_ENTRIES, target_inode))
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-18 10:09:57 +00:00
|
|
|
fn append_entry(&mut self, name: &str, inode: Arc<RamInode>) -> usize {
|
2024-09-14 07:15:28 +00:00
|
|
|
let name = CStr256::from(name);
|
|
|
|
|
let idx = self.children.put((name, inode));
|
|
|
|
|
self.idx_map.insert(name, idx);
|
|
|
|
|
idx
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
fn remove_entry(&mut self, idx: usize) -> Option<(CStr256, Arc<RamInode>)> {
|
2024-09-14 07:15:28 +00:00
|
|
|
assert!(idx >= NUM_SPECIAL_ENTRIES);
|
|
|
|
|
let removed = self.children.remove(idx - NUM_SPECIAL_ENTRIES)?;
|
|
|
|
|
self.idx_map.remove(&removed.0);
|
|
|
|
|
Some(removed)
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-24 10:15:08 +00:00
|
|
|
fn substitute_entry(
|
|
|
|
|
&mut self,
|
|
|
|
|
idx: usize,
|
2023-09-18 03:47:17 +00:00
|
|
|
new_entry: (CStr256, Arc<RamInode>),
|
|
|
|
|
) -> Option<(CStr256, Arc<RamInode>)> {
|
2024-09-14 07:15:28 +00:00
|
|
|
assert!(idx >= NUM_SPECIAL_ENTRIES);
|
|
|
|
|
let new_name = new_entry.0;
|
|
|
|
|
let idx_children = idx - NUM_SPECIAL_ENTRIES;
|
|
|
|
|
|
|
|
|
|
let substitute = self.children.put_at(idx_children, new_entry)?;
|
|
|
|
|
let removed = self.idx_map.remove(&substitute.0);
|
|
|
|
|
debug_assert_eq!(removed.unwrap(), idx_children);
|
|
|
|
|
self.idx_map.insert(new_name, idx_children);
|
|
|
|
|
Some(substitute)
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-18 09:19:32 +00:00
|
|
|
fn visit_entry(&self, idx: usize, visitor: &mut dyn DirentVisitor) -> Result<usize> {
|
2023-03-08 07:08:31 +00:00
|
|
|
let try_visit = |idx: &mut usize, visitor: &mut dyn DirentVisitor| -> Result<()> {
|
|
|
|
|
// Read the two special entries("." and "..").
|
|
|
|
|
if *idx == 0 {
|
|
|
|
|
let this_inode = self.this.upgrade().unwrap();
|
2024-05-22 07:51:48 +00:00
|
|
|
visitor.visit(".", this_inode.ino, this_inode.typ, *idx)?;
|
2023-03-08 07:08:31 +00:00
|
|
|
*idx += 1;
|
|
|
|
|
}
|
|
|
|
|
if *idx == 1 {
|
|
|
|
|
let parent_inode = self.parent.upgrade().unwrap();
|
2024-05-22 07:51:48 +00:00
|
|
|
visitor.visit("..", parent_inode.ino, parent_inode.typ, *idx)?;
|
2023-03-08 07:08:31 +00:00
|
|
|
*idx += 1;
|
|
|
|
|
}
|
|
|
|
|
// Read the normal child entries.
|
2023-09-04 03:04:42 +00:00
|
|
|
let start_idx = *idx;
|
2024-09-14 07:15:28 +00:00
|
|
|
for (offset_children, (name, child)) in self
|
2023-03-24 10:15:08 +00:00
|
|
|
.children
|
2023-04-18 10:09:57 +00:00
|
|
|
.idxes_and_items()
|
2024-09-14 07:15:28 +00:00
|
|
|
.skip_while(|(offset, _)| offset + NUM_SPECIAL_ENTRIES < start_idx)
|
2023-03-24 10:15:08 +00:00
|
|
|
{
|
2024-09-14 07:15:28 +00:00
|
|
|
let offset = offset_children + NUM_SPECIAL_ENTRIES;
|
2024-05-22 07:51:48 +00:00
|
|
|
visitor.visit(name.as_str().unwrap(), child.ino, child.typ, offset)?;
|
2023-03-24 10:15:08 +00:00
|
|
|
*idx = offset + 1;
|
2023-03-08 07:08:31 +00:00
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-18 09:19:32 +00:00
|
|
|
let mut iterate_idx = idx;
|
|
|
|
|
match try_visit(&mut iterate_idx, visitor) {
|
|
|
|
|
Err(e) if idx == iterate_idx => Err(e),
|
|
|
|
|
_ => Ok(iterate_idx - idx),
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_empty_children(&self) -> bool {
|
|
|
|
|
self.children.is_empty()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-18 09:19:32 +00:00
|
|
|
impl RamInode {
|
2024-05-22 07:51:48 +00:00
|
|
|
fn new_dir(
|
2025-09-07 15:36:15 +00:00
|
|
|
fs: &Arc<RamFs>,
|
2024-05-22 07:51:48 +00:00
|
|
|
mode: InodeMode,
|
|
|
|
|
uid: Uid,
|
|
|
|
|
gid: Gid,
|
|
|
|
|
parent: &Weak<RamInode>,
|
|
|
|
|
) -> Arc<Self> {
|
|
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
inner: Inner::new_dir(weak_self.clone(), parent.clone()),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new_dir(mode, uid, gid)),
|
2024-05-22 07:51:48 +00:00
|
|
|
ino: fs.alloc_id(),
|
|
|
|
|
typ: InodeType::Dir,
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Arc::downgrade(fs),
|
2024-08-09 03:18:50 +00:00
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2023-07-18 09:19:32 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
fn new_file(fs: &Arc<RamFs>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
2024-05-22 07:51:48 +00:00
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
inner: Inner::new_file(weak_self.clone()),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
2024-05-22 07:51:48 +00:00
|
|
|
ino: fs.alloc_id(),
|
|
|
|
|
typ: InodeType::File,
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Arc::downgrade(fs),
|
2024-08-09 03:18:50 +00:00
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2023-07-18 09:19:32 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-30 09:00:08 +00:00
|
|
|
fn new_file_detached(mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
|
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
|
|
|
|
inner: Inner::new_file(weak_self.clone()),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
|
|
|
|
ino: weak_self.as_ptr() as u64,
|
|
|
|
|
typ: InodeType::File,
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Weak::new(),
|
|
|
|
|
extension: Extension::new(),
|
|
|
|
|
xattr: RamXattr::new(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
fn new_symlink(fs: &Arc<RamFs>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
2024-05-22 07:51:48 +00:00
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
inner: Inner::new_symlink(),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
2024-05-22 07:51:48 +00:00
|
|
|
ino: fs.alloc_id(),
|
|
|
|
|
typ: InodeType::SymLink,
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Arc::downgrade(fs),
|
2024-08-09 03:18:50 +00:00
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2023-08-09 07:10:33 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-22 07:51:48 +00:00
|
|
|
fn new_device(
|
2025-09-07 15:36:15 +00:00
|
|
|
fs: &Arc<RamFs>,
|
2024-05-22 07:51:48 +00:00
|
|
|
mode: InodeMode,
|
|
|
|
|
uid: Uid,
|
|
|
|
|
gid: Gid,
|
|
|
|
|
device: Arc<dyn Device>,
|
|
|
|
|
) -> Arc<Self> {
|
|
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
inner: Inner::new_device(device.clone()),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
2024-05-22 07:51:48 +00:00
|
|
|
ino: fs.alloc_id(),
|
|
|
|
|
typ: InodeType::from(device.type_()),
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Arc::downgrade(fs),
|
2024-08-09 03:18:50 +00:00
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2023-07-18 09:19:32 +00:00
|
|
|
})
|
|
|
|
|
}
|
2024-05-11 06:11:57 +00:00
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
fn new_socket(fs: &Arc<RamFs>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
2024-09-26 12:23:56 +00:00
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
|
|
|
|
inner: Inner::new_socket(),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
|
|
|
|
ino: fs.alloc_id(),
|
|
|
|
|
typ: InodeType::Socket,
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Arc::downgrade(fs),
|
|
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2024-09-26 12:23:56 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
fn new_named_pipe(fs: &Arc<RamFs>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
2024-08-16 09:29:01 +00:00
|
|
|
Arc::new_cyclic(|weak_self| RamInode {
|
2024-09-26 12:23:56 +00:00
|
|
|
inner: Inner::new_named_pipe(),
|
|
|
|
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
2024-08-16 09:29:01 +00:00
|
|
|
ino: fs.alloc_id(),
|
|
|
|
|
typ: InodeType::NamedPipe,
|
|
|
|
|
this: weak_self.clone(),
|
|
|
|
|
fs: Arc::downgrade(fs),
|
|
|
|
|
extension: Extension::new(),
|
2025-03-28 06:00:34 +00:00
|
|
|
xattr: RamXattr::new(),
|
2024-08-16 09:29:01 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-11 06:11:57 +00:00
|
|
|
fn find(&self, name: &str) -> Result<Arc<Self>> {
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::Dir {
|
2024-05-11 06:11:57 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let (_, inode) = self
|
2024-05-11 06:11:57 +00:00
|
|
|
.inner
|
|
|
|
|
.as_direntry()
|
|
|
|
|
.unwrap()
|
2024-09-26 12:23:56 +00:00
|
|
|
.read()
|
2024-05-11 06:11:57 +00:00
|
|
|
.get_entry(name)
|
|
|
|
|
.ok_or(Error::new(Errno::ENOENT))?;
|
|
|
|
|
Ok(inode)
|
|
|
|
|
}
|
2023-07-18 09:19:32 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
impl PageCacheBackend for RamInode {
|
2024-12-27 03:55:56 +00:00
|
|
|
fn read_page_async(&self, _idx: usize, frame: &CachePage) -> Result<BioWaiter> {
|
2024-01-05 06:44:19 +00:00
|
|
|
// Initially, any block/page in a RamFs inode contains all zeros
|
2025-07-27 15:43:36 +00:00
|
|
|
frame.writer().fill_zeros(frame.size());
|
2024-03-20 05:57:49 +00:00
|
|
|
Ok(BioWaiter::new())
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-27 03:55:56 +00:00
|
|
|
fn write_page_async(&self, _idx: usize, _frame: &CachePage) -> Result<BioWaiter> {
|
2023-01-05 08:55:58 +00:00
|
|
|
// do nothing
|
2024-03-20 05:57:49 +00:00
|
|
|
Ok(BioWaiter::new())
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
fn npages(&self) -> usize {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().blocks
|
2023-09-18 03:47:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Inode for RamInode {
|
2025-10-28 08:50:57 +00:00
|
|
|
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.inner
|
2023-09-13 04:07:58 +00:00
|
|
|
.as_file()
|
2025-10-28 08:50:57 +00:00
|
|
|
.map(|page_cache| page_cache.pages().clone())
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 07:52:20 +00:00
|
|
|
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
2024-09-02 13:23:46 +00:00
|
|
|
let read_len = {
|
2024-09-26 12:23:56 +00:00
|
|
|
match &self.inner {
|
2024-09-02 13:23:46 +00:00
|
|
|
Inner::File(page_cache) => {
|
|
|
|
|
let (offset, read_len) = {
|
2024-09-26 12:23:56 +00:00
|
|
|
let file_size = self.size();
|
2024-09-02 13:23:46 +00:00
|
|
|
let start = file_size.min(offset);
|
|
|
|
|
let end = file_size.min(offset + writer.avail());
|
|
|
|
|
(start, end - start)
|
|
|
|
|
};
|
|
|
|
|
page_cache.pages().read(offset, writer)?;
|
|
|
|
|
read_len
|
|
|
|
|
}
|
|
|
|
|
Inner::Device(device) => {
|
|
|
|
|
device.read(writer)?
|
|
|
|
|
// Typically, devices like "/dev/zero" or "/dev/null" do not require modifying
|
|
|
|
|
// timestamps here. Please adjust this behavior accordingly if there are special devices.
|
|
|
|
|
}
|
|
|
|
|
Inner::NamedPipe(named_pipe) => named_pipe.read(writer)?,
|
|
|
|
|
_ => return_errno_with_message!(Errno::EISDIR, "read is not supported"),
|
2024-09-02 07:54:01 +00:00
|
|
|
}
|
2023-09-13 04:07:58 +00:00
|
|
|
};
|
2024-09-02 13:23:46 +00:00
|
|
|
|
|
|
|
|
if self.typ == InodeType::File {
|
|
|
|
|
self.set_atime(now());
|
|
|
|
|
}
|
2023-09-13 04:07:58 +00:00
|
|
|
Ok(read_len)
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 07:52:20 +00:00
|
|
|
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
|
|
|
|
self.read_at(offset, writer)
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 07:52:20 +00:00
|
|
|
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
2024-09-02 13:23:46 +00:00
|
|
|
let written_len = match self.typ {
|
|
|
|
|
InodeType::File => {
|
2024-09-26 12:23:56 +00:00
|
|
|
let page_cache = self.inner.as_file().unwrap();
|
2024-05-11 06:11:57 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let file_size = self.size();
|
2024-09-02 07:54:01 +00:00
|
|
|
let write_len = reader.remain();
|
2024-08-16 09:29:01 +00:00
|
|
|
let new_size = offset + write_len;
|
|
|
|
|
let should_expand_size = new_size > file_size;
|
2024-09-26 12:23:56 +00:00
|
|
|
let new_size_aligned = new_size.align_up(BLOCK_SIZE);
|
2024-08-16 09:29:01 +00:00
|
|
|
if should_expand_size {
|
2024-09-26 12:23:56 +00:00
|
|
|
page_cache.resize(new_size_aligned)?;
|
2024-08-16 09:29:01 +00:00
|
|
|
}
|
|
|
|
|
page_cache.pages().write(offset, reader)?;
|
|
|
|
|
|
|
|
|
|
let now = now();
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut inode_meta = self.metadata.lock();
|
|
|
|
|
inode_meta.set_mtime(now);
|
|
|
|
|
inode_meta.set_ctime(now);
|
2024-08-16 09:29:01 +00:00
|
|
|
if should_expand_size {
|
2024-09-26 12:23:56 +00:00
|
|
|
inode_meta.size = new_size;
|
|
|
|
|
inode_meta.blocks = new_size_aligned / BLOCK_SIZE;
|
2024-08-16 09:29:01 +00:00
|
|
|
}
|
2024-09-02 07:54:01 +00:00
|
|
|
write_len
|
2024-08-16 09:29:01 +00:00
|
|
|
}
|
2024-09-02 13:23:46 +00:00
|
|
|
InodeType::CharDevice | InodeType::BlockDevice => {
|
2024-09-26 12:23:56 +00:00
|
|
|
let device = self.inner.as_device().unwrap();
|
2024-09-02 07:54:01 +00:00
|
|
|
device.write(reader)?
|
|
|
|
|
// Typically, devices like "/dev/zero" or "/dev/null" do not require modifying
|
|
|
|
|
// timestamps here. Please adjust this behavior accordingly if there are special devices.
|
2024-08-16 09:29:01 +00:00
|
|
|
}
|
2024-09-02 13:23:46 +00:00
|
|
|
InodeType::NamedPipe => {
|
2024-09-26 12:23:56 +00:00
|
|
|
let named_pipe = self.inner.as_named_pipe().unwrap();
|
2024-09-02 13:23:46 +00:00
|
|
|
named_pipe.write(reader)?
|
|
|
|
|
}
|
2024-08-16 09:29:01 +00:00
|
|
|
_ => return_errno_with_message!(Errno::EISDIR, "write is not supported"),
|
2023-09-13 04:07:58 +00:00
|
|
|
};
|
2024-09-02 07:54:01 +00:00
|
|
|
Ok(written_len)
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 07:52:20 +00:00
|
|
|
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
|
|
|
|
self.write_at(offset, reader)
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-05 06:44:19 +00:00
|
|
|
fn size(&self) -> usize {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().size
|
2023-03-02 01:36:17 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
fn resize(&self, new_size: usize) -> Result<()> {
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::File {
|
|
|
|
|
return_errno_with_message!(Errno::EISDIR, "not regular file");
|
2024-01-05 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let file_size = self.size();
|
2024-01-05 06:44:19 +00:00
|
|
|
if file_size == new_size {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let page_cache = self.inner.as_file().unwrap();
|
2024-07-02 09:29:22 +00:00
|
|
|
page_cache.resize(new_size)?;
|
2024-01-05 06:44:19 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let now = now();
|
|
|
|
|
let mut inode_meta = self.metadata.lock();
|
|
|
|
|
inode_meta.set_mtime(now);
|
|
|
|
|
inode_meta.set_ctime(now);
|
|
|
|
|
inode_meta.resize(new_size);
|
2023-09-18 03:47:17 +00:00
|
|
|
Ok(())
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-09 03:57:52 +00:00
|
|
|
fn atime(&self) -> Duration {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().atime
|
2023-03-09 03:57:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_atime(&self, time: Duration) {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().set_atime(time);
|
2023-03-09 03:57:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mtime(&self) -> Duration {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().mtime
|
2023-03-09 03:57:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_mtime(&self, time: Duration) {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().set_mtime(time);
|
2023-03-09 03:57:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-13 06:53:09 +00:00
|
|
|
fn ctime(&self) -> Duration {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().ctime
|
2024-06-13 06:53:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_ctime(&self, time: Duration) {
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().set_ctime(time);
|
2024-06-13 06:53:09 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
fn ino(&self) -> u64 {
|
2024-05-22 07:51:48 +00:00
|
|
|
self.ino
|
2023-09-18 03:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-13 04:07:58 +00:00
|
|
|
fn type_(&self) -> InodeType {
|
2024-05-22 07:51:48 +00:00
|
|
|
self.typ
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-04 09:52:27 +00:00
|
|
|
fn mode(&self) -> Result<InodeMode> {
|
2024-09-26 12:23:56 +00:00
|
|
|
Ok(self.metadata.lock().mode)
|
2023-09-13 04:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-04 09:52:27 +00:00
|
|
|
fn set_mode(&self, mode: InodeMode) -> Result<()> {
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut inode_meta = self.metadata.lock();
|
|
|
|
|
inode_meta.mode = mode;
|
|
|
|
|
inode_meta.set_ctime(now());
|
2024-01-04 09:52:27 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn owner(&self) -> Result<Uid> {
|
2024-09-26 12:23:56 +00:00
|
|
|
Ok(self.metadata.lock().uid)
|
2024-01-04 09:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_owner(&self, uid: Uid) -> Result<()> {
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut inode_meta = self.metadata.lock();
|
|
|
|
|
inode_meta.uid = uid;
|
|
|
|
|
inode_meta.set_ctime(now());
|
2024-01-04 09:52:27 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn group(&self) -> Result<Gid> {
|
2024-09-26 12:23:56 +00:00
|
|
|
Ok(self.metadata.lock().gid)
|
2024-01-04 09:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_group(&self, gid: Gid) -> Result<()> {
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut inode_meta = self.metadata.lock();
|
|
|
|
|
inode_meta.gid = gid;
|
|
|
|
|
inode_meta.set_ctime(now());
|
2024-01-04 09:52:27 +00:00
|
|
|
Ok(())
|
2023-07-03 08:14:40 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-16 02:47:48 +00:00
|
|
|
fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Arc<dyn Inode>> {
|
2023-09-13 04:07:58 +00:00
|
|
|
if name.len() > NAME_MAX {
|
|
|
|
|
return_errno!(Errno::ENAMETOOLONG);
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::Dir {
|
2024-05-11 06:11:57 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let self_dir = self.inner.as_direntry().unwrap().upread();
|
|
|
|
|
if self_dir.contains_entry(name) {
|
2023-05-18 08:57:29 +00:00
|
|
|
return_errno_with_message!(Errno::EEXIST, "entry exists");
|
|
|
|
|
}
|
2024-09-26 12:23:56 +00:00
|
|
|
|
|
|
|
|
let new_inode = match type_ {
|
2025-08-22 01:59:59 +00:00
|
|
|
MknodType::CharDevice(device) | MknodType::BlockDevice(device) => RamInode::new_device(
|
|
|
|
|
&self.fs.upgrade().unwrap(),
|
|
|
|
|
mode,
|
|
|
|
|
Uid::new_root(),
|
|
|
|
|
Gid::new_root(),
|
|
|
|
|
device,
|
|
|
|
|
),
|
|
|
|
|
MknodType::NamedPipe => RamInode::new_named_pipe(
|
2024-08-16 09:29:01 +00:00
|
|
|
&self.fs.upgrade().unwrap(),
|
|
|
|
|
mode,
|
|
|
|
|
Uid::new_root(),
|
|
|
|
|
Gid::new_root(),
|
|
|
|
|
),
|
2024-08-16 02:47:48 +00:00
|
|
|
};
|
2024-05-11 06:11:57 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_dir = self_dir.upgrade();
|
|
|
|
|
self_dir.append_entry(name, new_inode.clone());
|
|
|
|
|
drop(self_dir);
|
|
|
|
|
|
|
|
|
|
self.metadata.lock().inc_size();
|
|
|
|
|
Ok(new_inode)
|
2023-05-18 08:57:29 +00:00
|
|
|
}
|
|
|
|
|
|
2025-10-30 08:12:51 +00:00
|
|
|
fn open(
|
|
|
|
|
&self,
|
|
|
|
|
access_mode: AccessMode,
|
|
|
|
|
status_flags: StatusFlags,
|
|
|
|
|
) -> Option<Result<Arc<dyn FileIo>>> {
|
|
|
|
|
self.inner.open(access_mode, status_flags)
|
2023-08-10 03:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-18 08:57:29 +00:00
|
|
|
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
2023-09-13 04:07:58 +00:00
|
|
|
if name.len() > NAME_MAX {
|
|
|
|
|
return_errno!(Errno::ENAMETOOLONG);
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::Dir {
|
2024-05-11 06:11:57 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let self_dir = self.inner.as_direntry().unwrap().upread();
|
|
|
|
|
if self_dir.contains_entry(name) {
|
2023-01-05 08:55:58 +00:00
|
|
|
return_errno_with_message!(Errno::EEXIST, "entry exists");
|
|
|
|
|
}
|
2024-09-26 12:23:56 +00:00
|
|
|
|
2024-05-22 07:51:48 +00:00
|
|
|
let fs = self.fs.upgrade().unwrap();
|
2023-01-05 08:55:58 +00:00
|
|
|
let new_inode = match type_ {
|
2024-05-22 07:51:48 +00:00
|
|
|
InodeType::File => RamInode::new_file(&fs, mode, Uid::new_root(), Gid::new_root()),
|
|
|
|
|
InodeType::SymLink => {
|
|
|
|
|
RamInode::new_symlink(&fs, mode, Uid::new_root(), Gid::new_root())
|
|
|
|
|
}
|
|
|
|
|
InodeType::Socket => RamInode::new_socket(&fs, mode, Uid::new_root(), Gid::new_root()),
|
|
|
|
|
InodeType::Dir => {
|
|
|
|
|
RamInode::new_dir(&fs, mode, Uid::new_root(), Gid::new_root(), &self.this)
|
|
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
_ => {
|
|
|
|
|
panic!("unsupported inode type");
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-05-11 06:11:57 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_dir = self_dir.upgrade();
|
|
|
|
|
self_dir.append_entry(name, new_inode.clone());
|
|
|
|
|
drop(self_dir);
|
|
|
|
|
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut inode_meta = self.metadata.lock();
|
|
|
|
|
inode_meta.set_mtime(now);
|
|
|
|
|
inode_meta.set_ctime(now);
|
|
|
|
|
inode_meta.inc_size();
|
|
|
|
|
if type_ == InodeType::Dir {
|
|
|
|
|
inode_meta.inc_nlinks();
|
|
|
|
|
}
|
2024-07-04 07:35:14 +00:00
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
Ok(new_inode)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-08 07:08:31 +00:00
|
|
|
fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result<usize> {
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::Dir {
|
2023-01-05 08:55:58 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-07-04 07:35:14 +00:00
|
|
|
let cnt = self
|
2023-01-05 08:55:58 +00:00
|
|
|
.inner
|
|
|
|
|
.as_direntry()
|
|
|
|
|
.unwrap()
|
2024-09-26 12:23:56 +00:00
|
|
|
.read()
|
2023-03-08 07:08:31 +00:00
|
|
|
.visit_entry(offset, visitor)?;
|
2024-07-04 07:35:14 +00:00
|
|
|
|
|
|
|
|
self.set_atime(now());
|
|
|
|
|
|
2023-03-08 07:08:31 +00:00
|
|
|
Ok(cnt)
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn link(&self, old: &Arc<dyn Inode>, name: &str) -> Result<()> {
|
2023-09-13 04:07:58 +00:00
|
|
|
if !Arc::ptr_eq(&self.fs(), &old.fs()) {
|
|
|
|
|
return_errno_with_message!(Errno::EXDEV, "not same fs");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::Dir {
|
|
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
|
|
|
|
|
}
|
2024-09-26 12:23:56 +00:00
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
let old = old
|
|
|
|
|
.downcast_ref::<RamInode>()
|
|
|
|
|
.ok_or(Error::new(Errno::EXDEV))?;
|
2024-05-22 07:51:48 +00:00
|
|
|
if old.typ == InodeType::Dir {
|
|
|
|
|
return_errno_with_message!(Errno::EPERM, "old is a dir");
|
2024-05-11 06:11:57 +00:00
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_dir = self.inner.as_direntry().unwrap().write();
|
2023-11-28 04:17:42 +00:00
|
|
|
if self_dir.contains_entry(name) {
|
2023-01-05 08:55:58 +00:00
|
|
|
return_errno_with_message!(Errno::EEXIST, "entry exist");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
self_dir.append_entry(name, old.this.upgrade().unwrap());
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
|
|
|
|
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
self_meta.inc_size();
|
|
|
|
|
drop(self_meta);
|
2024-07-04 07:35:14 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut old_meta = old.metadata.lock();
|
|
|
|
|
old_meta.inc_nlinks();
|
|
|
|
|
old_meta.set_ctime(now);
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn unlink(&self, name: &str) -> Result<()> {
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dot_or_dotdot(name) {
|
2023-01-05 08:55:58 +00:00
|
|
|
return_errno_with_message!(Errno::EISDIR, "unlink . or ..");
|
|
|
|
|
}
|
2024-05-11 06:11:57 +00:00
|
|
|
|
|
|
|
|
let target = self.find(name)?;
|
2024-05-22 07:51:48 +00:00
|
|
|
if target.typ == InodeType::Dir {
|
2023-02-15 11:31:13 +00:00
|
|
|
return_errno_with_message!(Errno::EISDIR, "unlink on dir");
|
|
|
|
|
}
|
2024-05-11 06:11:57 +00:00
|
|
|
|
|
|
|
|
// When we got the lock, the dir may have been modified by another thread
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_dir = self.inner.as_direntry().unwrap().write();
|
2024-05-11 06:11:57 +00:00
|
|
|
let (idx, new_target) = self_dir.get_entry(name).ok_or(Error::new(Errno::ENOENT))?;
|
|
|
|
|
if !Arc::ptr_eq(&new_target, &target) {
|
|
|
|
|
return_errno!(Errno::ENOENT);
|
|
|
|
|
}
|
2023-02-15 11:31:13 +00:00
|
|
|
self_dir.remove_entry(idx);
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
|
|
|
|
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.dec_size();
|
|
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
drop(self_meta);
|
|
|
|
|
let mut target_meta = target.metadata.lock();
|
|
|
|
|
target_meta.dec_nlinks();
|
|
|
|
|
target_meta.set_ctime(now);
|
2024-07-04 07:35:14 +00:00
|
|
|
|
2023-02-15 11:31:13 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn rmdir(&self, name: &str) -> Result<()> {
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dot(name) {
|
2023-11-28 04:17:42 +00:00
|
|
|
return_errno_with_message!(Errno::EINVAL, "rmdir on .");
|
|
|
|
|
}
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dotdot(name) {
|
2023-11-28 04:17:42 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTEMPTY, "rmdir on ..");
|
2023-02-15 11:31:13 +00:00
|
|
|
}
|
2024-05-11 06:11:57 +00:00
|
|
|
|
|
|
|
|
let target = self.find(name)?;
|
2024-05-22 07:51:48 +00:00
|
|
|
if target.typ != InodeType::Dir {
|
2024-05-11 06:11:57 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "rmdir on not dir");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
// When we got the lock, the dir may have been modified by another thread
|
|
|
|
|
let (mut self_dir, target_dir) = write_lock_two_direntries_by_ino(
|
|
|
|
|
(self.ino, self.inner.as_direntry().unwrap()),
|
|
|
|
|
(target.ino, target.inner.as_direntry().unwrap()),
|
|
|
|
|
);
|
|
|
|
|
if !target_dir.is_empty_children() {
|
2024-05-11 06:11:57 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTEMPTY, "dir not empty");
|
|
|
|
|
}
|
|
|
|
|
let (idx, new_target) = self_dir.get_entry(name).ok_or(Error::new(Errno::ENOENT))?;
|
|
|
|
|
if !Arc::ptr_eq(&new_target, &target) {
|
|
|
|
|
return_errno!(Errno::ENOENT);
|
|
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
self_dir.remove_entry(idx);
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
|
|
|
|
drop(target_dir);
|
|
|
|
|
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.dec_size();
|
|
|
|
|
self_meta.dec_nlinks();
|
|
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
drop(self_meta);
|
|
|
|
|
let mut target_meta = target.metadata.lock();
|
|
|
|
|
target_meta.dec_nlinks();
|
|
|
|
|
target_meta.dec_nlinks();
|
2024-07-04 07:35:14 +00:00
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
2024-05-11 06:11:57 +00:00
|
|
|
let inode = self.find(name)?;
|
2023-01-05 08:55:58 +00:00
|
|
|
Ok(inode as _)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn rename(&self, old_name: &str, target: &Arc<dyn Inode>, new_name: &str) -> Result<()> {
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dot_or_dotdot(old_name) {
|
2024-05-22 07:51:48 +00:00
|
|
|
return_errno_with_message!(Errno::EISDIR, "old_name is . or ..");
|
|
|
|
|
}
|
2025-01-16 08:17:27 +00:00
|
|
|
if is_dot_or_dotdot(new_name) {
|
2024-05-22 07:51:48 +00:00
|
|
|
return_errno_with_message!(Errno::EISDIR, "new_name is . or ..");
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
let target = target
|
|
|
|
|
.downcast_ref::<RamInode>()
|
|
|
|
|
.ok_or(Error::new(Errno::EXDEV))?;
|
2024-05-11 06:11:57 +00:00
|
|
|
|
2024-05-22 07:51:48 +00:00
|
|
|
if !Arc::ptr_eq(&self.fs(), &target.fs()) {
|
|
|
|
|
return_errno_with_message!(Errno::EXDEV, "not same fs");
|
|
|
|
|
}
|
|
|
|
|
if self.typ != InodeType::Dir {
|
|
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
|
|
|
|
|
}
|
|
|
|
|
if target.typ != InodeType::Dir {
|
|
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "target is not dir");
|
|
|
|
|
}
|
2023-11-28 04:17:42 +00:00
|
|
|
|
|
|
|
|
// Perform necessary checks to ensure that `dst_inode` can be replaced by `src_inode`.
|
|
|
|
|
let check_replace_inode =
|
|
|
|
|
|src_inode: &Arc<RamInode>, dst_inode: &Arc<RamInode>| -> Result<()> {
|
2024-05-22 07:51:48 +00:00
|
|
|
if src_inode.ino == dst_inode.ino {
|
2023-11-28 04:17:42 +00:00
|
|
|
return Ok(());
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
2023-11-28 04:17:42 +00:00
|
|
|
|
2024-05-22 07:51:48 +00:00
|
|
|
match (src_inode.typ, dst_inode.typ) {
|
2023-11-28 04:17:42 +00:00
|
|
|
(InodeType::Dir, InodeType::Dir) => {
|
|
|
|
|
if !dst_inode
|
|
|
|
|
.inner
|
|
|
|
|
.as_direntry()
|
|
|
|
|
.unwrap()
|
2024-09-26 12:23:56 +00:00
|
|
|
.read()
|
2023-11-28 04:17:42 +00:00
|
|
|
.is_empty_children()
|
|
|
|
|
{
|
|
|
|
|
return_errno_with_message!(Errno::ENOTEMPTY, "dir not empty");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(InodeType::Dir, _) => {
|
|
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "old is not dir");
|
|
|
|
|
}
|
|
|
|
|
(_, InodeType::Dir) => {
|
|
|
|
|
return_errno_with_message!(Errno::EISDIR, "new is dir");
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
2023-11-28 04:17:42 +00:00
|
|
|
Ok(())
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Rename in the same directory
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.ino == target.ino {
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_dir = self.inner.as_direntry().unwrap().write();
|
2023-11-28 04:17:42 +00:00
|
|
|
let (src_idx, src_inode) = self_dir
|
2023-01-05 08:55:58 +00:00
|
|
|
.get_entry(old_name)
|
|
|
|
|
.ok_or(Error::new(Errno::ENOENT))?;
|
2024-05-22 07:51:48 +00:00
|
|
|
let is_dir = src_inode.typ == InodeType::Dir;
|
2023-11-28 04:17:42 +00:00
|
|
|
|
|
|
|
|
if let Some((dst_idx, dst_inode)) = self_dir.get_entry(new_name) {
|
|
|
|
|
check_replace_inode(&src_inode, &dst_inode)?;
|
|
|
|
|
self_dir.remove_entry(dst_idx);
|
|
|
|
|
self_dir.substitute_entry(src_idx, (CStr256::from(new_name), src_inode.clone()));
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
|
|
|
|
|
|
|
|
|
let now = now();
|
|
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.dec_size();
|
2023-11-28 04:17:42 +00:00
|
|
|
if is_dir {
|
2024-09-26 12:23:56 +00:00
|
|
|
self_meta.dec_nlinks();
|
2023-11-28 04:17:42 +00:00
|
|
|
}
|
2024-09-26 12:23:56 +00:00
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
drop(self_meta);
|
2024-07-04 07:35:14 +00:00
|
|
|
src_inode.set_ctime(now);
|
2024-09-26 12:23:56 +00:00
|
|
|
dst_inode.set_ctime(now);
|
2023-11-28 04:17:42 +00:00
|
|
|
} else {
|
|
|
|
|
self_dir.substitute_entry(src_idx, (CStr256::from(new_name), src_inode.clone()));
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
2024-07-04 07:35:14 +00:00
|
|
|
let now = now();
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
drop(self_meta);
|
2024-07-04 07:35:14 +00:00
|
|
|
src_inode.set_ctime(now);
|
2023-11-28 04:17:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Or rename across different directories
|
|
|
|
|
else {
|
2024-09-26 12:23:56 +00:00
|
|
|
let (mut self_dir, mut target_dir) = write_lock_two_direntries_by_ino(
|
|
|
|
|
(self.ino, self.inner.as_direntry().unwrap()),
|
|
|
|
|
(target.ino, target.inner.as_direntry().unwrap()),
|
|
|
|
|
);
|
2024-05-22 07:51:48 +00:00
|
|
|
let self_inode_arc = self.this.upgrade().unwrap();
|
|
|
|
|
let target_inode_arc = target.this.upgrade().unwrap();
|
2023-11-28 04:17:42 +00:00
|
|
|
let (src_idx, src_inode) = self_dir
|
2023-01-05 08:55:58 +00:00
|
|
|
.get_entry(old_name)
|
|
|
|
|
.ok_or(Error::new(Errno::ENOENT))?;
|
2023-11-28 04:17:42 +00:00
|
|
|
// Avoid renaming a directory to a subdirectory of itself
|
|
|
|
|
if Arc::ptr_eq(&src_inode, &target_inode_arc) {
|
|
|
|
|
return_errno!(Errno::EINVAL);
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
let is_dir = src_inode.typ == InodeType::Dir;
|
2023-11-28 04:17:42 +00:00
|
|
|
|
|
|
|
|
if let Some((dst_idx, dst_inode)) = target_dir.get_entry(new_name) {
|
|
|
|
|
// Avoid renaming a subdirectory to a directory.
|
|
|
|
|
if Arc::ptr_eq(&self_inode_arc, &dst_inode) {
|
|
|
|
|
return_errno!(Errno::ENOTEMPTY);
|
|
|
|
|
}
|
|
|
|
|
check_replace_inode(&src_inode, &dst_inode)?;
|
|
|
|
|
self_dir.remove_entry(src_idx);
|
|
|
|
|
target_dir.remove_entry(dst_idx);
|
|
|
|
|
target_dir.append_entry(new_name, src_inode.clone());
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
|
|
|
|
drop(target_dir);
|
|
|
|
|
|
|
|
|
|
let now = now();
|
|
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.dec_size();
|
2023-11-28 04:17:42 +00:00
|
|
|
if is_dir {
|
2024-09-26 12:23:56 +00:00
|
|
|
self_meta.dec_nlinks();
|
2023-11-28 04:17:42 +00:00
|
|
|
}
|
2024-09-26 12:23:56 +00:00
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
drop(self_meta);
|
|
|
|
|
let mut target_meta = target.metadata.lock();
|
|
|
|
|
target_meta.set_mtime(now);
|
|
|
|
|
target_meta.set_ctime(now);
|
|
|
|
|
drop(target_meta);
|
2024-07-04 07:35:14 +00:00
|
|
|
dst_inode.set_ctime(now);
|
|
|
|
|
src_inode.set_ctime(now);
|
2023-11-28 04:17:42 +00:00
|
|
|
} else {
|
|
|
|
|
self_dir.remove_entry(src_idx);
|
|
|
|
|
target_dir.append_entry(new_name, src_inode.clone());
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(self_dir);
|
|
|
|
|
drop(target_dir);
|
|
|
|
|
|
|
|
|
|
let now = now();
|
|
|
|
|
let mut self_meta = self.metadata.lock();
|
|
|
|
|
self_meta.dec_size();
|
2023-11-28 04:17:42 +00:00
|
|
|
if is_dir {
|
2024-09-26 12:23:56 +00:00
|
|
|
self_meta.dec_nlinks();
|
2023-11-28 04:17:42 +00:00
|
|
|
}
|
2024-09-26 12:23:56 +00:00
|
|
|
self_meta.set_mtime(now);
|
|
|
|
|
self_meta.set_ctime(now);
|
|
|
|
|
drop(self_meta);
|
|
|
|
|
|
|
|
|
|
let mut target_meta = target.metadata.lock();
|
|
|
|
|
target_meta.inc_size();
|
|
|
|
|
if is_dir {
|
|
|
|
|
target_meta.inc_nlinks();
|
|
|
|
|
}
|
|
|
|
|
target_meta.set_mtime(now);
|
|
|
|
|
target_meta.set_ctime(now);
|
|
|
|
|
drop(target_meta);
|
2024-07-04 07:35:14 +00:00
|
|
|
src_inode.set_ctime(now);
|
2023-02-27 08:49:54 +00:00
|
|
|
}
|
2024-07-04 07:35:14 +00:00
|
|
|
|
2023-11-28 04:17:42 +00:00
|
|
|
if is_dir {
|
2023-01-05 08:55:58 +00:00
|
|
|
src_inode
|
|
|
|
|
.inner
|
2024-09-26 12:23:56 +00:00
|
|
|
.as_direntry()
|
2023-01-05 08:55:58 +00:00
|
|
|
.unwrap()
|
2024-09-26 12:23:56 +00:00
|
|
|
.write()
|
2024-05-22 07:51:48 +00:00
|
|
|
.set_parent(target.this.clone());
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn read_link(&self) -> Result<String> {
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::SymLink {
|
2023-01-05 08:55:58 +00:00
|
|
|
return_errno_with_message!(Errno::EINVAL, "self is not symlink");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let link = self.inner.as_symlink().unwrap().lock();
|
|
|
|
|
Ok(link.clone())
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn write_link(&self, target: &str) -> Result<()> {
|
2024-05-22 07:51:48 +00:00
|
|
|
if self.typ != InodeType::SymLink {
|
2023-01-05 08:55:58 +00:00
|
|
|
return_errno_with_message!(Errno::EINVAL, "self is not symlink");
|
|
|
|
|
}
|
2024-05-22 07:51:48 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let mut link = self.inner.as_symlink().unwrap().lock();
|
2023-09-13 04:07:58 +00:00
|
|
|
*link = String::from(target);
|
2024-09-26 12:23:56 +00:00
|
|
|
drop(link);
|
|
|
|
|
|
2023-03-22 04:02:19 +00:00
|
|
|
// Symlink's metadata.blocks should be 0, so just set the size.
|
2024-09-26 12:23:56 +00:00
|
|
|
self.metadata.lock().size = target.len();
|
2023-01-05 08:55:58 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn metadata(&self) -> Metadata {
|
2024-09-26 12:23:56 +00:00
|
|
|
let rdev = self
|
|
|
|
|
.inner
|
|
|
|
|
.as_device()
|
2025-07-02 10:40:36 +00:00
|
|
|
.map(|device| device.id().as_encoded_u64())
|
2024-09-26 12:23:56 +00:00
|
|
|
.unwrap_or(0);
|
|
|
|
|
let inode_metadata = self.metadata.lock();
|
2024-05-22 07:51:48 +00:00
|
|
|
Metadata {
|
2024-09-26 04:03:32 +00:00
|
|
|
dev: 0,
|
2024-05-22 07:51:48 +00:00
|
|
|
ino: self.ino as _,
|
2024-09-26 04:03:32 +00:00
|
|
|
size: inode_metadata.size,
|
2024-05-22 07:51:48 +00:00
|
|
|
blk_size: BLOCK_SIZE,
|
2024-09-26 04:03:32 +00:00
|
|
|
blocks: inode_metadata.blocks,
|
|
|
|
|
atime: inode_metadata.atime,
|
|
|
|
|
mtime: inode_metadata.mtime,
|
|
|
|
|
ctime: inode_metadata.ctime,
|
2024-05-22 07:51:48 +00:00
|
|
|
type_: self.typ,
|
2024-09-26 04:03:32 +00:00
|
|
|
mode: inode_metadata.mode,
|
|
|
|
|
nlinks: inode_metadata.nlinks,
|
|
|
|
|
uid: inode_metadata.uid,
|
|
|
|
|
gid: inode_metadata.gid,
|
2024-09-26 12:23:56 +00:00
|
|
|
rdev,
|
2024-05-22 07:51:48 +00:00
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-24 09:45:47 +00:00
|
|
|
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents {
|
2024-08-15 03:44:30 +00:00
|
|
|
if !self.typ.is_device() {
|
|
|
|
|
return (IoEvents::IN | IoEvents::OUT) & mask;
|
2023-05-18 08:57:29 +00:00
|
|
|
}
|
2024-08-15 03:44:30 +00:00
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
let device = self
|
2024-08-15 03:44:30 +00:00
|
|
|
.inner
|
|
|
|
|
.as_device()
|
2024-09-26 12:23:56 +00:00
|
|
|
.expect("[Internal error] self.typ is device, while self.inner is not");
|
2024-08-15 03:44:30 +00:00
|
|
|
device.poll(mask, poller)
|
2023-05-18 08:57:29 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
fn fs(&self) -> Arc<dyn FileSystem> {
|
2024-05-22 07:51:48 +00:00
|
|
|
Weak::upgrade(&self.fs).unwrap()
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-28 10:45:16 +00:00
|
|
|
fn fallocate(&self, mode: FallocMode, offset: usize, len: usize) -> Result<()> {
|
|
|
|
|
if self.typ != InodeType::File {
|
|
|
|
|
return_errno_with_message!(Errno::EISDIR, "not regular file");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The support for flags is consistent with Linux
|
|
|
|
|
match mode {
|
|
|
|
|
FallocMode::Allocate => {
|
|
|
|
|
let new_size = offset + len;
|
|
|
|
|
if new_size > self.size() {
|
|
|
|
|
self.resize(new_size)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
FallocMode::AllocateKeepSize => {
|
|
|
|
|
// Do nothing
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
FallocMode::PunchHoleKeepSize => {
|
2024-09-26 12:23:56 +00:00
|
|
|
let file_size = self.size();
|
2024-06-28 10:45:16 +00:00
|
|
|
if offset >= file_size {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
let range = offset..file_size.min(offset + len);
|
|
|
|
|
// TODO: Think of a more light-weight approach
|
2024-09-26 12:23:56 +00:00
|
|
|
self.inner.as_file().unwrap().fill_zeros(range)
|
2024-06-28 10:45:16 +00:00
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EOPNOTSUPP,
|
|
|
|
|
"fallocate with the specified flags is not supported"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-18 08:57:29 +00:00
|
|
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
2024-09-26 12:23:56 +00:00
|
|
|
if let Some(device) = self.inner.as_device() {
|
2023-05-18 08:57:29 +00:00
|
|
|
return device.ioctl(cmd, arg);
|
|
|
|
|
}
|
|
|
|
|
return_errno_with_message!(Errno::EINVAL, "ioctl is not supported");
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
2024-08-09 03:18:50 +00:00
|
|
|
|
2024-09-02 09:48:15 +00:00
|
|
|
fn is_seekable(&self) -> bool {
|
|
|
|
|
!matches!(
|
|
|
|
|
self.typ,
|
|
|
|
|
InodeType::NamedPipe | InodeType::CharDevice | InodeType::Dir | InodeType::Socket
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-09 03:18:50 +00:00
|
|
|
fn extension(&self) -> Option<&Extension> {
|
|
|
|
|
Some(&self.extension)
|
|
|
|
|
}
|
2025-03-28 06:00:34 +00:00
|
|
|
|
|
|
|
|
fn set_xattr(
|
|
|
|
|
&self,
|
|
|
|
|
name: XattrName,
|
|
|
|
|
value_reader: &mut VmReader,
|
|
|
|
|
flags: XattrSetFlags,
|
|
|
|
|
) -> Result<()> {
|
|
|
|
|
RamXattr::check_file_type_for_xattr(self.typ)?;
|
|
|
|
|
self.check_permission(Permission::MAY_WRITE)?;
|
|
|
|
|
self.xattr.set(name, value_reader, flags)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize> {
|
|
|
|
|
RamXattr::check_file_type_for_xattr(self.typ)
|
|
|
|
|
.map_err(|_| Error::with_message(Errno::ENODATA, "no available xattrs"))?;
|
|
|
|
|
self.check_permission(Permission::MAY_READ)?;
|
|
|
|
|
self.xattr.get(name, value_writer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn list_xattr(&self, namespace: XattrNamespace, list_writer: &mut VmWriter) -> Result<usize> {
|
|
|
|
|
if RamXattr::check_file_type_for_xattr(self.typ).is_err() {
|
|
|
|
|
return Ok(0);
|
|
|
|
|
}
|
|
|
|
|
if self.check_permission(Permission::MAY_ACCESS).is_err() {
|
|
|
|
|
return Ok(0);
|
|
|
|
|
}
|
|
|
|
|
self.xattr.list(namespace, list_writer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn remove_xattr(&self, name: XattrName) -> Result<()> {
|
|
|
|
|
RamXattr::check_file_type_for_xattr(self.typ)?;
|
|
|
|
|
self.check_permission(Permission::MAY_WRITE)?;
|
|
|
|
|
self.xattr.remove(name)
|
|
|
|
|
}
|
2023-01-05 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
2025-09-07 15:36:15 +00:00
|
|
|
/// Creates a RAM inode that is detached from any `RamFs`.
|
2025-07-30 09:00:08 +00:00
|
|
|
///
|
|
|
|
|
// TODO: Add "anonymous inode fs" and link the inode to it.
|
|
|
|
|
pub fn new_detached_inode(mode: InodeMode, uid: Uid, gid: Gid) -> Arc<dyn Inode> {
|
|
|
|
|
RamInode::new_file_detached(mode, uid, gid)
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 12:23:56 +00:00
|
|
|
fn write_lock_two_direntries_by_ino<'a>(
|
|
|
|
|
this: (u64, &'a RwLock<DirEntry>),
|
|
|
|
|
other: (u64, &'a RwLock<DirEntry>),
|
|
|
|
|
) -> (
|
2024-11-19 10:35:20 +00:00
|
|
|
RwLockWriteGuard<'a, DirEntry, PreemptDisabled>,
|
|
|
|
|
RwLockWriteGuard<'a, DirEntry, PreemptDisabled>,
|
2024-09-26 12:23:56 +00:00
|
|
|
) {
|
|
|
|
|
if this.0 < other.0 {
|
|
|
|
|
let this = this.1.write();
|
|
|
|
|
let other = other.1.write();
|
2023-01-05 08:55:58 +00:00
|
|
|
(this, other)
|
|
|
|
|
} else {
|
2024-09-26 12:23:56 +00:00
|
|
|
let other = other.1.write();
|
|
|
|
|
let this = this.1.write();
|
2023-01-05 08:55:58 +00:00
|
|
|
(this, other)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-04 07:35:14 +00:00
|
|
|
|
|
|
|
|
fn now() -> Duration {
|
|
|
|
|
RealTimeCoarseClock::get().read_time()
|
|
|
|
|
}
|
2025-07-17 03:24:21 +00:00
|
|
|
|
|
|
|
|
pub(super) struct RamFsType;
|
|
|
|
|
|
|
|
|
|
impl FsType for RamFsType {
|
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
"ramfs"
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-05 02:33:22 +00:00
|
|
|
fn properties(&self) -> FsProperties {
|
|
|
|
|
FsProperties::empty()
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-17 03:24:21 +00:00
|
|
|
fn create(
|
|
|
|
|
&self,
|
2025-10-31 08:42:31 +00:00
|
|
|
_flags: FsFlags,
|
2025-07-17 03:24:21 +00:00
|
|
|
_args: Option<CString>,
|
|
|
|
|
_disk: Option<Arc<dyn aster_block::BlockDevice>>,
|
|
|
|
|
) -> Result<Arc<dyn FileSystem>> {
|
2025-09-07 15:36:15 +00:00
|
|
|
Ok(RamFs::new())
|
2025-07-17 03:24:21 +00:00
|
|
|
}
|
|
|
|
|
|
2025-09-05 02:33:22 +00:00
|
|
|
fn sysnode(&self) -> Option<Arc<dyn aster_systree::SysNode>> {
|
2025-07-17 03:24:21 +00:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|