magi-code 0.96.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::*;
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub(super) fn rename_noreplace(parent: &CapDir, source: &OsStr, target: &OsStr) -> io::Result<()> {
    use std::{
        ffi::CString,
        os::{fd::AsRawFd, unix::ffi::OsStrExt},
    };

    let source_c = CString::new(source.as_bytes())
        .map_err(|_| io::Error::new(ErrorKind::InvalidInput, "rename source contains NUL"))?;
    let target_c = CString::new(target.as_bytes())
        .map_err(|_| io::Error::new(ErrorKind::InvalidInput, "rename target contains NUL"))?;
    #[cfg(target_os = "linux")]
    {
        // SAFETY: `parent` is a live held capability directory. The two
        // `CString`s contain NUL-terminated relative names and remain alive
        // for the duration of this syscall; the raw fd is only borrowed.
        let result = unsafe {
            libc::renameat2(
                parent.as_raw_fd(),
                source_c.as_ptr(),
                parent.as_raw_fd(),
                target_c.as_ptr(),
                libc::RENAME_NOREPLACE,
            )
        };
        if result == 0 {
            Ok(())
        } else {
            Err(io::Error::last_os_error())
        }
    }
    #[cfg(target_os = "macos")]
    {
        // SAFETY: `parent` is a live held capability directory. The two
        // `CString`s contain NUL-terminated relative names and remain alive
        // for the duration of this syscall; the raw fd is only borrowed.
        let result = unsafe {
            libc::renameatx_np(
                parent.as_raw_fd(),
                source_c.as_ptr(),
                parent.as_raw_fd(),
                target_c.as_ptr(),
                libc::RENAME_EXCL,
            )
        };
        if result == 0 {
            Ok(())
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
pub(super) fn rename_noreplace(parent: &CapDir, source: &OsStr, target: &OsStr) -> io::Result<()> {
    let _ = (parent, source, target);
    Err(io::Error::new(
        ErrorKind::Unsupported,
        "atomic no-replace rename is unsupported on this platform",
    ))
}

pub(super) fn open_rewind_root(cwd: &Path) -> (PathBuf, Option<CapDir>) {
    let canonical_cwd = cwd
        .canonicalize()
        .unwrap_or_else(|_| lexical_normalize(cwd));
    let root = CapDir::open_ambient_dir(&canonical_cwd, ambient_authority()).ok();
    (canonical_cwd, root)
}

#[derive(Debug)]
pub(super) struct RewindTarget {
    pub(super) parent: CapDir,
    pub(super) name: OsString,
}

#[derive(Debug)]
pub(super) struct TargetSnapshot {
    pub(super) hash: String,
    #[cfg(unix)]
    pub(super) mode: u32,
}

pub(super) fn open_target_parent(
    root: &CapDir,
    relative_path: &Path,
    create_missing: bool,
    inject_ancestor_sync_failure: bool,
) -> io::Result<RewindTarget> {
    let mut components = Vec::new();
    for component in relative_path.components() {
        match component {
            Component::Normal(name) => components.push(name),
            Component::CurDir => {}
            Component::ParentDir | Component::Prefix(_) | Component::RootDir => {
                return Err(io::Error::new(
                    ErrorKind::InvalidInput,
                    "unsafe rewind target path",
                ));
            }
        }
    }
    let name = components
        .pop()
        .ok_or_else(|| io::Error::new(ErrorKind::InvalidInput, "rewind target has no name"))?;
    let mut parent = root.try_clone()?;
    for component in components {
        parent = open_parent_component(
            &parent,
            component,
            create_missing,
            inject_ancestor_sync_failure,
        )?;
    }
    Ok(RewindTarget {
        parent,
        name: name.to_os_string(),
    })
}

fn open_parent_component(
    parent: &CapDir,
    name: &OsStr,
    create_missing: bool,
    inject_ancestor_sync_failure: bool,
) -> io::Result<CapDir> {
    let component = Path::new(name);
    match parent.symlink_metadata(component) {
        Ok(metadata) => {
            if metadata.is_symlink() || !metadata.is_dir() {
                return Err(io::Error::new(
                    ErrorKind::InvalidInput,
                    "rewind target parent is not a safe directory",
                ));
            }
            parent.open_dir_nofollow(component)
        }
        Err(error) if error.kind() == ErrorKind::NotFound && create_missing => {
            let created = match parent.create_dir(component) {
                Ok(()) => true,
                Err(error) if error.kind() == ErrorKind::AlreadyExists => false,
                Err(error) => return Err(error),
            };
            if created {
                let sync_result = if inject_ancestor_sync_failure {
                    Err(io::Error::other("injected ancestor directory sync failure"))
                } else {
                    sync_capability_directory(parent)
                };
                if let Err(error) = sync_result {
                    // This directory is still empty unless an external actor raced us.
                    // `remove_dir` is deliberately non-recursive; never remove someone
                    // else's contents during rollback.
                    let _ = parent.remove_dir(component);
                    return Err(error);
                }
            }
            parent.open_dir_nofollow(component)
        }
        Err(error) => Err(error),
    }
}

pub(super) fn target_snapshot(target: &RewindTarget) -> io::Result<Option<TargetSnapshot>> {
    snapshot_named(&target.parent, &target.name)
}

pub(super) fn snapshot_named(parent: &CapDir, name: &OsStr) -> io::Result<Option<TargetSnapshot>> {
    let metadata = match parent.symlink_metadata(name) {
        Ok(metadata) => metadata,
        Err(error) if error.kind() == ErrorKind::NotFound => return Ok(None),
        Err(error) => return Err(error),
    };
    if metadata.is_symlink() {
        return Err(io::Error::new(
            ErrorKind::InvalidInput,
            "rewind target is a symlink",
        ));
    }
    if !metadata.is_file() {
        return Err(io::Error::new(
            ErrorKind::InvalidInput,
            "rewind target is not a regular file",
        ));
    }

    let mut options = CapOpenOptions::new();
    options.read(true).follow(FollowSymlinks::No);
    let mut file = match parent.open_with(name, &options) {
        Ok(file) => file,
        Err(error) if error.kind() == ErrorKind::NotFound => return Ok(None),
        Err(error) => return Err(error),
    };
    let metadata = file.metadata()?;
    if metadata.is_symlink() || !metadata.is_file() {
        return Err(io::Error::new(
            ErrorKind::InvalidInput,
            "rewind target is not a regular file",
        ));
    }
    let mut bytes = Vec::new();
    file.read_to_end(&mut bytes)?;
    #[cfg(unix)]
    let mode = metadata.permissions().mode() & 0o777;
    Ok(Some(TargetSnapshot {
        hash: sha256_hex(&bytes),
        #[cfg(unix)]
        mode,
    }))
}

pub(super) fn target_snapshot_for_plan(
    root: &CapDir,
    relative_path: &Path,
    missing_parent_is_missing: bool,
) -> anyhow::Result<Option<TargetSnapshot>> {
    let target = match open_target_parent(root, relative_path, false, false) {
        Ok(target) => target,
        Err(error) if missing_parent_is_missing && error.kind() == ErrorKind::NotFound => {
            return Ok(None);
        }
        Err(error) => return Err(error.into()),
    };
    Ok(target_snapshot(&target)?)
}

pub(super) fn target_mode(snapshot: &TargetSnapshot) -> Option<u32> {
    #[cfg(unix)]
    {
        Some(snapshot.mode)
    }
    #[cfg(not(unix))]
    {
        let _ = snapshot;
        None
    }
}

pub(super) fn reject_final_symlink(parent: &CapDir, name: &OsStr) -> io::Result<()> {
    match parent.symlink_metadata(Path::new(name)) {
        Ok(metadata) if metadata.is_symlink() => Err(io::Error::new(
            ErrorKind::InvalidInput,
            "rewind target is a symlink",
        )),
        Ok(_) => Ok(()),
        Err(error) if error.kind() == ErrorKind::NotFound => Ok(()),
        Err(error) => Err(error),
    }
}

pub(super) fn sync_capability_directory(directory: &CapDir) -> io::Result<()> {
    #[cfg(unix)]
    {
        directory.try_clone()?.into_std_file().sync_all()
    }
    #[cfg(not(unix))]
    {
        let _ = directory;
        Ok(())
    }
}