monochromatic-git-policy-cli 0.5.31

Repository-owned Git policy wrapper: forwards Git commands and checks commits against configured policies.
Documentation
//! What:
//!  A file's identity at the moment it was judged: the removal checks that it is still that file.
//! Why:
//!  A freed inode number may be handed to the next file created at once, so device and inode alone cannot tell the judged
//!  lock from a new lock a live Git made at the same path; the size, birth time and modification time are compared too.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! type Identity = { device: bigint; inode: bigint; size: number; bornNs?: bigint; modifiedNs: bigint };
//! ```

use std::os::unix::fs::MetadataExt;
use std::path::Path;
use std::time::SystemTime;

/// A lock's identity at the moment it was judged: the removal checks that it is still this file.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Identity {
    /// Device number.
    pub device: u64,
    /// Inode number; a freed inode may be reused at once, so it is never compared alone.
    pub inode: u64,
    /// Size in bytes.
    pub size: u64,
    /// Birth time in nanoseconds since the epoch, where the file system keeps it.
    pub born_ns: Option<u128>,
    /// Modification time in nanoseconds since the epoch.
    pub modified_ns: i128,
}

/// The identity of the file at `path`, without following a link.
pub fn identity_of(path: &Path) -> Option<Identity> {
    let metadata: std::fs::Metadata = std::fs::symlink_metadata(path).ok()?;
    let born_ns: Option<u128> = metadata
        .created()
        .ok()
        .and_then(|born| { return born.duration_since(SystemTime::UNIX_EPOCH).ok(); })
        .map(|elapsed| { return elapsed.as_nanos(); });
    let modified_ns: i128 = i128::from(metadata.mtime()) * 1_000_000_000 + i128::from(metadata.mtime_nsec());
    return Some(Identity { device: metadata.dev(), inode: metadata.ino(), size: metadata.len(), born_ns, modified_ns });
}