lcpfs 2026.1.102

LCP File System - A ZFS-inspired copy-on-write filesystem for Rust
// Copyright 2025 LunaOS Contributors
// SPDX-License-Identifier: Apache-2.0

//! # LunAr Archives
//!
//! Native archive support (ZIP, TAR) with real LZ4 compression.
//!
//! ## Overview
//!
//! This module provides transparent access to archive contents as if they
//! were regular directories, allowing reading and writing files inside
//! archives without manual extraction.
//!
//! ## Supported Formats
//!
//! - **ZIP** (read/write with LZ4 compression)
//! - **TAR** (read/write)
//! - **TAR.LZ4** (read/write with LZ4 compression)
//!
//! ## Compression
//!
//! All archives use LZ4 compression for optimal performance in no_std environments:
//! - ZIP files use LZ4 instead of DEFLATE for faster compression/decompression
//! - TAR.LZ4 provides whole-archive compression
//! - CRC32 checksums ensure data integrity
//!
//! ## Example
//!
//! ```rust,ignore
//! use lcpfs::archive::{create_zip, parse_zip, extract_file};
//!
//! // Create a ZIP archive with compression
//! let files = [
//!     ("hello.txt", b"Hello, World!".as_slice()),
//!     ("data.bin", &[0u8, 1, 2, 3, 4, 5]),
//! ];
//! let archive = create_zip(&files)?;
//!
//! // Parse and extract
//! let entries = parse_zip(&archive)?;
//! let data = extract_file(&archive, entries.get("hello.txt").unwrap())?;
//! ```

mod detect;
mod mount;
mod tar;
mod types;
mod zip;

pub use detect::*;
pub use mount::*;
pub use types::*;

// Explicit exports from tar to avoid ambiguity with zip
pub use tar::{
    TarHeader, TarType, compression_stats, create_tar, create_tar_lz4, extract_all_lz4, parse_tar,
    parse_tar_directory, parse_tar_lz4,
};

// Explicit exports from zip
pub use zip::{
    add_to_archive, create_zip, extract_all, extract_archive, extract_file, parse_zip,
    parse_zip_directory,
};

use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use spin::Mutex;

lazy_static! {
    /// Cache of open archives
    static ref ARCHIVE_CACHE: Mutex<BTreeMap<String, ArchiveMount>> = Mutex::new(BTreeMap::new());
}

/// Archive interface
pub struct Archive;

impl Archive {
    /// Open an archive file
    pub fn open(path: &str) -> Result<ArchiveMount, ArchiveError> {
        ArchiveMount::open(path)
    }

    /// Check if a path is an archive
    pub fn is_archive(path: &str) -> bool {
        detect_archive_type(path).is_some()
    }

    /// Get archive type from path
    pub fn archive_type(path: &str) -> Option<ArchiveType> {
        detect_archive_type(path)
    }

    /// Create a new archive
    pub fn create(path: &str, archive_type: ArchiveType) -> Result<ArchiveMount, ArchiveError> {
        ArchiveMount::create(path, archive_type)
    }

    /// Extract archive from bytes to a target directory
    ///
    /// In `no_std`, we can't read files from paths directly.
    /// The archive_data should contain the raw archive bytes.
    pub fn extract(archive_data: &[u8], target_dir: &str) -> Result<ExtractResult, ArchiveError> {
        extract_archive(archive_data, target_dir)
    }

    /// Add files to an archive
    pub fn add_files(archive_path: &str, files: &[(&str, &[u8])]) -> Result<Vec<u8>, ArchiveError> {
        add_to_archive(archive_path, files)
    }
}