use super::*;
impl PassthroughFs {
pub fn open(&self, inode: u64, flags: u32) -> Result<u64> {
let path = self.inode_path(inode)?;
let mut opts = OpenOptions::new();
Self::apply_flags(&mut opts, flags);
let file = opts.open(&path).map_err(FsError::io)?;
let handle = self.alloc_handle();
{
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
handles.insert(handle, HandleData { file, inode, flags });
}
Ok(handle)
}
pub fn read(&self, handle: u64, offset: u64, size: u32) -> Result<Vec<u8>> {
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let data = handles
.get_mut(&handle)
.ok_or(FsError::InvalidHandle(handle))?;
data.file
.seek(SeekFrom::Start(offset))
.map_err(FsError::io)?;
let mut buf = vec![0u8; size as usize];
let n = data.file.read(&mut buf).map_err(FsError::io)?;
buf.truncate(n);
Ok(buf)
}
pub fn write(&self, handle: u64, offset: u64, data: &[u8], _flags: u32) -> Result<u32> {
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let handle_data = handles
.get_mut(&handle)
.ok_or(FsError::InvalidHandle(handle))?;
handle_data
.file
.seek(SeekFrom::Start(offset))
.map_err(FsError::io)?;
let n = handle_data.file.write(data).map_err(FsError::io)?;
#[allow(clippy::cast_possible_truncation)]
Ok(n as u32)
}
pub fn flush(&self, handle: u64) -> Result<()> {
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let data = handles
.get_mut(&handle)
.ok_or(FsError::InvalidHandle(handle))?;
data.file.flush().map_err(FsError::io)
}
pub fn fsync(&self, handle: u64, datasync: bool) -> Result<()> {
let handles = self
.handles
.read()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let data = handles.get(&handle).ok_or(FsError::InvalidHandle(handle))?;
if datasync {
data.file.sync_data().map_err(FsError::io)
} else {
data.file.sync_all().map_err(FsError::io)
}
}
pub fn release(&self, handle: u64) -> Result<()> {
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
handles.remove(&handle);
Ok(())
}
pub fn get_file_raw_fd(&self, handle: u64) -> Option<std::os::unix::io::RawFd> {
use std::os::unix::io::AsRawFd;
let handles = self.handles.read().ok()?;
handles.get(&handle).map(|h| h.file.as_raw_fd())
}
pub fn lseek(&self, handle: u64, offset: i64, whence: u32) -> Result<u64> {
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let data = handles
.get_mut(&handle)
.ok_or(FsError::InvalidHandle(handle))?;
let seek_from = match whence {
0 => SeekFrom::Start(offset as u64), 1 => SeekFrom::Current(offset), 2 => SeekFrom::End(offset), _ => return Err(FsError::InvalidPath("invalid whence".to_string())),
};
data.file.seek(seek_from).map_err(FsError::io)
}
#[cfg(target_os = "linux")]
pub fn fallocate(&self, handle: u64, mode: u32, offset: u64, length: u64) -> Result<()> {
let handles = self
.handles
.read()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let data = handles.get(&handle).ok_or(FsError::InvalidHandle(handle))?;
let fd = data.file.as_raw_fd();
#[allow(clippy::cast_possible_wrap)]
let ret = unsafe { libc::fallocate(fd, mode as i32, offset as i64, length as i64) };
if ret != 0 {
Err(FsError::io(std::io::Error::last_os_error()))
} else {
Ok(())
}
}
#[cfg(target_os = "macos")]
pub fn fallocate(&self, handle: u64, _mode: u32, offset: u64, length: u64) -> Result<()> {
let mut handles = self
.handles
.write()
.map_err(|_| FsError::Cache("failed to acquire handle lock".to_string()))?;
let data = handles
.get_mut(&handle)
.ok_or(FsError::InvalidHandle(handle))?;
let new_size = offset + length;
data.file.set_len(new_size).map_err(FsError::io)
}
}