Skip to content

Port branchfs to macOS#26

Open
nitin966 wants to merge 3 commits intomultikernel:mainfrom
nitin966:main
Open

Port branchfs to macOS#26
nitin966 wants to merge 3 commits intomultikernel:mainfrom
nitin966:main

Conversation

@nitin966
Copy link

Description

Port branchfs to macOS with verified integration tests and stable control interface

Testing

All existing tests pass

@nitin966 nitin966 mentioned this pull request Mar 16, 2026
@congwang-mk
Copy link
Contributor

Could we separate the platform specific code? For example, src/platform/linux.rs and src/platform/macos.rs behind a src/platform/mod.rs that re-exports the right impl via #[cfg]. Move into it:

  • Ioctl constants
  • Mount option construction
  • init() capability setup
  • Passthrough open logic
  • access() impl
  • Rename flag handling

Copy link
Contributor

@congwang-mk congwang-mk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your update. Some additional reviews

let options = vec![
let mut options = vec![
MountOption::FSName("branchfs".to_string()),
MountOption::DefaultPermissions,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this also removed for Linux?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it here because we refactored all mount options out into the new platform/ module to separate the OS-specific logic. I've restored MountOption::DefaultPermissions explicitly for Linux inside

src/platform/linux.rs
get_mount_options()

function, while successfully keeping it disabled for macOS. Let me know if you have any concerns.

crtime: UNIX_EPOCH,
kind: FileType::RegularFile,
perm: 0o600,
perm: 0o777,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this perm change expected?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, no, that was an accident! I temporarily raised the permissions to 0o777 during some deep debugging of EPERM failures specifically on macOS. Now that the true root cause is solved, this should definitely be 0o600. I have reverted it back. Good catch!

// Report a non-zero size so the kernel issues read() calls.
// The actual content length is determined by the read handler.
let size = if ino == CTL_INO { 256 } else { 0 };
let size = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is intentional. When testing on mac, I discovered that if the control file reports a size > 0 (e.g. 256), writing to it causes the macOS kernel to issue a Read-Modify-Write cycle. The kernel would internally read the dummy contents, blend it with our command, and then write a corrupted string (e.g. \0\0\0commit\0\0...) which broke our command parsing. Setting the size to exactly 0 forces the kernel to send the raw write payload exactly as intended.

let mut buf = [0u8; 128];
let ret = libc::ioctl(fd, FS_IOC_BRANCH_CREATE as libc::c_ulong, buf.as_mut_ptr());
if ret < 0 {
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! That was a copy-pasted polyfill for parsing errno across all Apple and BSD platforms. Since branchfs only officially targets linux and macos, I've stripped out the rest of those OS targets as dead code to make it much cleaner.

if ret < 0 {
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
return Err(unsafe { *libc::__error() });
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd")))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

#[cfg(target_os = "linux")]
pub use linux::*;

#[cfg(not(target_os = "linux"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flip this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point. Relying on not(linux) was too broad and would break if anyone ever tried to build this on Windows or FreeBSD. I've flipped both of those to explicitly use #[cfg(target_os = "macos")] to strictly isolate the Apple-specific module. Thanks for catching that.


#[cfg(not(target_os = "linux"))]
mod macos;
#[cfg(not(target_os = "linux"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants