227501c063
we will reuse that later in the client, so we need it somewhere we can use from there Signed-off-by: Dominik Csapak <d.csapak@proxmox.com> [add strongly typed ArchiveEntry and put api code into helpers.rs] Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
61 lines
1.9 KiB
Rust
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, &direntry.attr);
|
|
if let DirEntryAttribute::File { size, mtime } = direntry.attr {
|
|
entry.size = size.into();
|
|
entry.mtime = mtime.into();
|
|
}
|
|
res.push(entry);
|
|
}
|
|
|
|
Ok(res)
|
|
}
|