vfs: add ctime/mtime/atime
This commit is contained in:
parent
4acb148d0e
commit
76f1872764
@ -5,6 +5,7 @@ use libk::vfs::Metadata;
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
io::{FileMode, FileType, GroupId, UserId},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use crate::Ext2Fs;
|
||||
@ -226,6 +227,8 @@ impl Inode {
|
||||
inode: Some(ino),
|
||||
block_count: self.blocks(fs) as _,
|
||||
block_size: fs.block_size as _,
|
||||
ctime: self.ctime as _,
|
||||
mtime: self.mtime as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ impl<'a> Iterator for DirentIter<'a> {
|
||||
|
||||
impl DirectoryNode {
|
||||
pub fn new(fs: Arc<Ext2Fs>, inode: InodeAccess) -> NodeRef {
|
||||
Node::directory(Self { fs, inode }, NodeFlags::empty())
|
||||
Node::directory(Self { fs, inode }, NodeFlags::empty(), None)
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
@ -166,7 +166,7 @@ impl DirectoryNode {
|
||||
this.create_entry("..", parent).await?;
|
||||
}
|
||||
|
||||
Ok(Node::directory(this, NodeFlags::empty()))
|
||||
Ok(Node::directory(this, NodeFlags::empty(), None))
|
||||
}
|
||||
|
||||
async fn create_entry(&self, name: &str, ino: u32) -> Result<(), Error> {
|
||||
|
@ -17,7 +17,7 @@ pub struct RegularNode {
|
||||
|
||||
impl RegularNode {
|
||||
pub fn new(fs: Arc<Ext2Fs>, inode: InodeAccess) -> NodeRef {
|
||||
Node::regular(Self { fs, inode }, NodeFlags::empty())
|
||||
Node::regular(Self { fs, inode }, NodeFlags::empty(), None)
|
||||
}
|
||||
|
||||
async fn resize(&self, new_size: u64) -> Result<(), Error> {
|
||||
|
@ -25,6 +25,7 @@ impl SymlinkNode {
|
||||
cache: IrqSafeRwLock::new(Vec::new()),
|
||||
},
|
||||
NodeFlags::empty(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use libk::vfs::{CommonImpl, DirectoryImpl, DirectoryOpenPosition, Node, NodeFlags, NodeRef};
|
||||
use yggdrasil_abi::{error::Error, io::FileType};
|
||||
use libk::vfs::{
|
||||
CommonImpl, DirectoryImpl, DirectoryOpenPosition, Metadata, Node, NodeFlags, NodeRef,
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{FileMode, FileType},
|
||||
};
|
||||
|
||||
use crate::{block::BlockAllocator, file::FileNode};
|
||||
|
||||
@ -10,10 +15,11 @@ pub(crate) struct DirectoryNode<A: BlockAllocator> {
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator> DirectoryNode<A> {
|
||||
pub fn new() -> NodeRef {
|
||||
pub fn new(metadata: Metadata) -> NodeRef {
|
||||
Node::directory(
|
||||
Self { _pd: PhantomData },
|
||||
NodeFlags::IN_MEMORY_SIZE | NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(metadata),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -27,8 +33,10 @@ impl<A: BlockAllocator> DirectoryImpl for DirectoryNode<A> {
|
||||
|
||||
fn create_node(&self, _parent: &NodeRef, ty: FileType) -> Result<NodeRef, Error> {
|
||||
match ty {
|
||||
FileType::File => Ok(FileNode::<A>::new()),
|
||||
FileType::Directory => Ok(DirectoryNode::<A>::new()),
|
||||
FileType::File => Ok(FileNode::<A>::new(Metadata::now_root(FileMode::new(0o644)))),
|
||||
FileType::Directory => Ok(DirectoryNode::<A>::new(Metadata::now_root(FileMode::new(
|
||||
0o755,
|
||||
)))),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::any::Any;
|
||||
|
||||
use libk::vfs::{CommonImpl, InstanceData, Node, NodeFlags, NodeRef, RegularImpl};
|
||||
use libk::vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use yggdrasil_abi::{error::Error, io::OpenOptions};
|
||||
|
||||
@ -11,12 +11,13 @@ pub(crate) struct FileNode<A: BlockAllocator> {
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator> FileNode<A> {
|
||||
pub fn new() -> NodeRef {
|
||||
pub fn new(metadata: Metadata) -> NodeRef {
|
||||
Node::regular(
|
||||
Self {
|
||||
data: IrqSafeSpinlock::new(BVec::new()),
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(metadata),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use alloc::rc::Rc;
|
||||
use block::BlockAllocator;
|
||||
use dir::DirectoryNode;
|
||||
use file::FileNode;
|
||||
use libk::vfs::{impls::fixed_path_symlink, AccessToken, NodeRef};
|
||||
use libk::vfs::{impls::fixed_path_symlink, AccessToken, Metadata, NodeRef};
|
||||
use tar::TarEntry;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
@ -68,6 +68,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
at: &NodeRef,
|
||||
path: &Path,
|
||||
create: bool,
|
||||
mode: FileMode,
|
||||
) -> Result<NodeRef, Error> {
|
||||
let access = unsafe { AccessToken::authorized() };
|
||||
if path.is_empty() {
|
||||
@ -87,7 +88,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
return Err(Error::DoesNotExist);
|
||||
}
|
||||
|
||||
let node = DirectoryNode::<A>::new();
|
||||
let node = DirectoryNode::<A>::new(Metadata::now_root(mode));
|
||||
at.add_child(element, node.clone())?;
|
||||
|
||||
node
|
||||
@ -102,15 +103,17 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
Ok(node)
|
||||
} else {
|
||||
assert!(node.is_directory());
|
||||
Self::make_path(&node, rest, create)
|
||||
Self::make_path(&node, rest, create, mode)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_node_initial(self: &Rc<Self>, hdr: &TarEntry) -> Result<NodeRef, Error> {
|
||||
let kind = hdr.node_kind();
|
||||
let mode = usize::from(&hdr.mode);
|
||||
let mode = FileMode::new(0o777 & (mode as u32));
|
||||
match kind {
|
||||
FileType::File => Ok(FileNode::<A>::new()),
|
||||
FileType::Directory => Ok(DirectoryNode::<A>::new()),
|
||||
FileType::File => Ok(FileNode::<A>::new(Metadata::now_root(mode))),
|
||||
FileType::Directory => Ok(DirectoryNode::<A>::new(Metadata::now_root(mode))),
|
||||
FileType::Symlink => {
|
||||
let target = hdr.symlink_target()?;
|
||||
Ok(fixed_path_symlink(target))
|
||||
@ -120,7 +123,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
}
|
||||
|
||||
fn from_slice_internal(self: &Rc<Self>, tar_data: &'static [u8]) -> Result<NodeRef, Error> {
|
||||
let root = DirectoryNode::<A>::new();
|
||||
let root = DirectoryNode::<A>::new(Metadata::now_root(FileMode::new(0o755)));
|
||||
|
||||
// 1. Create paths in tar
|
||||
for item in TarIterator::new(tar_data) {
|
||||
@ -131,7 +134,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
|
||||
|
||||
let (dirname, filename) = path.split_right();
|
||||
let parent = Self::make_path(&root, dirname, true)?;
|
||||
let parent = Self::make_path(&root, dirname, true, FileMode::new(0o755))?;
|
||||
let node = self.create_node_initial(hdr)?;
|
||||
|
||||
parent.add_child(filename, node)?;
|
||||
@ -144,7 +147,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
};
|
||||
|
||||
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
|
||||
let node = Self::make_path(&root, path, false)?;
|
||||
let node = Self::make_path(&root, path, false, FileMode::empty())?;
|
||||
assert_eq!(node.ty(), hdr.node_kind());
|
||||
|
||||
let uid = unsafe { UserId::from_raw(usize::from(&hdr.uid) as u32) };
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
device::{block::BlockDevice, char::CharDevice},
|
||||
vfs::{
|
||||
impls::{fixed_path_symlink, MemoryDirectory},
|
||||
AccessToken, Node, NodeFlags, NodeRef,
|
||||
AccessToken, Metadata, Node, NodeFlags, NodeRef,
|
||||
},
|
||||
};
|
||||
|
||||
@ -46,7 +46,7 @@ pub fn add_named_char_device(
|
||||
) -> Result<(), Error> {
|
||||
log::info!("Add char device: {}", name);
|
||||
|
||||
let node = Node::char(dev, NodeFlags::IN_MEMORY_PROPS, mode);
|
||||
let node = Node::char(dev, NodeFlags::IN_MEMORY_PROPS, Metadata::now_root(mode));
|
||||
|
||||
DEVFS_ROOT.get().add_child(name, node)
|
||||
}
|
||||
@ -60,7 +60,7 @@ pub fn add_named_block_device<S: Into<String>>(
|
||||
let name = name.into();
|
||||
log::info!("Add block device: {}", name);
|
||||
|
||||
let node = Node::block(dev, NodeFlags::IN_MEMORY_PROPS, mode);
|
||||
let node = Node::block(dev, NodeFlags::IN_MEMORY_PROPS, Metadata::now_root(mode));
|
||||
|
||||
DEVFS_ROOT.get().add_child(name, node.clone())?;
|
||||
|
||||
|
@ -8,7 +8,7 @@ use yggdrasil_abi::{
|
||||
|
||||
use crate::{
|
||||
fs::sysfs::object::KObject,
|
||||
vfs::{CommonImpl, InstanceData, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
};
|
||||
|
||||
use super::Attribute;
|
||||
@ -112,13 +112,13 @@ impl<V: BytesAttributeOps> Attribute<V::Data> for BytesAttribute<V> {
|
||||
true => FileMode::new(0o644),
|
||||
};
|
||||
|
||||
Ok(Node::regular_kernel(
|
||||
Ok(Node::regular(
|
||||
BytesAttributeNode {
|
||||
object: parent.clone(),
|
||||
_pd: PhantomData::<V>,
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
mode,
|
||||
Some(Metadata::now_root(mode)),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ use yggdrasil_abi::{
|
||||
|
||||
use crate::{
|
||||
fs::sysfs::object::KObject,
|
||||
vfs::{CommonImpl, InstanceData, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
};
|
||||
|
||||
use super::Attribute;
|
||||
@ -180,13 +180,13 @@ impl<V: StringAttributeOps> Attribute<V::Data> for StringAttribute<V> {
|
||||
true => FileMode::new(0o644),
|
||||
};
|
||||
|
||||
Ok(Node::regular_kernel(
|
||||
Ok(Node::regular(
|
||||
StringAttributeNode {
|
||||
object: parent.clone(),
|
||||
_pd: PhantomData::<V>,
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
mode,
|
||||
Some(Metadata::now_root(mode)),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use alloc::{string::String, sync::Arc};
|
||||
use libk_util::OneTimeInit;
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
|
||||
use crate::vfs::{impls::MemoryDirectory, Node, NodeFlags};
|
||||
use crate::vfs::{impls::MemoryDirectory, Metadata, Node, NodeFlags};
|
||||
|
||||
use super::attribute::Attribute;
|
||||
|
||||
@ -13,10 +13,10 @@ pub struct KObject<D> {
|
||||
|
||||
impl<D> KObject<D> {
|
||||
pub fn new(data: D) -> Arc<Self> {
|
||||
let node = Node::directory_kernel(
|
||||
let node = Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_SIZE | NodeFlags::IN_MEMORY_PROPS,
|
||||
FileMode::new(0o555),
|
||||
Some(Metadata::now_root(FileMode::new(0o555))),
|
||||
);
|
||||
Arc::new(Self { data, node })
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ use libk_util::{
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
DeviceRequest, DirectoryEntry, OpenOptions, PipeOptions, RawFd, SeekFrom, TerminalOptions,
|
||||
TerminalSize, TimerOptions,
|
||||
DeviceRequest, DirectoryEntry, FileMode, OpenOptions, PipeOptions, RawFd, SeekFrom,
|
||||
TerminalOptions, TerminalSize, TimerOptions,
|
||||
},
|
||||
process::{ProcessWait, WaitFlags},
|
||||
};
|
||||
@ -56,6 +56,7 @@ use super::{
|
||||
pid::PidFile,
|
||||
pty::{self, PseudoTerminalMaster, PseudoTerminalSlave},
|
||||
socket::SocketWrapper,
|
||||
Metadata,
|
||||
};
|
||||
|
||||
mod device;
|
||||
@ -157,7 +158,8 @@ impl File {
|
||||
let (master, slave) = pty::create(config, size)?;
|
||||
let master = Arc::new(master);
|
||||
let slave = Arc::new(slave);
|
||||
let (master_node, slave_node) = Node::pseudo_terminal_nodes(&master, &slave);
|
||||
let (master_node, slave_node) =
|
||||
Node::pseudo_terminal_nodes(&master, &slave, Metadata::now_root(FileMode::new(0o644)));
|
||||
Ok((
|
||||
Arc::new(Self::PtyMaster(TerminalHalfWrapper {
|
||||
blocking: AtomicBool::new(true),
|
||||
|
@ -10,14 +10,14 @@ use alloc::{
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{FileMode, FileType, OpenOptions},
|
||||
io::{FileMode, FileType, GroupId, OpenOptions, UserId},
|
||||
};
|
||||
|
||||
use crate::vfs::{DirectoryOpenPosition, InstanceData};
|
||||
|
||||
use super::{
|
||||
traits::HardlinkImpl, CommonImpl, DirectoryImpl, Node, NodeFlags, NodeRef, RegularImpl,
|
||||
SymlinkImpl,
|
||||
traits::HardlinkImpl, CommonImpl, DirectoryImpl, Metadata, Node, NodeFlags, NodeRef,
|
||||
RegularImpl, SymlinkImpl,
|
||||
};
|
||||
|
||||
trait SliceRead {
|
||||
@ -126,7 +126,11 @@ where
|
||||
}
|
||||
|
||||
pub fn new_node(read: R) -> NodeRef {
|
||||
Node::regular(Self::new(read), NodeFlags::IN_MEMORY_PROPS)
|
||||
Node::regular(
|
||||
Self::new(read),
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o444))),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +229,11 @@ where
|
||||
}
|
||||
|
||||
pub fn new_node(read: R, write: W) -> NodeRef {
|
||||
Node::regular(Self::new(read, write), NodeFlags::IN_MEMORY_PROPS)
|
||||
Node::regular(
|
||||
Self::new(read, write),
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o644))),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,10 +369,10 @@ where
|
||||
impl MemoryDirectory {
|
||||
/// Creates a [MemoryDirectory] with no children
|
||||
pub fn empty(mode: FileMode) -> NodeRef {
|
||||
Node::directory_kernel(
|
||||
Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
mode,
|
||||
Some(Metadata::now_root(mode)),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -444,10 +452,10 @@ where
|
||||
|
||||
/// Creates a read-only node with given read function
|
||||
pub fn read_fn_node<R: ReadFn + 'static>(read: R) -> NodeRef {
|
||||
Node::regular_kernel(
|
||||
Node::regular(
|
||||
ReadOnlyFnNode::new(read),
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
FileMode::USER_READ | FileMode::GROUP_READ | FileMode::OTHER_READ,
|
||||
Some(Metadata::now_root(FileMode::new(0o444))),
|
||||
)
|
||||
}
|
||||
|
||||
@ -456,6 +464,7 @@ pub fn mdir<S: Into<String>, I: IntoIterator<Item = (S, NodeRef)>>(it: I) -> Nod
|
||||
let dir = Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
Some(Metadata::now_root(FileMode::new(0o555))),
|
||||
);
|
||||
for (name, node) in it {
|
||||
dir.add_child(name, node).unwrap();
|
||||
@ -469,6 +478,7 @@ pub fn fixed_path_symlink(target: impl Into<String>) -> NodeRef {
|
||||
target: target.into(),
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o555))),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ use yggdrasil_abi::{
|
||||
bitflags,
|
||||
error::Error,
|
||||
io::{FileMode, FileType, GroupId, UserId},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
mod access;
|
||||
@ -28,9 +29,12 @@ mod tree;
|
||||
pub use access::AccessToken;
|
||||
pub use traits::{CommonImpl, DirectoryImpl, RegularImpl, SymlinkImpl};
|
||||
|
||||
use crate::device::{
|
||||
block::{BlockDevice, BlockDeviceFile},
|
||||
char::{CharDevice, CharDeviceFile},
|
||||
use crate::{
|
||||
device::{
|
||||
block::{BlockDevice, BlockDeviceFile},
|
||||
char::{CharDevice, CharDeviceFile},
|
||||
},
|
||||
time::real_time,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -114,10 +118,14 @@ pub struct Metadata {
|
||||
pub block_size: u64,
|
||||
/// Size of the node (without metadata) in units of `block_size`
|
||||
pub block_count: u64,
|
||||
/// Creation time (in seconds)
|
||||
pub ctime: u64,
|
||||
/// Modification time (in seconds)
|
||||
pub mtime: u64,
|
||||
}
|
||||
|
||||
struct PropertyCache {
|
||||
metadata: Metadata,
|
||||
metadata: Option<Metadata>,
|
||||
size: Option<u64>,
|
||||
}
|
||||
|
||||
@ -130,31 +138,27 @@ pub struct Node {
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub(crate) const fn default_dir() -> Metadata {
|
||||
pub fn now(uid: UserId, gid: GroupId, mode: FileMode) -> Metadata {
|
||||
let now = real_time().seconds;
|
||||
Metadata {
|
||||
uid: UserId::root(),
|
||||
gid: GroupId::root(),
|
||||
mode: FileMode::new(0o755),
|
||||
block_size: 0,
|
||||
block_count: 0,
|
||||
mode,
|
||||
uid,
|
||||
gid,
|
||||
ctime: now,
|
||||
mtime: now,
|
||||
inode: None,
|
||||
block_size: 4096,
|
||||
block_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn default_file() -> Metadata {
|
||||
Metadata {
|
||||
uid: UserId::root(),
|
||||
gid: GroupId::root(),
|
||||
mode: FileMode::new(0o644),
|
||||
block_size: 0,
|
||||
block_count: 0,
|
||||
inode: None,
|
||||
}
|
||||
pub fn now_root(mode: FileMode) -> Metadata {
|
||||
Self::now(UserId::root(), GroupId::root(), mode)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn new(data: NodeImpl, flags: NodeFlags, metadata: Metadata) -> NodeRef {
|
||||
fn new(data: NodeImpl, flags: NodeFlags, metadata: Option<Metadata>) -> NodeRef {
|
||||
Arc::new(Self {
|
||||
data,
|
||||
flags,
|
||||
@ -169,16 +173,17 @@ impl Node {
|
||||
pub(crate) fn pseudo_terminal_nodes(
|
||||
master: &Arc<PseudoTerminalMaster>,
|
||||
slave: &Arc<PseudoTerminalSlave>,
|
||||
metadata: Metadata,
|
||||
) -> (NodeRef, NodeRef) {
|
||||
let master = Self::new(
|
||||
NodeImpl::PseudoTerminalMaster(Arc::downgrade(master)),
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
Metadata::default_file(),
|
||||
Some(metadata),
|
||||
);
|
||||
let slave = Self::new(
|
||||
NodeImpl::PseudoTerminalSlave(Arc::downgrade(slave)),
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
Metadata::default_file(),
|
||||
Some(metadata),
|
||||
);
|
||||
|
||||
master.props.lock().size = Some(0);
|
||||
@ -188,85 +193,69 @@ impl Node {
|
||||
}
|
||||
|
||||
/// Creates a new directory node with given [DirectoryImpl] and permissions
|
||||
pub fn directory_kernel<T: DirectoryImpl + 'static>(
|
||||
pub fn directory<T: DirectoryImpl + 'static>(
|
||||
data: T,
|
||||
flags: NodeFlags,
|
||||
mode: FileMode,
|
||||
metadata: Option<Metadata>,
|
||||
) -> NodeRef {
|
||||
let data = NodeImpl::Directory(DirectoryData {
|
||||
imp: Box::new(data),
|
||||
mountpoint: IrqSafeSpinlock::new(None),
|
||||
children: IrqSafeSpinlock::new(Vec::new()),
|
||||
});
|
||||
Self::new(
|
||||
data,
|
||||
flags,
|
||||
Metadata {
|
||||
mode,
|
||||
..Metadata::default_dir()
|
||||
},
|
||||
)
|
||||
Self::new(data, flags, metadata)
|
||||
}
|
||||
|
||||
/// Creates a new directory node with given [DirectoryImpl]
|
||||
pub fn directory<T: DirectoryImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
||||
Self::directory_kernel(data, flags, FileMode::default_dir())
|
||||
}
|
||||
// /// Creates a new directory node with given [DirectoryImpl]
|
||||
// pub fn directory<T: DirectoryImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
||||
// Self::directory_kernel(data, flags, FileMode::default_dir())
|
||||
// }
|
||||
|
||||
/// Creates a new file node with given [RegularImpl] and permissions
|
||||
pub fn regular_kernel<T: RegularImpl + 'static>(
|
||||
pub fn regular<T: RegularImpl + 'static>(
|
||||
data: T,
|
||||
flags: NodeFlags,
|
||||
mode: FileMode,
|
||||
metadata: Option<Metadata>,
|
||||
) -> NodeRef {
|
||||
Self::new(
|
||||
NodeImpl::Regular(Box::new(data)),
|
||||
flags,
|
||||
Metadata {
|
||||
mode,
|
||||
..Metadata::default_file()
|
||||
},
|
||||
)
|
||||
Self::new(NodeImpl::Regular(Box::new(data)), flags, metadata)
|
||||
}
|
||||
|
||||
/// Creates a new file node with given [RegularImpl]
|
||||
pub fn regular<T: RegularImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
||||
Self::regular_kernel(data, flags, FileMode::default_file())
|
||||
}
|
||||
// /// Creates a new file node with given [RegularImpl]
|
||||
// pub fn regular<T: RegularImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
||||
// Self::regular_kernel(data, flags, FileMode::default_file())
|
||||
// }
|
||||
|
||||
/// Creates a new block device node with given [BlockDevice]
|
||||
pub fn block(device: Arc<dyn BlockDevice>, flags: NodeFlags, mode: FileMode) -> NodeRef {
|
||||
pub fn block(device: Arc<dyn BlockDevice>, flags: NodeFlags, metadata: Metadata) -> NodeRef {
|
||||
Self::new(
|
||||
NodeImpl::Block(BlockDeviceFile(device)),
|
||||
flags,
|
||||
Metadata {
|
||||
mode,
|
||||
..Metadata::default_file()
|
||||
},
|
||||
Some(metadata),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new character device node with given [CharDevice]
|
||||
pub fn char(device: Arc<dyn CharDevice>, flags: NodeFlags, mode: FileMode) -> NodeRef {
|
||||
pub fn char(device: Arc<dyn CharDevice>, flags: NodeFlags, metadata: Metadata) -> NodeRef {
|
||||
Self::new(
|
||||
NodeImpl::Char(CharDeviceFile(device)),
|
||||
flags,
|
||||
Metadata {
|
||||
mode,
|
||||
..Metadata::default_file()
|
||||
},
|
||||
Some(metadata),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new symbolic link node with given [SymlinkImpl]
|
||||
pub fn symlink<T: SymlinkImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
||||
pub fn symlink<T: SymlinkImpl + 'static>(
|
||||
data: T,
|
||||
flags: NodeFlags,
|
||||
metadata: Option<Metadata>,
|
||||
) -> NodeRef {
|
||||
Self::new(
|
||||
NodeImpl::Symlink(SymlinkData {
|
||||
target: IrqSafeRwLock::new(None),
|
||||
imp: Box::new(data),
|
||||
}),
|
||||
flags,
|
||||
Metadata::default_file(),
|
||||
metadata,
|
||||
)
|
||||
}
|
||||
|
||||
@ -277,7 +266,7 @@ impl Node {
|
||||
imp: Box::new(data),
|
||||
}),
|
||||
NodeFlags::IN_MEMORY_SIZE,
|
||||
Metadata::default_file(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@ -495,8 +484,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn dir_cache_add() {
|
||||
let d1 = Node::directory(DummyDirectory, NodeFlags::empty());
|
||||
let d2 = Node::directory(DummyDirectory, NodeFlags::empty());
|
||||
let d1 = Node::directory(DummyDirectory, NodeFlags::empty(), None);
|
||||
let d2 = Node::directory(DummyDirectory, NodeFlags::empty(), None);
|
||||
let f1 = Node::regular(DummyFile, NodeFlags::empty());
|
||||
|
||||
assert!(Arc::ptr_eq(&f1.parent(), &f1));
|
||||
@ -516,7 +505,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn in_mem_dir_size_coherence() {
|
||||
let d = Node::directory(DummyDirectory, NodeFlags::IN_MEMORY_SIZE);
|
||||
let d = Node::directory(DummyDirectory, NodeFlags::IN_MEMORY_SIZE, None);
|
||||
|
||||
for i in 0..10 {
|
||||
let name = format!("f{}", i);
|
||||
@ -540,7 +529,7 @@ mod tests {
|
||||
}
|
||||
impl DirectoryImpl for AnyData {}
|
||||
|
||||
let d = Node::directory(AnyData { value: 1234 }, NodeFlags::empty());
|
||||
let d = Node::directory(AnyData { value: 1234 }, NodeFlags::empty(), None);
|
||||
let r = d.data_as_ref::<AnyData>();
|
||||
|
||||
assert_eq!(r.value, 1234);
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use libk_util::ext::OptionExt;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, DirectoryEntry, FileMode, GroupId, OpenOptions, UserId},
|
||||
@ -172,7 +173,13 @@ impl Node {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
let mut metadata = self.metadata()?;
|
||||
let mut cache = self.props.lock();
|
||||
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| self.data_as_common().metadata(self))?;
|
||||
|
||||
// let mut metadata = self.metadata()?;
|
||||
|
||||
if let Some(uid) = uid {
|
||||
metadata.uid = uid;
|
||||
@ -184,9 +191,6 @@ impl Node {
|
||||
metadata.mode = mode;
|
||||
}
|
||||
|
||||
// Update cached props
|
||||
self.props.lock().metadata = metadata;
|
||||
|
||||
if !self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
// Update permissions in the real node
|
||||
// todo!();
|
||||
@ -200,7 +204,7 @@ impl Node {
|
||||
pub fn metadata(self: &NodeRef) -> Result<Metadata, Error> {
|
||||
if self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
let props = self.props.lock();
|
||||
return Ok(props.metadata);
|
||||
return Ok(props.metadata.unwrap());
|
||||
}
|
||||
|
||||
self.data_as_common().metadata(self)
|
||||
|
@ -227,6 +227,10 @@ pub(crate) fn get_metadata(
|
||||
inode: metadata.inode,
|
||||
block_count: metadata.block_count,
|
||||
block_size: metadata.block_size,
|
||||
ctime: metadata.ctime,
|
||||
mtime: metadata.mtime,
|
||||
// TODO atime?
|
||||
atime: metadata.mtime,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -98,6 +98,13 @@ struct FileAttr {
|
||||
pub uid: UserId,
|
||||
/// Owner group ID
|
||||
pub gid: GroupId,
|
||||
|
||||
/// Creation time
|
||||
pub ctime: u64,
|
||||
/// Last modification time
|
||||
pub mtime: u64,
|
||||
/// Last access time
|
||||
pub atime: u64,
|
||||
}
|
||||
|
||||
/// Raw directory entry representation
|
||||
|
@ -2,7 +2,13 @@
|
||||
#![feature(let_chains, decl_macro)]
|
||||
|
||||
use std::{
|
||||
cmp::Ordering, fmt, fs::{read_dir, FileType, Metadata}, io, path::{Path, PathBuf}, process::ExitCode
|
||||
cmp::Ordering,
|
||||
fmt,
|
||||
fs::{read_dir, FileType, Metadata},
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
process::ExitCode,
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
@ -10,6 +16,7 @@ use std::os::unix::fs::MetadataExt;
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
use std::os::yggdrasil::fs::MetadataExt;
|
||||
|
||||
use chrono::{Datelike, Timelike};
|
||||
use clap::Parser;
|
||||
use humansize::{FormatSize, BINARY};
|
||||
|
||||
@ -51,6 +58,7 @@ trait MetadataImpl {
|
||||
fn size(&self) -> u64;
|
||||
fn inode(&self) -> Option<u32>;
|
||||
fn mode(&self) -> Self::Mode;
|
||||
fn mtime(&self) -> SystemTime;
|
||||
}
|
||||
|
||||
impl DisplaySizeBit for u64 {
|
||||
@ -130,8 +138,11 @@ impl MetadataImpl for Metadata {
|
||||
fn inode(&self) -> Option<u32> {
|
||||
MetadataExt::inode(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn mtime(&self) -> SystemTime {
|
||||
self.modified().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix, rust_analyzer))]
|
||||
struct UnixFileMode(u32);
|
||||
@ -177,14 +188,56 @@ impl MetadataImpl for Metadata {
|
||||
fn mode(&self) -> Self::Mode {
|
||||
UnixFileMode(MetadataExt::mode(self))
|
||||
}
|
||||
|
||||
fn mtime(&self) -> SystemTime {
|
||||
self.modified().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_file_time(time: SystemTime) -> chrono::DateTime<chrono::Utc> {
|
||||
let timestamp = time.duration_since(SystemTime::UNIX_EPOCH).unwrap();
|
||||
chrono::DateTime::from_timestamp(timestamp.as_secs() as _, 0).unwrap()
|
||||
}
|
||||
|
||||
fn time_now() -> chrono::DateTime<chrono::Utc> {
|
||||
let now = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap();
|
||||
chrono::DateTime::from_timestamp(now.as_secs() as _, 0).unwrap()
|
||||
}
|
||||
|
||||
impl DisplayBit for Option<Metadata> {
|
||||
fn display_bit(&self, opts: &Args, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
const MONTHS: &[&str] = &[
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
];
|
||||
|
||||
let now = time_now();
|
||||
let this = self.as_ref();
|
||||
let ino = this.and_then(MetadataImpl::inode);
|
||||
let mode = this.map(MetadataImpl::mode);
|
||||
let size = this.map(MetadataImpl::size);
|
||||
let mtime = this
|
||||
.map(MetadataImpl::mtime)
|
||||
.map(convert_file_time)
|
||||
.map(|time| {
|
||||
if time.year() == now.year() {
|
||||
format!(
|
||||
"{} {:02} {:02}:{:02}",
|
||||
MONTHS[time.month0() as usize],
|
||||
time.day(),
|
||||
time.hour(),
|
||||
time.minute()
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{} {:02}, {:04}",
|
||||
MONTHS[time.month0() as usize],
|
||||
time.day(),
|
||||
time.year()
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(mode) = mode {
|
||||
mode.display_bit(opts, f)?;
|
||||
@ -195,7 +248,13 @@ impl DisplayBit for Option<Metadata> {
|
||||
if let Some(size) = size {
|
||||
write!(f, " {:>12}", size.display_size_with(opts))?;
|
||||
} else {
|
||||
write!(f, " {:<12}", "???")?;
|
||||
write!(f, " {:>12}", "???")?;
|
||||
}
|
||||
|
||||
if let Some(mtime) = mtime {
|
||||
write!(f, " {:>14}", mtime)?;
|
||||
} else {
|
||||
write!(f, " {:<14}", "???")?;
|
||||
}
|
||||
|
||||
if opts.inodes {
|
||||
@ -229,7 +288,10 @@ impl DisplayBit for Entry {
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
let ino = self.attrs.as_ref().and_then(<Metadata as MetadataImpl>::inode);
|
||||
let ino = self
|
||||
.attrs
|
||||
.as_ref()
|
||||
.and_then(<Metadata as MetadataImpl>::inode);
|
||||
if opts.inodes {
|
||||
if let Some(ino) = ino {
|
||||
write!(f, "{ino:<8} ")?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user