proxmox-backup/src/api2/helpers.rs

61 lines
1.9 KiB
Rust

use std::io::{Read, Seek};
use std::path::PathBuf;
use anyhow::Error;
use futures::stream::TryStreamExt;
use hyper::{Body, Response, StatusCode, header};
use proxmox::http_bail;
use crate::api2::types::ArchiveEntry;
use crate::backup::{CatalogReader, DirEntryAttribute};
pub async fn create_download_response(path: PathBuf) -> Result<Response<Body>, Error> {
let file = match tokio::fs::File::open(path.clone()).await {
Ok(file) => file,
Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => {
http_bail!(NOT_FOUND, "open file {:?} failed - not found", path);
}
Err(err) => http_bail!(BAD_REQUEST, "open file {:?} failed: {}", path, err),
};
let payload = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new())
.map_ok(|bytes| bytes.freeze());
let body = Body::wrap_stream(payload);
// fixme: set other headers ?
Ok(Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, "application/octet-stream")
.body(body)
.unwrap())
}
/// Returns the list of content of the given path
pub fn list_dir_content<R: Read + Seek>(
reader: &mut CatalogReader<R>,
path: &[u8],
) -> Result<Vec<ArchiveEntry>, Error> {
let dir = reader.lookup_recursive(path)?;
let mut res = vec![];
let mut path = path.to_vec();
if !path.is_empty() && path[0] == b'/' {
path.remove(0);
}
for direntry in reader.read_dir(&dir)? {
let mut components = path.clone();
components.push(b'/');
components.extend(&direntry.name);
let mut entry = ArchiveEntry::new(&components, Some(&direntry.attr));
if let DirEntryAttribute::File { size, mtime } = direntry.attr {
entry.size = size.into();
entry.mtime = mtime.into();
}
res.push(entry);
}
Ok(res)
}