exclude_from_backups 1.1.0

Mark files or directories as excluded from backups (for Time Machine on macOS). Can be used to prevent caches and temporary files from bloating backups. Includes both a library interface and a basic command-line executable.
Documentation
use core_foundation as cf;

use self::cf::base::TCFType;
use crate::error::Error;
use crate::error::Error::{IncompatiblePathCharset, SystemCallFailed};
use std::path::Path;
use std::ptr;

pub fn exclude_from_backups<P: AsRef<Path>>(path: P) -> Result<(), Error> {
    let url = cf::url::CFURL::from_path(path, false).ok_or(IncompatiblePathCharset)?;
    unsafe {
        let mut err = ptr::null_mut();
        cf::url::CFURLSetResourcePropertyForKey(
            url.as_concrete_TypeRef(),
            cf::url::kCFURLIsExcludedFromBackupKey,
            cf::number::kCFBooleanTrue.cast(),
            &mut err,
        );

        if !err.is_null() {
            let err: cf::error::CFError = TCFType::wrap_under_create_rule(err);
            return Err(SystemCallFailed(err.to_string().into()));
        }
    }
    Ok(())
}

#[test]
fn test_excluding() {
    use std::fs;
    use std::process::Command;

    let path = Path::new("/tmp/exclude_from_backups_test_dir");
    if !path.exists() {
        fs::create_dir(path).unwrap();
    }
    exclude_from_backups(path).unwrap();

    let out = Command::new("xattr")
        .arg("-p")
        .arg("com.apple.metadata:com_apple_backup_excludeItem")
        .arg(path)
        .output()
        .unwrap();
    assert!(out.status.success());

    let _ = fs::remove_dir_all(path);
}