107 lines
2.9 KiB
Rust
Raw Normal View History

2024-08-02 17:04:47 +03:00
use core::any::Any;
2024-10-11 15:29:41 +03:00
use alloc::{sync::Arc, vec::Vec};
2024-08-02 17:04:47 +03:00
use libk::{
block,
error::Error,
vfs::{CommonImpl, Metadata, Node, NodeFlags, NodeRef, SymlinkImpl},
};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
2024-12-04 20:44:17 +02:00
use crate::{inode::InodeAccess, Ext2Fs, Inode};
2024-08-02 17:04:47 +03:00
pub struct SymlinkNode {
fs: Arc<Ext2Fs>,
2024-12-04 18:28:27 +02:00
inode: InodeAccess,
2024-08-02 17:04:47 +03:00
cache: IrqSafeRwLock<Vec<u8>>,
}
impl SymlinkNode {
2024-12-04 18:28:27 +02:00
pub fn new(fs: Arc<Ext2Fs>, inode: InodeAccess) -> NodeRef {
2024-08-02 17:04:47 +03:00
Node::symlink(
Self {
fs,
2024-12-04 18:28:27 +02:00
inode,
2024-08-02 17:04:47 +03:00
cache: IrqSafeRwLock::new(Vec::new()),
},
NodeFlags::empty(),
2024-12-22 15:22:40 +02:00
None,
2024-08-02 17:04:47 +03:00
)
}
async fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
2024-12-04 20:44:17 +02:00
let inode = self.inode.get().await?;
let inode = inode.read();
let len = inode.size(&self.fs) as usize;
2024-12-05 19:25:18 +02:00
if len > self.fs.block_size {
log::warn!("ext2: symlink size > block size");
return Err(Error::InvalidFile);
2024-12-04 20:44:17 +02:00
}
if buf.len() < len {
2024-12-05 19:25:18 +02:00
return Err(Error::BufferTooSmall);
2024-12-04 20:44:17 +02:00
}
2024-08-02 17:04:47 +03:00
2024-12-04 20:44:17 +02:00
let mut write = self.cache.write();
write.clear();
2024-08-02 17:04:47 +03:00
2024-12-04 20:44:17 +02:00
// If length of symlink is lower than 60, data is stored directly in "block address"
// section of the inode
if len < 60 {
let bytes = unsafe { Self::link_from_inode_blocks(&inode, len) };
write.extend_from_slice(bytes);
buf[..len].copy_from_slice(bytes);
} else {
self.fs
.with_inode_block(&inode, 0, |block| {
write.extend_from_slice(&block[..len]);
buf[..len].copy_from_slice(&block[..len]);
Ok(())
})
.await?;
}
2024-08-02 17:04:47 +03:00
2024-12-04 20:44:17 +02:00
Ok(len)
2024-08-02 17:04:47 +03:00
}
2024-12-02 19:02:18 +02:00
unsafe fn link_from_inode_blocks(inode: &Inode, len: usize) -> &[u8] {
2024-08-02 17:04:47 +03:00
debug_assert!(len < 60);
2024-12-02 19:02:18 +02:00
&bytemuck::bytes_of(&inode.blocks)[..len]
2024-08-02 17:04:47 +03:00
}
}
impl CommonImpl for SymlinkNode {
2024-10-11 15:29:41 +03:00
fn size(&self, _node: &NodeRef) -> Result<u64, Error> {
2024-12-04 18:28:27 +02:00
let inode = block!(self.inode.get().await)??;
let inode = inode.read();
2024-12-02 19:02:18 +02:00
Ok(inode.size(&self.fs))
2024-08-02 17:04:47 +03:00
}
fn as_any(&self) -> &dyn Any {
self
}
2024-10-11 15:29:41 +03:00
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
2024-12-04 18:28:27 +02:00
let inode = block!(self.inode.get().await)??;
let inode = inode.read();
2024-12-04 19:22:08 +02:00
Ok(inode.metadata(&self.fs, self.inode.ino()))
2024-08-02 17:04:47 +03:00
}
}
impl SymlinkImpl for SymlinkNode {
fn read_link(&self, buf: &mut [u8]) -> Result<usize, Error> {
{
let read = self.cache.read();
2024-12-02 19:02:18 +02:00
if buf.len() < read.len() {
todo!();
}
2024-08-02 17:04:47 +03:00
if !read.is_empty() {
buf[..read.len()].copy_from_slice(&read[..]);
return Ok(read.len());
}
}
block!(self.read(buf).await)?
}
}