agama/rust/agama-transfer/src/lib.rs
2026-02-20 10:17:01 +00:00

97 lines
3.4 KiB
Rust

// Copyright (c) [2025] SUSE LLC
//
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, contact SUSE LLC.
//
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.
//! File transfer API for Agama.
//!
//! Implement a file transfer API which, at this point, partially supports Agama specific URLs. Check the
//! YaST document about [URL handling in the
//! installer](https://github.com/yast/yast-installation/blob/master/doc/url.md) for further
//! information.
//!
//! This API supports the following URLs from YaST: `device:`, `usb:`, `label:`, ! `hd:`, `dvd:` and
//! `cd:`. The support for well-known URLs (e.g., `file:`, `http:`, `https:`, ! `ftp:`, `nfs:`,
//! etc.) is implemented using CURL.
//!
//! ## SSL
//!
//! YaST support for HTTPS used a custom certificate which was located in
//! `/etc/sssl/clientcerts/client-cert.pem`. Agama does not use such a certificate and it only
//! relies on those that are installed in the installation media.
//!
//! ## Examples
//! Requires working localectl.
//!
//! ```no_run
//! use agama_transfer::Transfer;
//! Transfer::get("label://OEMDRV/autoinst.xml", &mut std::io::stdout(), false).unwrap();
//! ````
use std::io::Write;
use url::Url;
mod file_finder;
mod file_systems;
mod handlers;
use handlers::{DeviceHandler, GenericHandler, HdHandler, LabelHandler};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Could not retrieve the file")]
CurlError(#[from] curl::Error),
#[error("Could not retrieve '{0}'")]
CurlTransferError(String, #[source] curl::Error),
#[error("Could not parse the URL {0}")]
ParseError(String, #[source] url::ParseError),
#[error("File not found '{0}'")]
FileNotFound(String),
#[error("IO error: {0}")]
IO(#[from] std::io::Error),
#[error("Could not mount the file system {0}")]
FileSystemMount(String),
#[error("Missing file path '{0}'")]
MissingPath(Url),
#[error("Missing device '{0}'")]
MissingDevice(Url),
#[error("Missing file system label '{0}'")]
MissingLabel(Url),
}
pub type TransferResult<T> = Result<T, Error>;
/// File transfer API
pub struct Transfer {}
impl Transfer {
/// Retrieves and writes the data from an URL
///
/// * `url`: URL to get the data from.
/// * `out_fd`: where to write the data.
/// * `insecure`: ignore SSL problems in HTTPS downloads.
pub fn get(url: &str, out_fd: &mut impl Write, insecure: bool) -> TransferResult<()> {
let url = Url::parse(url).map_err(|e| Error::ParseError(url.to_string(), e))?;
match url.scheme() {
"device" | "usb" => DeviceHandler::default().get(url, out_fd),
"label" => LabelHandler::default().get(url, out_fd),
"cd" | "dvd" | "hd" => HdHandler::default().get(url, out_fd),
_ => GenericHandler::default().get(url, out_fd, insecure),
}
}
}