Support create()
This commit is contained in:
parent
d7f0e7a141
commit
6a16534ec7
@ -1,7 +1,7 @@
|
|||||||
use fuser::{
|
use fuser::{
|
||||||
Filesystem, KernelConfig, ReplyAttr, ReplyBmap, ReplyCreate, ReplyData, ReplyDirectory,
|
FileAttr, Filesystem, KernelConfig, ReplyAttr, ReplyBmap, ReplyCreate, ReplyData,
|
||||||
ReplyDirectoryPlus, ReplyEmpty, ReplyEntry, ReplyIoctl, ReplyLock, ReplyLseek, ReplyOpen,
|
ReplyDirectory, ReplyDirectoryPlus, ReplyEmpty, ReplyEntry, ReplyIoctl, ReplyLock, ReplyLseek,
|
||||||
ReplyStatfs, ReplyWrite, ReplyXattr, Request, TimeOrNow,
|
ReplyOpen, ReplyStatfs, ReplyWrite, ReplyXattr, Request, TimeOrNow,
|
||||||
};
|
};
|
||||||
use libc::{ENOSYS, EPERM, O_APPEND, O_RDONLY, O_RDWR, O_WRONLY};
|
use libc::{ENOSYS, EPERM, O_APPEND, O_RDONLY, O_RDWR, O_WRONLY};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
@ -200,6 +200,8 @@ impl Filesystem for OliveFilesystem {
|
|||||||
rdev: u32,
|
rdev: u32,
|
||||||
reply: ReplyEntry,
|
reply: ReplyEntry,
|
||||||
) {
|
) {
|
||||||
|
// TODO Support this as a create + release.
|
||||||
|
// Modern Linuxes will call create() rather than mknod()+open() so this may even be optional.
|
||||||
debug!(
|
debug!(
|
||||||
"[Not Implemented] mknod(parent: {:#x?}, name: {:?}, mode: {}, \
|
"[Not Implemented] mknod(parent: {:#x?}, name: {:?}, mode: {}, \
|
||||||
umask: {:#x?}, rdev: {})",
|
umask: {:#x?}, rdev: {})",
|
||||||
@ -381,7 +383,7 @@ impl Filesystem for OliveFilesystem {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
"opendir",
|
"open",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,7 +819,75 @@ impl Filesystem for OliveFilesystem {
|
|||||||
flags: {:#x?})",
|
flags: {:#x?})",
|
||||||
parent, name, mode, umask, flags
|
parent, name, mode, umask, flags
|
||||||
);
|
);
|
||||||
reply.error(ENOSYS);
|
|
||||||
|
let name = if let Some(name) = name.to_str() {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
// If we can't decode the filename, pretend it doesn't exist.
|
||||||
|
reply.error(ENOENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let requester = self.requester.clone();
|
||||||
|
|
||||||
|
// TODO This needs more careful consideration before using to write files
|
||||||
|
// How does truncation work?
|
||||||
|
let mut open_mode = OpenMode {
|
||||||
|
read: false,
|
||||||
|
write: false,
|
||||||
|
append: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if test_bits(flags, O_APPEND) {
|
||||||
|
open_mode.append = true;
|
||||||
|
}
|
||||||
|
if test_bits(flags, O_RDWR) {
|
||||||
|
open_mode.read = true;
|
||||||
|
open_mode.write = true;
|
||||||
|
} else if test_bits(flags, O_WRONLY) {
|
||||||
|
open_mode.write = true;
|
||||||
|
} else if test_bits(flags, O_RDONLY) {
|
||||||
|
open_mode.read = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.spawn_with_error_handler(
|
||||||
|
async move {
|
||||||
|
let parent_vnode = VnodeId(
|
||||||
|
parent
|
||||||
|
.try_into()
|
||||||
|
.context("Converting u64 inode to u32 VnodeId.")?,
|
||||||
|
);
|
||||||
|
|
||||||
|
match requester.create(parent_vnode, open_mode, name).await? {
|
||||||
|
DataResponse::Success((file_handle, metadata)) => {
|
||||||
|
// Use the direct I/O flag so that we can be in control of when EOF happens
|
||||||
|
// rather than letting the kernel assume the getattr size is valid
|
||||||
|
// and caching up to that point.
|
||||||
|
// We might wind up wanting to do our own buffering...
|
||||||
|
let file_attr: FileAttr = metadata.into();
|
||||||
|
// TODO generation should be generated client-side
|
||||||
|
reply.created(
|
||||||
|
&Duration::from_secs(5),
|
||||||
|
&file_attr,
|
||||||
|
0,
|
||||||
|
file_handle as u64,
|
||||||
|
FOPEN_DIRECT_IO,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
DataResponse::Error { code, message } => {
|
||||||
|
warn!(
|
||||||
|
"create(parent: {:#x?}, flags: {:#x?}) failed: {:?}",
|
||||||
|
parent_vnode, flags, message
|
||||||
|
);
|
||||||
|
reply.error(code as c_int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
"create",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test for a POSIX file lock.
|
/// Test for a POSIX file lock.
|
||||||
|
@ -196,6 +196,21 @@ impl Requester {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create(
|
||||||
|
&self,
|
||||||
|
dir_vnode: VnodeId,
|
||||||
|
mode: OpenMode,
|
||||||
|
name: String,
|
||||||
|
) -> anyhow::Result<DataResponse<(u32, FileMetadata)>> {
|
||||||
|
self.internal
|
||||||
|
.command(&DataCommand::CreateFile {
|
||||||
|
dir_vnode,
|
||||||
|
mode,
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn open(&self, vnode: VnodeId, mode: OpenMode) -> anyhow::Result<DataResponse<u32>> {
|
pub async fn open(&self, vnode: VnodeId, mode: OpenMode) -> anyhow::Result<DataResponse<u32>> {
|
||||||
self.internal
|
self.internal
|
||||||
.command(&DataCommand::OpenFile { vnode, mode })
|
.command(&DataCommand::OpenFile { vnode, mode })
|
||||||
|
@ -54,6 +54,11 @@ pub enum DataCommand {
|
|||||||
dir_vnode: VnodeId,
|
dir_vnode: VnodeId,
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
CreateFile {
|
||||||
|
dir_vnode: VnodeId,
|
||||||
|
mode: OpenMode,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
OpenFile {
|
OpenFile {
|
||||||
vnode: VnodeId,
|
vnode: VnodeId,
|
||||||
mode: OpenMode,
|
mode: OpenMode,
|
||||||
|
@ -62,6 +62,14 @@ pub async fn handle_command_stream(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
DataCommand::CreateFile {
|
||||||
|
dir_vnode,
|
||||||
|
mode,
|
||||||
|
name,
|
||||||
|
} => {
|
||||||
|
send_bare_message(&mut tx, &file_access.create(dir_vnode, mode, name).await?)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +297,71 @@ impl FileAccess {
|
|||||||
Ok(DataResponse::Success(()))
|
Ok(DataResponse::Success(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create(
|
||||||
|
&self,
|
||||||
|
dir_vnode: VnodeId,
|
||||||
|
mode: OpenMode,
|
||||||
|
name: String,
|
||||||
|
) -> anyhow::Result<DataResponse<(u32, FileMetadata)>> {
|
||||||
|
match self.resolve_vnode(dir_vnode).await {
|
||||||
|
Ok(dir_path) => {
|
||||||
|
let lookup_path = dir_path.join(name);
|
||||||
|
// TODO check the security of this: make sure you can't escape the root
|
||||||
|
match lookup_path.absolutize_virtually(&self.client_info.root) {
|
||||||
|
Ok(the_path) => {
|
||||||
|
// We'll allocate the Vnode after we know the target doesn't already exist. Fill in 0 for now.
|
||||||
|
let mut open_options = OpenOptions::new();
|
||||||
|
|
||||||
|
// Only create new files
|
||||||
|
open_options.create_new(true);
|
||||||
|
|
||||||
|
if mode.read {
|
||||||
|
open_options.read(true);
|
||||||
|
}
|
||||||
|
if mode.write {
|
||||||
|
open_options.write(true);
|
||||||
|
}
|
||||||
|
if mode.append {
|
||||||
|
open_options.append(true);
|
||||||
|
}
|
||||||
|
// TODO truncate?
|
||||||
|
|
||||||
|
match open_options.open(&the_path).await {
|
||||||
|
Ok(file) => {
|
||||||
|
// TODO offset & append files: how does that work?
|
||||||
|
let handle = Arc::new(RwLock::new(FileHandle { file, offset: 0 }));
|
||||||
|
|
||||||
|
let file_handle: u32 = self
|
||||||
|
.client_state
|
||||||
|
.file_handles
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.insert(handle)
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let vnode = self.allocate_vnode(the_path.to_path_buf()).await?;
|
||||||
|
let metadata = self.read_metadata(&the_path, vnode).await?;
|
||||||
|
|
||||||
|
Ok(DataResponse::Success((file_handle, metadata)))
|
||||||
|
}
|
||||||
|
Err(error) => Ok(io_error_to_response(
|
||||||
|
error,
|
||||||
|
EFAULT,
|
||||||
|
&format!("create {:?}", the_path),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => Ok(DataResponse::Error {
|
||||||
|
code: ENOENT,
|
||||||
|
message: format!("Can't make absolute. {:?} ({:?})", error, lookup_path),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(response) => Ok(response),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn lookup(
|
pub async fn lookup(
|
||||||
&self,
|
&self,
|
||||||
dir_vnode: VnodeId,
|
dir_vnode: VnodeId,
|
||||||
|
Loading…
Reference in New Issue
Block a user