summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ripple/Cargo.lock1
-rw-r--r--ripple/fossil/Cargo.toml3
-rw-r--r--ripple/fossil/src/bin/mount.rs157
3 files changed, 140 insertions, 21 deletions
diff --git a/ripple/Cargo.lock b/ripple/Cargo.lock
index b04b546..cb9a42e 100644
--- a/ripple/Cargo.lock
+++ b/ripple/Cargo.lock
@@ -210,6 +210,7 @@ dependencies = [
  "bytes",
  "env_logger",
  "fuser",
+ "lazy_static",
  "libc",
  "log",
  "prost",
diff --git a/ripple/fossil/Cargo.toml b/ripple/fossil/Cargo.toml
index 86972c8..0634152 100644
--- a/ripple/fossil/Cargo.toml
+++ b/ripple/fossil/Cargo.toml
@@ -16,12 +16,13 @@ fuser = { version = "0.11.0", optional = true }
 log = { version = "0.4.14", optional = true }
 libc = { version = "0.2.112", optional = true }
 env_logger = { version = "0.9.0", optional = true }
+lazy_static = { version = "1.4.0", optional = true }
 
 [build-dependencies]
 prost-build = "0.8.0"
 
 [features]
-wip-mount = ["fuser", "log", "libc", "env_logger"]
+wip-mount = ["fuser", "log", "libc", "env_logger", "lazy_static"]
 
 [[bin]]
 name = "mount"
diff --git a/ripple/fossil/src/bin/mount.rs b/ripple/fossil/src/bin/mount.rs
index 5e4063e..4aaa0e0 100644
--- a/ripple/fossil/src/bin/mount.rs
+++ b/ripple/fossil/src/bin/mount.rs
@@ -2,15 +2,79 @@
 // SPDX-License-Identifier: OSL-3.0
 
 use {
-	libc::{c_int, ENOSYS, EROFS},
+	lazy_static::lazy_static,
+	libc::{c_int, ENOENT, ENOSYS, EROFS},
 	log::{debug, warn},
+	std::{
+		time::{Duration, SystemTime, UNIX_EPOCH},
+	},
 };
 
+lazy_static! {
+	static ref EPOCH_PLUS_ONE: SystemTime = UNIX_EPOCH + Duration::from_secs(1);
+}
+
+enum Kind {
+	Link,
+	File,
+	Directory,
+}
+
+fn file_attr(ino: u64, kind: Kind, size: u64) -> fuser::FileAttr {
+	let blksize = 512;
+	fuser::FileAttr {
+		/// Inode number
+		ino,
+		/// Size in bytes
+		size,
+		/// Size in blocks
+        // TODO(edef): switch to u64::div_ceil
+		blocks: (size + blksize as u64 - 1) / (blksize as u64),
+		/// Time of last access
+		atime: *EPOCH_PLUS_ONE,
+		/// Time of last modification
+		mtime: *EPOCH_PLUS_ONE,
+		/// Time of last change
+		ctime: *EPOCH_PLUS_ONE,
+		/// Time of creation (macOS only)
+		crtime: *EPOCH_PLUS_ONE,
+		/// Kind of file (directory, file, pipe, etc)
+		kind: match kind {
+			Kind::Directory => fuser::FileType::Directory,
+			Kind::File => fuser::FileType::RegularFile,
+			Kind::Link => fuser::FileType::Symlink,
+		},
+		/// Permissions
+		perm: match kind {
+			Kind::Directory => 0o755,
+			_ => 0o644,
+		},
+		/// Number of hard links
+		nlink: 1,
+		/// User id
+		uid: 1000,
+		/// Group id
+		gid: 100,
+		/// Rdev
+		rdev: 0,
+		/// Block size
+		blksize,
+		/// Flags (macOS only, see chflags(2))
+		flags: 0,
+	}
+}
+
 fn main() {
 	env_logger::init();
 
 	let store = fossil::Store::open("fossil.db").unwrap();
-	fuser::mount2(Filesystem::open(store), "mnt", &[]).unwrap();
+
+	fuser::mount2(
+		Filesystem::open(store),
+		"mnt",
+		&[fuser::MountOption::DefaultPermissions],
+	)
+	.unwrap();
 }
 
 struct Filesystem {
@@ -41,18 +105,39 @@ impl fuser::Filesystem for Filesystem {
 		name: &std::ffi::OsStr,
 		reply: fuser::ReplyEntry,
 	) {
-		warn!(
-			"[Not Implemented] lookup(parent: {:#x?}, name {:?})",
-			parent, name
+		if parent != 1 {
+			warn!(
+				"[Not Implemented] lookup(parent: {:#x?}, name {:?})",
+				parent, name
+			);
+			reply.error(ENOSYS);
+			return;
+		}
+		if name != "hello" {
+			reply.error(ENOENT);
+			return;
+		}
+		reply.entry(
+			&Duration::ZERO,
+			&file_attr(2, Kind::File, "world".len() as u64),
+			0,
 		);
-		reply.error(ENOSYS);
 	}
 
 	fn forget(&mut self, _req: &fuser::Request<'_>, _ino: u64, _nlookup: u64) {}
 
 	fn getattr(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyAttr) {
-		warn!("[Not Implemented] getattr(ino: {:#x?})", ino);
-		reply.error(ENOSYS);
+		match ino {
+			1 => reply.attr(&Duration::ZERO, &file_attr(ino, Kind::Directory, 2)),
+			2 => reply.attr(
+				&Duration::ZERO,
+				&file_attr(ino, Kind::File, "world".len() as u64),
+			),
+			_ => {
+				warn!("[Not Implemented] getattr(ino: {:#x?})", ino);
+				reply.error(ENOSYS);
+			}
+		}
 	}
 
 	fn setattr(
@@ -180,12 +265,27 @@ impl fuser::Filesystem for Filesystem {
 		lock_owner: Option<u64>,
 		reply: fuser::ReplyData,
 	) {
-		warn!(
-			"[Not Implemented] read(ino: {:#x?}, fh: {}, offset: {}, size: {}, \
-            flags: {:#x?}, lock_owner: {:?})",
-			ino, fh, offset, size, flags, lock_owner
-		);
-		reply.error(ENOSYS);
+		match ino {
+			2 => {
+				let offset = offset as usize;
+				let size = size as usize;
+
+				let content = b"world";
+				let mut buffer = content.get(offset..).unwrap_or_default();
+				if buffer.len() > size {
+					buffer = &buffer[..size];
+				}
+				reply.data(buffer);
+			}
+			_ => {
+				warn!(
+					"[Not Implemented] read(ino: {:#x?}, fh: {}, offset: {}, size: {}, \
+					 flags: {:#x?}, lock_owner: {:?})",
+					ino, fh, offset, size, flags, lock_owner
+				);
+				reply.error(ENOSYS);
+			}
+		}
 	}
 
 	fn write(
@@ -262,13 +362,30 @@ impl fuser::Filesystem for Filesystem {
 		ino: u64,
 		fh: u64,
 		offset: i64,
-		reply: fuser::ReplyDirectory,
+		mut reply: fuser::ReplyDirectory,
 	) {
-		warn!(
-			"[Not Implemented] readdir(ino: {:#x?}, fh: {}, offset: {})",
-			ino, fh, offset
-		);
-		reply.error(ENOSYS);
+		if ino != 1 {
+			warn!(
+				"[Not Implemented] readdir(ino: {:#x?}, fh: {}, offset: {})",
+				ino, fh, offset
+			);
+			reply.error(ENOSYS);
+			return;
+		}
+
+		let children = &[
+			(ino, fuser::FileType::Directory, "."),
+			(ino, fuser::FileType::Directory, ".."),
+			(0x2, fuser::FileType::RegularFile, "hello"),
+		];
+
+		for (offset, &(ino, kind, name)) in children.iter().enumerate().skip(offset as usize) {
+			if reply.add(ino, (offset + 1) as i64, kind, name) {
+				break;
+			}
+		}
+
+		reply.ok();
 	}
 
 	fn readdirplus(