From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: Lukas Wagner <l.wagner@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [pve-devel] [RFC proxmox 2/7] sys: add make_tmp_dir
Date: Tue, 22 Aug 2023 10:39:07 +0200 [thread overview]
Message-ID: <2rcro4k2bheh4vrr74ryju4ptzeiu4yxefhywzpyn3edlue5vf@267yvx3xhomr> (raw)
In-Reply-To: <20230821134444.620021-3-l.wagner@proxmox.com>
On Mon, Aug 21, 2023 at 03:44:39PM +0200, Lukas Wagner wrote:
> 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>
> ---
> proxmox-sys/src/fs/dir.rs | 73 +++++++++++++++++++++++++++++++++++++--
> 1 file changed, 71 insertions(+), 2 deletions(-)
>
> diff --git a/proxmox-sys/src/fs/dir.rs b/proxmox-sys/src/fs/dir.rs
> index 6aee316..72bf1ad 100644
> --- a/proxmox-sys/src/fs/dir.rs
> +++ b/proxmox-sys/src/fs/dir.rs
> @@ -1,6 +1,8 @@
> -use std::ffi::CStr;
> +use std::ffi::{CStr, CString, OsStr};
> +use std::fs::File;
> +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 +10,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.
> @@ -152,6 +156,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 template = CString::new(template.into_os_string().as_bytes())?;
> +
> + let raw_template_buffer = template.into_raw();
^ This might be shorter without going over the `CString` type with just
a `Vec<u8>` with an explicit `.push(0)` without temporarily giving up
ownership for the `mkdtemp` call.
> +
> + let path = unsafe {
> + let raw_returned_buffer = libc::mkdtemp(raw_template_buffer);
> + if raw_returned_buffer.is_null() {
Need to add
let err = io::Error::last_os_error();
as the very first thing you do in this branch.
Never give any external libraries a chance to mess with your
`errno` values before you use them, even `std` ;-)
> + // The returned pointer points to the same buffer, so in case
> + // of an error we need to make sure to claim it back to that
> + // it is freed properly.
> + drop(CString::from_raw(raw_template_buffer));
^ but I think we could avoid this - but as long as you fix up the
`errno` usage the CString code can also just stay this way, no strong
feelings there.
> + return Err(std::io::Error::last_os_error().into());
> + }
> + CString::from_raw(raw_returned_buffer)
> + };
> +
> + let path = OsStr::from_bytes(path.as_bytes());
> + let path = PathBuf::from(path);
^ This seems like there should be a cheap non-copying version:
PathBuf::from(OsString::from_vec(path.into_bytes())) ?
> +
> + if let Some(options) = options {
> + if let Err(err) = try_block!({
> + let fd = crate::fd::open(&path, OFlag::O_DIRECTORY, stat::Mode::empty())?;
> + let mut file = File::from(fd);
> + options.apply_to(&mut file, &path)?;
^ Huh, just noticing this weirdness, can we fix up the apply_to API to
take a `RawFd` or `&BorrowedFd` instead of a `File`? This is... not a
file... :-) And also `CreateOptions` doesn't really need it to be
mutable ;-)
> + Ok::<(), Error>(())
> + }) {
> + let _ = unistd::unlink(&path);
^ This calls `unlink(2)` which does not remove directories. You need to
use either `std::fs::remove_dir()` or `unlinkat` with
`UnlinkatFlags::RemoveDir`.
Also, please also log the error if this fails.
> + bail!("could not apply create options to new temporary directory: {err}");
> + }
> + }
> +
> + Ok(path)
> +}
> +
> #[cfg(test)]
> mod tests {
> use super::*;
> @@ -169,4 +221,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-08-22 8:39 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-21 13:44 [pve-devel] [RFC storage/proxmox{, -perl-rs} 0/7] cache storage plugin status for pvestatd/API status update calls Lukas Wagner
2023-08-21 13:44 ` [pve-devel] [RFC proxmox 1/7] sys: fs: move tests to a sub-module Lukas Wagner
2023-08-30 15:38 ` [pve-devel] applied: " Thomas Lamprecht
2023-08-21 13:44 ` [pve-devel] [RFC proxmox 2/7] sys: add make_tmp_dir Lukas Wagner
2023-08-22 8:39 ` Wolfgang Bumiller [this message]
2023-08-21 13:44 ` [pve-devel] [RFC proxmox 3/7] sys: fs: remove unnecessary clippy allow directive Lukas Wagner
2023-08-21 13:44 ` [pve-devel] [RFC proxmox 4/7] cache: add new crate 'proxmox-cache' Lukas Wagner
2023-08-22 10:08 ` Max Carrara
2023-08-22 11:33 ` Lukas Wagner
2023-08-22 12:01 ` Wolfgang Bumiller
2023-08-22 11:56 ` Wolfgang Bumiller
2023-08-22 13:52 ` Max Carrara
2023-08-21 13:44 ` [pve-devel] [RFC proxmox 5/7] cache: add debian packaging Lukas Wagner
2023-08-21 13:44 ` [pve-devel] [RFC proxmox-perl-rs 6/7] cache: add bindings for `SharedCache` from `proxmox-cache` Lukas Wagner
2023-08-21 13:44 ` [pve-devel] [RFC pve-storage 7/7] stats: api: cache storage plugin status Lukas Wagner
2023-08-22 8:51 ` Lukas Wagner
2023-08-22 9:17 ` [pve-devel] [RFC storage/proxmox{, -perl-rs} 0/7] cache storage plugin status for pvestatd/API status update calls Fiona Ebner
2023-08-22 11:25 ` Wolfgang Bumiller
2023-08-30 17:07 ` Wolf Noble
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=2rcro4k2bheh4vrr74ryju4ptzeiu4yxefhywzpyn3edlue5vf@267yvx3xhomr \
--to=w.bumiller@proxmox.com \
--cc=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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox