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

//! Alternate Data Streams Module.
//!
//! Provides NTFS-style alternate data streams (ADS) support. Each file can have
//! multiple named data streams in addition to the primary (unnamed) data stream.
//! Common uses include:
//! - Extended metadata
//! - Thumbnails and previews
//! - Resource forks
//! - Zone identifiers
//! - Version information

extern crate alloc;

mod ops;
mod types;

pub use ops::*;
pub use types::*;

use alloc::string::String;
use alloc::vec::Vec;

/// Alternate Data Streams API
pub struct Streams;

impl Streams {
    /// List all streams for a file
    pub fn list(dataset: &str, object_id: u64) -> Result<Vec<StreamInfo>, StreamError> {
        list_streams(dataset, object_id)
    }

    /// Check if a stream exists
    pub fn exists(dataset: &str, object_id: u64, stream_name: &str) -> Result<bool, StreamError> {
        stream_exists(dataset, object_id, stream_name)
    }

    /// Get stream information
    pub fn info(
        dataset: &str,
        object_id: u64,
        stream_name: &str,
    ) -> Result<StreamInfo, StreamError> {
        get_stream_info(dataset, object_id, stream_name)
    }

    /// Create a new stream
    pub fn create(
        dataset: &str,
        object_id: u64,
        stream_name: &str,
        stream_type: StreamType,
    ) -> Result<(), StreamError> {
        create_stream(dataset, object_id, stream_name, stream_type)
    }

    /// Delete a stream
    pub fn delete(dataset: &str, object_id: u64, stream_name: &str) -> Result<(), StreamError> {
        delete_stream(dataset, object_id, stream_name)
    }

    /// Read stream data
    pub fn read(
        dataset: &str,
        object_id: u64,
        stream_name: &str,
        offset: u64,
        length: usize,
    ) -> Result<Vec<u8>, StreamError> {
        read_stream(dataset, object_id, stream_name, offset, length)
    }

    /// Write stream data
    pub fn write(
        dataset: &str,
        object_id: u64,
        stream_name: &str,
        offset: u64,
        data: &[u8],
    ) -> Result<usize, StreamError> {
        write_stream(dataset, object_id, stream_name, offset, data)
    }

    /// Truncate a stream
    pub fn truncate(
        dataset: &str,
        object_id: u64,
        stream_name: &str,
        length: u64,
    ) -> Result<(), StreamError> {
        truncate_stream(dataset, object_id, stream_name, length)
    }

    /// Rename a stream
    pub fn rename(
        dataset: &str,
        object_id: u64,
        old_name: &str,
        new_name: &str,
    ) -> Result<(), StreamError> {
        rename_stream(dataset, object_id, old_name, new_name)
    }

    /// Copy a stream
    pub fn copy(
        src_dataset: &str,
        src_id: u64,
        src_stream: &str,
        dst_dataset: &str,
        dst_id: u64,
        dst_stream: &str,
    ) -> Result<u64, StreamError> {
        copy_stream(
            src_dataset,
            src_id,
            src_stream,
            dst_dataset,
            dst_id,
            dst_stream,
        )
    }

    /// Get total size of all streams for a file
    pub fn total_size(dataset: &str, object_id: u64) -> Result<u64, StreamError> {
        get_total_stream_size(dataset, object_id)
    }

    /// Parse a path with stream component (e.g., "file.txt:stream_name")
    pub fn parse_path(path: &str) -> ParsedStreamPath {
        parse_stream_path(path)
    }

    /// Build a path with stream component
    pub fn build_path(file_path: &str, stream_name: &str) -> String {
        build_stream_path(file_path, stream_name)
    }
}

/// Well-known stream names
pub mod well_known {
    /// Zone identifier (marks files downloaded from internet)
    pub const ZONE_IDENTIFIER: &str = "Zone.Identifier";
    /// Thumbnail cache
    pub const THUMBNAIL: &str = "Thumbnail";
    /// Icon resource
    pub const ICON: &str = "Icon";
    /// Summary information
    pub const SUMMARY_INFO: &str = "SummaryInformation";
    /// Document summary
    pub const DOC_SUMMARY: &str = "DocumentSummaryInformation";
    /// Encryption metadata
    pub const ENCRYPTED: &str = "Encrypted";
    /// Version history
    pub const VERSION_HISTORY: &str = "VersionHistory";
    /// Resource fork (macOS compatibility)
    pub const RESOURCE_FORK: &str = "ResourceFork";
    /// Extended attributes
    pub const XATTR: &str = "XAttr";
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_path() {
        let parsed = Streams::parse_path("/data/file.txt:stream_name");
        assert_eq!(parsed.file_path, "/data/file.txt");
        assert_eq!(parsed.stream_name.as_deref(), Some("stream_name"));
    }

    #[test]
    fn test_build_path() {
        let path = Streams::build_path("/data/file.txt", "metadata");
        assert_eq!(path, "/data/file.txt:metadata");
    }
}