use anyhow::anyhow; use crate::compression_engine::{CompressionType, get_compression_engine}; use clap::Command; use std::path::PathBuf; use std::str::FromStr; pub fn mode_get( cmd: &mut Command, args: &crate::Args, ids: &mut Vec, tags: &mut Vec, conn: &mut rusqlite::Connection, data_path: PathBuf, ) -> anyhow::Result<()> { if !ids.is_empty() && !tags.is_empty() { cmd.error(clap::error::ErrorKind::InvalidValue, "Both ID and tags given, you must supply exactly one ID or at least one tag when using --get").exit(); } else if ids.len() > 1 { cmd.error(clap::error::ErrorKind::InvalidValue, "More than one ID given, you must supply exactly one ID or at least one tag when using --get").exit(); } let mut meta: std::collections::HashMap = std::collections::HashMap::new(); for item in args.item.meta.iter() { let item = item.clone(); meta.insert(item.key, item.value); } let item_maybe = match tags.is_empty() && meta.is_empty() { true => match ids.iter().next() { Some(item_id) => crate::db::get_item(conn, *item_id)?, None => crate::db::get_item_last(conn)?, }, false => crate::db::get_item_matching(conn, tags, &meta)?, }; if let Some(item) = item_maybe { let item_id = item.id.ok_or_else(|| anyhow!("Item missing ID"))?; // Validate that item ID is positive to prevent path traversal issues if item_id <= 0 { return Err(anyhow!("Invalid item ID: {}", item_id)); } let mut item_path = data_path.clone(); item_path.push(item_id.to_string()); let compression_type = CompressionType::from_str(&item.compression)?; let compression_engine = get_compression_engine(compression_type)?; compression_engine.cat(item_path.clone())?; Ok(()) } else { Err(anyhow!("Unable to find matching item in database")) } }