feat: Add UDS bind and connect integration
This commit is contained in:
committed by
Jeremy Soller
parent
dc25344b68
commit
63217aa69a
Generated
+7
-7
@@ -303,9 +303,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
|
||||
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -417,9 +417,9 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||
|
||||
[[package]]
|
||||
name = "redox-scheme"
|
||||
version = "0.6.2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c00025a04f76fdcf72c15f10c7a12d9f2fdde93e539be9a57d5d632c4158a9e"
|
||||
checksum = "4da6a0251965958189cdfd5ebb66f99754db4aa165394300aa2b958525d94b64"
|
||||
dependencies = [
|
||||
"libredox",
|
||||
"redox_syscall",
|
||||
@@ -427,9 +427,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.13"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
||||
checksum = "7e8af0dde094006011e6a740d4879319439489813bd0bcdc7d821beaeeff48ec"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -442,7 +442,7 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
||||
|
||||
[[package]]
|
||||
name = "redoxfs"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"argon2",
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
name = "redoxfs"
|
||||
description = "The Redox Filesystem"
|
||||
repository = "https://gitlab.redox-os.org/redox-os/redoxfs"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
license-file = "LICENSE"
|
||||
readme = "README.md"
|
||||
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||
@@ -38,12 +38,12 @@ endian-num = "0.1"
|
||||
env_logger = { version = "0.11", optional = true }
|
||||
getrandom = { version = "0.2.5", optional = true }
|
||||
libc = "0.2"
|
||||
libredox = { version = "0.1.3", optional = true }
|
||||
log = { version = "0.4.14", default-features = false, optional = true}
|
||||
libredox = { version = "0.1.6", features = ["call"], optional = true }
|
||||
log = { version = "0.4.14", default-features = false, optional = true }
|
||||
range-tree = { version = "0.1", optional = true }
|
||||
redox-path = "0.3.0"
|
||||
redox-scheme = { version = "0.6.2", optional = true }
|
||||
redox_syscall = { version = "0.5.13" }
|
||||
redox-scheme = { version = "0.7.0", optional = true }
|
||||
redox_syscall = { version = "0.5.15", optional = true }
|
||||
seahash = { version = "4.1.0", default-features = false }
|
||||
termion = { version = "4", optional = true }
|
||||
uuid = { version = "1.4", default-features = false }
|
||||
|
||||
+18
-8
@@ -1,4 +1,4 @@
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{scheme::SchemeSync, RequestKind, Response, SignalBehavior, Socket};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::Ordering;
|
||||
@@ -22,17 +22,27 @@ where
|
||||
let mounted_path = format!("/scheme/{}", mountpoint.display());
|
||||
let res = callback(Path::new(&mounted_path));
|
||||
|
||||
let mut scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem);
|
||||
let mut scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem, &socket);
|
||||
while IS_UMT.load(Ordering::SeqCst) == 0 {
|
||||
let req = match socket.next_request(SignalBehavior::Restart)? {
|
||||
None => break,
|
||||
Some(req) => {
|
||||
if let RequestKind::Call(r) = req.kind() {
|
||||
r
|
||||
} else {
|
||||
// TODO: Redoxfs does not yet support asynchronous file IO. It might still make
|
||||
// sense to implement cancellation for huge buffers, e.g. dd bs=1G
|
||||
continue;
|
||||
match req.kind() {
|
||||
RequestKind::Call(r) => r,
|
||||
RequestKind::SendFd(sendfd_request) => {
|
||||
let result = scheme.on_sendfd(&sendfd_request);
|
||||
let response = Response::new(result, sendfd_request);
|
||||
|
||||
if !socket.write_response(response, SignalBehavior::Restart)? {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
// TODO: Redoxfs does not yet support asynchronous file IO. It might still make
|
||||
// sense to implement cancellation for huge buffers, e.g. dd bs=1G
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+153
-10
@@ -3,18 +3,20 @@ use std::str;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult};
|
||||
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult, SendFdRequest, Socket};
|
||||
use syscall::data::{Stat, StatVfs, TimeSpec};
|
||||
use syscall::dirent::DirentBuf;
|
||||
use syscall::error::{
|
||||
Error, Result, EACCES, EBADF, EBUSY, EEXIST, EINVAL, EISDIR, ELOOP, ENOENT, ENOTDIR, ENOTEMPTY,
|
||||
EPERM, EXDEV,
|
||||
EOPNOTSUPP, EPERM, EXDEV,
|
||||
};
|
||||
use syscall::flag::{
|
||||
EventFlags, MapFlags, O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_NOFOLLOW, O_RDONLY, O_RDWR,
|
||||
O_STAT, O_SYMLINK, O_TRUNC, O_WRONLY,
|
||||
};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::FobtainFdFlags;
|
||||
use syscall::FsCall;
|
||||
use syscall::MunmapFlags;
|
||||
|
||||
use redox_path::{
|
||||
@@ -26,22 +28,28 @@ use crate::{Disk, FileSystem, Node, Transaction, TreeData, TreePtr, BLOCK_SIZE};
|
||||
|
||||
use super::resource::{DirResource, Entry, FileResource, Resource};
|
||||
|
||||
pub struct FileScheme<D: Disk> {
|
||||
pub struct FileScheme<'sock, D: Disk> {
|
||||
name: String,
|
||||
pub(crate) fs: FileSystem<D>,
|
||||
socket: &'sock Socket,
|
||||
next_id: AtomicUsize,
|
||||
files: BTreeMap<usize, Box<dyn Resource<D>>>,
|
||||
fmap: super::resource::Fmaps,
|
||||
|
||||
// Map of file id to other scheme's file descriptor.
|
||||
other_scheme_fd_map: BTreeMap<u32, usize>,
|
||||
}
|
||||
|
||||
impl<D: Disk> FileScheme<D> {
|
||||
pub fn new(name: String, fs: FileSystem<D>) -> FileScheme<D> {
|
||||
impl<'sock, D: Disk> FileScheme<'sock, D> {
|
||||
pub fn new(name: String, fs: FileSystem<D>, socket: &'sock Socket) -> FileScheme<'sock, D> {
|
||||
FileScheme {
|
||||
name,
|
||||
fs,
|
||||
socket,
|
||||
next_id: AtomicUsize::new(1),
|
||||
files: BTreeMap::new(),
|
||||
fmap: BTreeMap::new(),
|
||||
other_scheme_fd_map: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +118,17 @@ impl<D: Disk> FileScheme<D> {
|
||||
Err(Error::new(ELOOP))
|
||||
}
|
||||
|
||||
fn handle_connect(&mut self, id: usize, payload: &mut [u8]) -> Result<usize> {
|
||||
let resource = self.files.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let inode_id = resource.node_ptr().id();
|
||||
let target_fd = self
|
||||
.other_scheme_fd_map
|
||||
.get(&inode_id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
let len = libredox::call::get_socket_token(*target_fd, payload)?;
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
fn open_internal(
|
||||
&mut self,
|
||||
start_ptr: TreePtr<Node>,
|
||||
@@ -383,7 +402,7 @@ fn dirname(path: &str) -> Option<String> {
|
||||
canonicalize_using_cwd(Some(path), "..")
|
||||
}
|
||||
|
||||
impl<D: Disk> SchemeSync for FileScheme<D> {
|
||||
impl<'sock, D: Disk> SchemeSync for FileScheme<'sock, D> {
|
||||
fn open(&mut self, url: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
self.open_internal(TreePtr::root(), url, flags, ctx)
|
||||
}
|
||||
@@ -454,7 +473,7 @@ impl<D: Disk> SchemeSync for FileScheme<D> {
|
||||
// println!("Unlink '{}'", path);
|
||||
|
||||
let scheme_name = &self.name;
|
||||
self.fs.tx(|tx| {
|
||||
let unlink_result = self.fs.tx(|tx| {
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
let Some((child, child_name)) =
|
||||
@@ -480,15 +499,23 @@ impl<D: Disk> SchemeSync for FileScheme<D> {
|
||||
|
||||
if child.data().is_symlink() {
|
||||
tx.remove_node(parent.ptr(), &child_name, Node::MODE_SYMLINK)
|
||||
.and(Ok(()))
|
||||
} else if child.data().is_sock() {
|
||||
tx.remove_node(parent.ptr(), &child_name, Node::MODE_SOCK)
|
||||
} else {
|
||||
tx.remove_node(parent.ptr(), &child_name, Node::MODE_FILE)
|
||||
.and(Ok(()))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EISDIR))
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let Some(node_id) = unlink_result? else {
|
||||
return Ok(());
|
||||
};
|
||||
if let Some(fd) = self.other_scheme_fd_map.remove(&node_id) {
|
||||
let _ = syscall::close(fd);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/* Resource operations */
|
||||
@@ -910,4 +937,120 @@ impl<D: Disk> SchemeSync for FileScheme<D> {
|
||||
// TODO: If open_fds reaches zero and there are no hardlinks (directory entries) to any
|
||||
// particular inode, remove that inode here.
|
||||
}
|
||||
|
||||
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
|
||||
let ctx = sendfd_request.caller();
|
||||
let uid = ctx.uid;
|
||||
let gid = ctx.gid;
|
||||
|
||||
let parent_resource = self
|
||||
.files
|
||||
.get(&sendfd_request.id())
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let mut new_fd = usize::MAX;
|
||||
if let Err(e) =
|
||||
sendfd_request.obtain_fd(&self.socket, FobtainFdFlags::empty(), Err(&mut new_fd))
|
||||
{
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
let parent_resource_ptr = parent_resource.node_ptr();
|
||||
|
||||
let parent_node = self.fs.tx(|tx| tx.read_tree(parent_resource_ptr))?;
|
||||
if !parent_node.data().is_dir() {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
}
|
||||
if !parent_node.data().permission(uid, gid, Node::MODE_WRITE) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
let parent_path = parent_resource.path();
|
||||
|
||||
// TODO: Move the PATH_MAX definition to a more appropriate place.
|
||||
const PATH_MAX: usize = 4096;
|
||||
let mut url_buf = [0u8; PATH_MAX];
|
||||
let url_len = syscall::fpath(new_fd, &mut url_buf)?;
|
||||
let url_str = str::from_utf8(&url_buf[..url_len]).map_err(|_| Error::new(EINVAL))?;
|
||||
let redox_path = RedoxPath::from_absolute(url_str).ok_or(Error::new(EINVAL))?;
|
||||
let (_, path) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let mut last_part = String::new();
|
||||
for part in path.as_ref().split('/') {
|
||||
if !part.is_empty() {
|
||||
last_part = part.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
let (resource, node_id): (Box<dyn Resource<D>>, u32) = if !last_part.is_empty() {
|
||||
let mut stat = Stat::default();
|
||||
syscall::fstat(new_fd, &mut stat)?;
|
||||
let mode_type = stat.st_mode & Node::MODE_TYPE;
|
||||
|
||||
let flags = 0o777;
|
||||
let node_ptr = self.fs.tx(|tx| {
|
||||
if tx.find_node(parent_resource_ptr, &last_part).is_ok() {
|
||||
// If the file already exists, we cannot create it again
|
||||
return Err(Error::new(EEXIST));
|
||||
}
|
||||
|
||||
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut node = tx.create_node(
|
||||
parent_resource_ptr,
|
||||
&last_part,
|
||||
mode_type | (flags as u16 & Node::MODE_PERM),
|
||||
ctime.as_secs(),
|
||||
ctime.subsec_nanos(),
|
||||
)?;
|
||||
let node_ptr = node.ptr();
|
||||
if node.data().uid() != uid || node.data().gid() != gid {
|
||||
node.data_mut().set_uid(uid);
|
||||
node.data_mut().set_gid(gid);
|
||||
tx.sync_tree(node)?;
|
||||
}
|
||||
Ok(node_ptr)
|
||||
})?;
|
||||
|
||||
let file_path = format!("{parent_path}/{last_part}");
|
||||
let node_id = node_ptr.id();
|
||||
|
||||
(
|
||||
Box::new(FileResource::new(
|
||||
file_path,
|
||||
Some(parent_resource_ptr),
|
||||
node_ptr,
|
||||
flags,
|
||||
uid,
|
||||
)),
|
||||
node_id,
|
||||
)
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
};
|
||||
|
||||
self.fmap
|
||||
.entry(resource.node_ptr().id())
|
||||
.or_insert_with(Default::default)
|
||||
.open_fds += 1;
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
|
||||
self.files.insert(id, resource);
|
||||
self.other_scheme_fd_map.insert(node_id, new_fd);
|
||||
Ok(new_fd)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
id: usize,
|
||||
payload: &mut [u8],
|
||||
metadata: &[u64],
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let Some(verb) = FsCall::try_from_raw(metadata[0] as usize) else {
|
||||
return Err(Error::new(EINVAL));
|
||||
};
|
||||
match verb {
|
||||
FsCall::Connect => self.handle_connect(id, payload),
|
||||
_ => Err(Error::new(EOPNOTSUPP)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ impl Node {
|
||||
pub const MODE_FILE: u16 = 0x8000;
|
||||
pub const MODE_DIR: u16 = 0x4000;
|
||||
pub const MODE_SYMLINK: u16 = 0xA000;
|
||||
pub const MODE_SOCK: u16 = 0xC000;
|
||||
|
||||
/// Mask for node permission bits
|
||||
pub const MODE_PERM: u16 = 0x0FFF;
|
||||
@@ -310,6 +311,10 @@ impl Node {
|
||||
self.mode() & Self::MODE_TYPE == Self::MODE_SYMLINK
|
||||
}
|
||||
|
||||
pub fn is_sock(&self) -> bool {
|
||||
self.mode() & Self::MODE_SOCK == Self::MODE_SOCK
|
||||
}
|
||||
|
||||
/// Tests if UID is the owner of that file, only true when uid=0 or when the UID stored in metadata is equal to the UID you supply
|
||||
pub fn owner(&self, uid: u32) -> bool {
|
||||
uid == 0 || self.uid() == uid
|
||||
|
||||
+10
-3
@@ -993,7 +993,12 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn remove_node(&mut self, parent_ptr: TreePtr<Node>, name: &str, mode: u16) -> Result<()> {
|
||||
pub fn remove_node(
|
||||
&mut self,
|
||||
parent_ptr: TreePtr<Node>,
|
||||
name: &str,
|
||||
mode: u16,
|
||||
) -> Result<Option<u32>> {
|
||||
#[cfg(feature = "log")]
|
||||
log::debug!(
|
||||
"REMOVE_NODE: name: {}, mode: {:x}, parent_ptr: {:?}",
|
||||
@@ -1052,6 +1057,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
}
|
||||
|
||||
let links = node.data().links();
|
||||
let node_id = node.id();
|
||||
let remove_node = if links > 1 {
|
||||
node.data_mut().set_links(links - 1);
|
||||
false
|
||||
@@ -1102,12 +1108,13 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
unsafe {
|
||||
self.deallocate(node_addr);
|
||||
}
|
||||
|
||||
Ok(Some(node_id))
|
||||
} else {
|
||||
// Sync both parent and node at the same time
|
||||
self.sync_trees(&[parent, node])?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_node_inner(
|
||||
|
||||
Reference in New Issue
Block a user