From: Lukas Wagner <l.wagner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v2 proxmox 4/7] sys: add make_tmp_dir
Date: Thu, 28 Sep 2023 13:50:09 +0200 [thread overview]
Message-ID: <20230928115012.326777-5-l.wagner@proxmox.com> (raw)
In-Reply-To: <20230928115012.326777-1-l.wagner@proxmox.com>
Under the hood, this function calls `mkdtemp` from libc. Unfortunatly
the nix crate did not provide bindings for this function, so we have
to call into libc directly.
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
Notes:
Changes from v1 -> v2:
- Use remove_dir instead of unlink
- Log error if cleaning up dir did not work
- Change how the tmp dir path is passed to mkdtemp, retaining
ownership at all time.
- Check for os_error immediately after calling mkdtemp
proxmox-sys/src/fs/dir.rs | 72 +++++++++++++++++++++++++++++++++++++--
1 file changed, 70 insertions(+), 2 deletions(-)
diff --git a/proxmox-sys/src/fs/dir.rs b/proxmox-sys/src/fs/dir.rs
index 0b409d7..2ef5e2e 100644
--- a/proxmox-sys/src/fs/dir.rs
+++ b/proxmox-sys/src/fs/dir.rs
@@ -1,6 +1,7 @@
-use std::ffi::CStr;
+use std::ffi::{CStr, OsStr};
+use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{AsRawFd, OwnedFd};
-use std::path::Path;
+use std::path::{Path, PathBuf};
use anyhow::{bail, Error};
use nix::errno::Errno;
@@ -8,6 +9,8 @@ use nix::fcntl::OFlag;
use nix::sys::stat;
use nix::unistd;
+use proxmox_lang::try_block;
+
use crate::fs::{fchown, CreateOptions};
/// Creates directory at the provided path with specified ownership.
@@ -148,6 +151,54 @@ fn create_path_at_do(
}
}
+/// Create a temporary directory.
+///
+/// `prefix` determines where the temporary directory will be created. For instance, if
+/// `prefix` is `/tmp`, on success the function will return a path in the style of
+/// `/tmp/tmp_XXXXXX`, where X stands for a random string, ensuring that the path is unique.
+///
+/// By default, the created directory has `0o700` permissions. If this is not desired, custom
+/// [`CreateOptions`] can be passed via the `option` parameter.
+pub fn make_tmp_dir<P: AsRef<Path>>(
+ prefix: P,
+ options: Option<CreateOptions>,
+) -> Result<PathBuf, Error> {
+ let mut template = prefix.as_ref().to_owned();
+ template = template.join("tmp_XXXXXX");
+
+ let mut template = template.into_os_string().as_bytes().to_owned();
+ // Push NULL byte so that we have a proper NULL-terminated string
+ template.push(0);
+
+ let returned_buffer = unsafe {
+ let raw_buffer: *mut i8 = std::mem::transmute(template.as_mut_ptr());
+ libc::mkdtemp(raw_buffer)
+ };
+
+ // Check errno immediately, so that nothing else can overwrite it.
+ let err = std::io::Error::last_os_error();
+
+ if returned_buffer.is_null() {
+ return Err(err.into());
+ }
+ let path = PathBuf::from(OsStr::from_bytes(&template[..template.len() - 1]));
+
+ if let Some(options) = options {
+ if let Err(err) = try_block!({
+ let fd = crate::fd::open(&path, OFlag::O_DIRECTORY, stat::Mode::empty())?;
+ options.apply_to(fd.as_raw_fd(), &path)?;
+ Ok::<(), Error>(())
+ }) {
+ if let Err(err) = std::fs::remove_dir(&path) {
+ log::error!("could not clean up temporary directory at {path:?}: {err}")
+ }
+ bail!("could not apply create options to new temporary directory: {err}");
+ }
+ }
+
+ Ok(path)
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -165,4 +216,21 @@ mod tests {
)
.expect("expected create_path to work");
}
+
+ #[test]
+ fn test_make_tmp_dir() -> Result<(), Error> {
+ let options = CreateOptions::new()
+ .owner(unistd::Uid::effective())
+ .group(unistd::Gid::effective())
+ .perm(stat::Mode::from_bits_truncate(0o755));
+
+ let path = make_tmp_dir("/tmp", Some(options))?;
+
+ assert!(path.exists());
+ assert!(path.is_dir());
+
+ std::fs::remove_dir_all(&path)?;
+
+ Ok(())
+ }
}
--
2.39.2
next prev parent reply other threads:[~2023-09-28 11:50 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-28 11:50 [pve-devel] [PATCH v2 storage/proxmox{, -perl-rs} 0/7] cache storage plugin status for pvestatd/API status update calls Lukas Wagner
2023-09-28 11:50 ` [pve-devel] [PATCH v2 proxmox 1/7] sys: fs: remove unnecessary clippy allow directive Lukas Wagner
2023-09-28 11:50 ` [pve-devel] [PATCH v2 proxmox 2/7] sys: fs: let CreateOptions::apply_to take RawFd instead of File Lukas Wagner
2023-09-28 11:50 ` [pve-devel] [PATCH v2 proxmox 3/7] sys: fs: use inline formatting for bail! macro Lukas Wagner
2023-09-28 11:50 ` Lukas Wagner [this message]
2023-09-28 11:50 ` [pve-devel] [PATCH v2 proxmox 5/7] cache: add new crate 'proxmox-shared-cache' Lukas Wagner
2023-09-28 11:50 ` [pve-devel] [PATCH v2 proxmox-perl-rs 6/7] cache: add bindings for `SharedCache` Lukas Wagner
2023-09-28 11:50 ` [pve-devel] [PATCH v2 pve-storage 7/7] stats: api: cache storage plugin status Lukas Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230928115012.326777-5-l.wagner@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.