107 lines
2.9 KiB
Rust
107 lines
2.9 KiB
Rust
use core::any::Any;
|
|
|
|
use alloc::{sync::Arc, vec::Vec};
|
|
use libk::{
|
|
block,
|
|
error::Error,
|
|
vfs::{CommonImpl, Metadata, Node, NodeFlags, NodeRef, SymlinkImpl},
|
|
};
|
|
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
|
|
|
use crate::{inode::InodeAccess, Ext2Fs, Inode};
|
|
|
|
pub struct SymlinkNode {
|
|
fs: Arc<Ext2Fs>,
|
|
inode: InodeAccess,
|
|
cache: IrqSafeRwLock<Vec<u8>>,
|
|
}
|
|
|
|
impl SymlinkNode {
|
|
pub fn new(fs: Arc<Ext2Fs>, inode: InodeAccess) -> NodeRef {
|
|
Node::symlink(
|
|
Self {
|
|
fs,
|
|
inode,
|
|
cache: IrqSafeRwLock::new(Vec::new()),
|
|
},
|
|
NodeFlags::empty(),
|
|
None,
|
|
)
|
|
}
|
|
|
|
async fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
|
let inode = self.inode.get().await?;
|
|
let inode = inode.read();
|
|
|
|
let len = inode.size(&self.fs) as usize;
|
|
if len > self.fs.block_size {
|
|
log::warn!("ext2: symlink size > block size");
|
|
return Err(Error::InvalidFile);
|
|
}
|
|
if buf.len() < len {
|
|
return Err(Error::BufferTooSmall);
|
|
}
|
|
|
|
let mut write = self.cache.write();
|
|
write.clear();
|
|
|
|
// 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?;
|
|
}
|
|
|
|
Ok(len)
|
|
}
|
|
|
|
unsafe fn link_from_inode_blocks(inode: &Inode, len: usize) -> &[u8] {
|
|
debug_assert!(len < 60);
|
|
&bytemuck::bytes_of(&inode.blocks)[..len]
|
|
}
|
|
}
|
|
|
|
impl CommonImpl for SymlinkNode {
|
|
fn size(&self, _node: &NodeRef) -> Result<u64, Error> {
|
|
let inode = block!(self.inode.get().await)??;
|
|
let inode = inode.read();
|
|
Ok(inode.size(&self.fs))
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn Any {
|
|
self
|
|
}
|
|
|
|
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
|
let inode = block!(self.inode.get().await)??;
|
|
let inode = inode.read();
|
|
Ok(inode.metadata(&self.fs, self.inode.ino()))
|
|
}
|
|
}
|
|
|
|
impl SymlinkImpl for SymlinkNode {
|
|
fn read_link(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
|
{
|
|
let read = self.cache.read();
|
|
if buf.len() < read.len() {
|
|
todo!();
|
|
}
|
|
if !read.is_empty() {
|
|
buf[..read.len()].copy_from_slice(&read[..]);
|
|
return Ok(read.len());
|
|
}
|
|
}
|
|
|
|
block!(self.read(buf).await)?
|
|
}
|
|
}
|