mirror of
https://git.proxmox.com/git/proxmox-backup
synced 2025-10-04 15:38:35 +00:00
fix #3699: client: prefer xdg cache directory for tmp files
Adds a helper to create temporal files in XDG_CACHE_HOME. If we cannot create a file there, we fallback to /tmp as before. Note that the temporary files stored by the client might grow arbitrarily in size, making XDG_RUNTIME_DIR a less desirable option. Citing the Arch wiki [1]: > Should not store large files as it may be mounted as a tmpfs. While the cache directory is most often not backed up by an ephemeral FS, using the `O_TMPFILE` flag avoids the need for potential cleanup, e.g. on interruption of a command. As with this flag set the data will be discarded when the last file descriptor is closed. [1] https://wiki.archlinux.org/title/XDG_Base_Directory Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com> [ TL: mention TMPFILE flag for clarity ] Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
2ecdbe9a96
commit
fcccc3dfa5
@ -1,7 +1,6 @@
|
|||||||
use anyhow::{format_err, Error};
|
use anyhow::{format_err, Error};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Seek, SeekFrom, Write};
|
use std::io::{Seek, SeekFrom, Write};
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures::future::AbortHandle;
|
use futures::future::AbortHandle;
|
||||||
@ -141,18 +140,14 @@ impl BackupReader {
|
|||||||
|
|
||||||
/// Download a .blob file
|
/// Download a .blob file
|
||||||
///
|
///
|
||||||
/// This creates a temporary file in /tmp (using O_TMPFILE). The data is verified using
|
/// This creates a temporary file (See [`crate::tools::create_tmp_file`] for
|
||||||
/// the provided manifest.
|
/// details). The data is verified using the provided manifest.
|
||||||
pub async fn download_blob(
|
pub async fn download_blob(
|
||||||
&self,
|
&self,
|
||||||
manifest: &BackupManifest,
|
manifest: &BackupManifest,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<DataBlobReader<'_, File>, Error> {
|
) -> Result<DataBlobReader<'_, File>, Error> {
|
||||||
let mut tmpfile = std::fs::OpenOptions::new()
|
let mut tmpfile = crate::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
self.download(name, &mut tmpfile).await?;
|
self.download(name, &mut tmpfile).await?;
|
||||||
|
|
||||||
@ -167,18 +162,14 @@ impl BackupReader {
|
|||||||
|
|
||||||
/// Download dynamic index file
|
/// Download dynamic index file
|
||||||
///
|
///
|
||||||
/// This creates a temporary file in /tmp (using O_TMPFILE). The index is verified using
|
/// This creates a temporary file (See [`crate::tools::create_tmp_file`] for
|
||||||
/// the provided manifest.
|
/// details). The index is verified using the provided manifest.
|
||||||
pub async fn download_dynamic_index(
|
pub async fn download_dynamic_index(
|
||||||
&self,
|
&self,
|
||||||
manifest: &BackupManifest,
|
manifest: &BackupManifest,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<DynamicIndexReader, Error> {
|
) -> Result<DynamicIndexReader, Error> {
|
||||||
let mut tmpfile = std::fs::OpenOptions::new()
|
let mut tmpfile = crate::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
self.download(name, &mut tmpfile).await?;
|
self.download(name, &mut tmpfile).await?;
|
||||||
|
|
||||||
@ -194,18 +185,14 @@ impl BackupReader {
|
|||||||
|
|
||||||
/// Download fixed index file
|
/// Download fixed index file
|
||||||
///
|
///
|
||||||
/// This creates a temporary file in /tmp (using O_TMPFILE). The index is verified using
|
/// This creates a temporary file (See [`crate::tools::create_tmp_file`] for
|
||||||
/// the provided manifest.
|
/// details). The index is verified using the provided manifest.
|
||||||
pub async fn download_fixed_index(
|
pub async fn download_fixed_index(
|
||||||
&self,
|
&self,
|
||||||
manifest: &BackupManifest,
|
manifest: &BackupManifest,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<FixedIndexReader, Error> {
|
) -> Result<FixedIndexReader, Error> {
|
||||||
let mut tmpfile = std::fs::OpenOptions::new()
|
let mut tmpfile = crate::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
self.download(name, &mut tmpfile).await?;
|
self.download(name, &mut tmpfile).await?;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
|
||||||
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -531,11 +530,7 @@ impl BackupWriter {
|
|||||||
manifest: &BackupManifest,
|
manifest: &BackupManifest,
|
||||||
known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
|
known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
|
||||||
) -> Result<FixedIndexReader, Error> {
|
) -> Result<FixedIndexReader, Error> {
|
||||||
let mut tmpfile = std::fs::OpenOptions::new()
|
let mut tmpfile = crate::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
let param = json!({ "archive-name": archive_name });
|
let param = json!({ "archive-name": archive_name });
|
||||||
self.h2
|
self.h2
|
||||||
@ -570,11 +565,7 @@ impl BackupWriter {
|
|||||||
manifest: &BackupManifest,
|
manifest: &BackupManifest,
|
||||||
known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
|
known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
|
||||||
) -> Result<DynamicIndexReader, Error> {
|
) -> Result<DynamicIndexReader, Error> {
|
||||||
let mut tmpfile = std::fs::OpenOptions::new()
|
let mut tmpfile = crate::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
let param = json!({ "archive-name": archive_name });
|
let param = json!({ "archive-name": archive_name });
|
||||||
self.h2
|
self.h2
|
||||||
|
@ -5,9 +5,11 @@ use std::ffi::OsStr;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
use std::os::unix::io::FromRawFd;
|
use std::os::unix::io::FromRawFd;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Context, Error};
|
use anyhow::{bail, format_err, Context, Error};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
@ -736,3 +738,27 @@ pub async fn pxar_metadata_catalog_lookup<T: Clone + ReadAt>(
|
|||||||
|
|
||||||
Ok(entries)
|
Ok(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a temporary file (with `O_TMPFILE`) in `XDG_CACHE_HOME`. If we
|
||||||
|
/// cannot create the file there it will be created in `/tmp` instead.
|
||||||
|
pub fn create_tmp_file() -> std::io::Result<std::fs::File> {
|
||||||
|
static TMP_PATH: OnceLock<std::path::PathBuf> = OnceLock::new();
|
||||||
|
let tmp_path = TMP_PATH.get_or_init(|| {
|
||||||
|
xdg::BaseDirectories::new()
|
||||||
|
.map(|base| base.get_cache_home())
|
||||||
|
.unwrap_or_else(|_| std::path::PathBuf::from("/tmp"))
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut open_opts_binding = std::fs::OpenOptions::new();
|
||||||
|
let builder = open_opts_binding
|
||||||
|
.write(true)
|
||||||
|
.read(true)
|
||||||
|
.custom_flags(libc::O_TMPFILE);
|
||||||
|
builder.open(tmp_path).or_else(|err| {
|
||||||
|
if tmp_path != std::path::Path::new("/tmp") {
|
||||||
|
builder.open("/tmp")
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
@ -106,11 +105,7 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
|
|||||||
|
|
||||||
let mut reader = BufferedDynamicReader::new(index, chunk_reader);
|
let mut reader = BufferedDynamicReader::new(index, chunk_reader);
|
||||||
|
|
||||||
let mut catalogfile = std::fs::OpenOptions::new()
|
let mut catalogfile = pbs_client::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
std::io::copy(&mut reader, &mut catalogfile)
|
std::io::copy(&mut reader, &mut catalogfile)
|
||||||
.map_err(|err| format_err!("unable to download catalog - {}", err))?;
|
.map_err(|err| format_err!("unable to download catalog - {}", err))?;
|
||||||
@ -198,11 +193,7 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut tmpfile = std::fs::OpenOptions::new()
|
let mut tmpfile = pbs_client::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
let (manifest, _) = client.download_manifest().await?;
|
let (manifest, _) = client.download_manifest().await?;
|
||||||
manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
|
manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
|
||||||
@ -233,11 +224,7 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
|
|||||||
most_used,
|
most_used,
|
||||||
);
|
);
|
||||||
let mut reader = BufferedDynamicReader::new(index, chunk_reader);
|
let mut reader = BufferedDynamicReader::new(index, chunk_reader);
|
||||||
let mut catalogfile = std::fs::OpenOptions::new()
|
let mut catalogfile = pbs_client::tools::create_tmp_file()?;
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.custom_flags(libc::O_TMPFILE)
|
|
||||||
.open("/tmp")?;
|
|
||||||
|
|
||||||
std::io::copy(&mut reader, &mut catalogfile)
|
std::io::copy(&mut reader, &mut catalogfile)
|
||||||
.map_err(|err| format_err!("unable to download catalog - {}", err))?;
|
.map_err(|err| format_err!("unable to download catalog - {}", err))?;
|
||||||
|
Loading…
Reference in New Issue
Block a user