Skip to main content

rightkit_fs/
lib.rs

1//! Safe filesystem state for Right Suite apps.
2//!
3//! - [`atomic`]: temp + `fsync` + rename replacement, streaming writer, crash-orphan sweep.
4//! - [`lock`]: OS advisory cross-process locks with owner/stale reporting.
5//! - [`private`]: owner-only files and directories (0600/0700, Windows DACL).
6//! - [`state`]: [`StateDir`], a descriptor-pinned state directory (`O_NOFOLLOW`, fd-relative
7//!   `*at` operations) that a swapped or symlinked path cannot redirect.
8//! - [`identity`]: stable file identity across renames and atomic replacement.
9//! - [`clone`]: macOS `clonefile(2)` with `CLONE_NOFOLLOW`; never falls back to a byte copy.
10
11pub mod atomic;
12pub mod clone;
13pub mod error;
14pub mod identity;
15pub mod lock;
16pub mod netfs;
17pub mod private;
18pub mod state;
19
20pub use atomic::{
21    atomic_write, atomic_write_private, atomic_write_with, sweep_stale_temps, AtomicOptions,
22    AtomicWriter,
23};
24pub use clone::{clone_file_nofollow, CloneError};
25pub use error::{FsError, Result};
26pub use identity::{FileKey, IdentityStore, Resolution, StableId, Tracked};
27pub use lock::{with_lock, FileLock, LockOptions, LockOwner};
28pub use netfs::is_network_filesystem;
29pub use private::{
30    create_private_new, ensure_private_dir, restrict_owner_only, sweep_owner_only,
31    write_private_file, write_private_text,
32};
33pub use state::{EntryKind, EntryStat, StateDir};
34
35/// Whether process `pid` currently exists.
36pub fn process_alive(pid: u32) -> bool {
37    #[cfg(unix)]
38    {
39        // SAFETY: signal 0 performs only the existence/permission check.
40        let rc = unsafe { libc::kill(pid as libc::pid_t, 0) };
41        rc == 0 || std::io::Error::last_os_error().raw_os_error() == Some(libc::EPERM)
42    }
43    #[cfg(windows)]
44    {
45        #[link(name = "kernel32")]
46        unsafe extern "system" {
47            fn OpenProcess(access: u32, inherit: i32, pid: u32) -> *mut std::ffi::c_void;
48            fn GetExitCodeProcess(handle: *mut std::ffi::c_void, code: *mut u32) -> i32;
49            fn CloseHandle(handle: *mut std::ffi::c_void) -> i32;
50        }
51        const PROCESS_QUERY_LIMITED_INFORMATION: u32 = 0x1000;
52        const STILL_ACTIVE: u32 = 259;
53        unsafe {
54            let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
55            if handle.is_null() {
56                return false;
57            }
58            let mut code = 0u32;
59            let ok = GetExitCodeProcess(handle, &mut code);
60            CloseHandle(handle);
61            ok != 0 && code == STILL_ACTIVE
62        }
63    }
64    #[cfg(not(any(unix, windows)))]
65    {
66        let _ = pid;
67        true
68    }
69}