graphforge-filesystem 0.6.0-rc.1

Audited native filesystem primitives for GraphForge durability
Documentation
use super::*;
use crate::{StableDirectory, file_identity, file_link_count, path_identity, windows};
use std::ffi::OsStr;

#[cfg(windows)]
#[test]
fn stable_directory_adopts_readonly_legacy_cas_without_data_write_authority() {
    use std::io::Read as _;
    use std::os::windows::fs::OpenOptionsExt as _;

    const FILE_SHARE_READ: u32 = 0x0000_0001;
    const FILE_SHARE_WRITE: u32 = 0x0000_0002;
    let root = tempfile::tempdir().unwrap();
    let path = root.path().join("legacy");
    let payload = b"authenticated legacy payload";
    std::fs::write(&path, payload).unwrap();
    let mut permissions = std::fs::metadata(&path).unwrap().permissions();
    permissions.set_readonly(true);
    std::fs::set_permissions(&path, permissions).unwrap();
    let stable = StableDirectory::open(root.path()).unwrap();
    let expected = path_identity(&path).unwrap();

    let mut adopter = stable
        .open_legacy_cas_child_for_adoption(OsStr::new("legacy"))
        .unwrap();
    let mut authenticated = Vec::new();
    adopter.read_to_end(&mut authenticated).unwrap();
    assert_eq!(authenticated, payload);
    assert!(
        std::fs::OpenOptions::new()
            .write(true)
            .share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
            .open(&path)
            .is_err()
    );

    let adopted = stable
        .adopt_legacy_cas_child(OsStr::new("legacy"), adopter)
        .unwrap();
    assert_eq!(file_identity(&adopted.0).unwrap(), expected);
    assert_eq!(std::fs::read(&path).unwrap(), payload);
    drop(adopted);
    assert!(stable.open_cas_child_file(OsStr::new("legacy")).is_ok());
    assert!(
        std::fs::OpenOptions::new()
            .write(true)
            .share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
            .open(&path)
            .is_err()
    );
}

#[cfg(windows)]
#[test]
fn stable_directory_unlinks_canonical_cas_child_without_unsealing_hard_link() {
    use std::io::Write as _;

    let root = tempfile::tempdir().unwrap();
    let stable = StableDirectory::open(root.path()).unwrap();
    let temporary_path = root.path().join("temporary");
    let installed_path = root.path().join("installed");
    let mut temporary = stable
        .create_cas_child_file(OsStr::new("temporary"))
        .unwrap();
    temporary.write_all(b"sealed").unwrap();
    temporary.sync_all().unwrap();
    let identity = temporary.identity();
    let temporary = stable
        .seal_cas_child_file(OsStr::new("temporary"), temporary)
        .unwrap()
        .into_file();
    assert!(
        stable.open_cas_child_file(OsStr::new("temporary")).is_ok(),
        "a freshly sealed CAS child must pass canonical reopen"
    );
    std::fs::hard_link(&temporary_path, &installed_path).unwrap();
    assert_eq!(path_identity(&installed_path).unwrap(), identity);
    assert!(temporary.metadata().unwrap().permissions().readonly());
    assert!(
        std::fs::metadata(&installed_path)
            .unwrap()
            .permissions()
            .readonly()
    );
    drop(temporary);
    windows::replace_with_owner_only_cas_dacl(&temporary_path).unwrap();
    assert_eq!(path_identity(&temporary_path).unwrap(), identity);

    stable
        .unlink_child_if_identity(OsStr::new("temporary"), identity)
        .unwrap();

    assert!(!temporary_path.exists());
    assert_eq!(std::fs::read(&installed_path).unwrap(), b"sealed");
    assert_eq!(path_identity(&installed_path).unwrap(), identity);
    let installed = File::open(&installed_path).unwrap();
    assert!(installed.metadata().unwrap().permissions().readonly());
    assert_eq!(file_link_count(&installed).unwrap(), 1);
}