sysmaster/backport-fix-libbasic-create-symlink-atomically.patch
huyubiao 8936fa02c5 sync patches from upstream,change the path of the unit,modify permissions for some directories and files
(cherry picked from commit ce9ff469b57f60130621bc293783bd3ac1fc92f2)
2023-08-05 18:15:53 +08:00

78 lines
2.6 KiB
Diff

From 58774990868761750874fc8c21af0ccabefb1e53 Mon Sep 17 00:00:00 2001
From: chenjiayi <chenjiayi22@huawei.com>
Date: Wed, 21 Jun 2023 23:43:12 +0800
Subject: [PATCH] fix(libbasic): create symlink atomically
Create a temporary symlink and rename it into the final symlink.
If there exists a symlink with the same name already, the symlink
will be overrided. If any error occurs, the original symlink will
be reserved.
---
libs/basic/Cargo.toml | 1 +
libs/basic/src/fs_util.rs | 20 ++++++++++++++++----
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/libs/basic/Cargo.toml b/libs/basic/Cargo.toml
index 64fbfba..7557d37 100644
--- a/libs/basic/Cargo.toml
+++ b/libs/basic/Cargo.toml
@@ -20,6 +20,7 @@ caps = "0.5.5"
lazy_static = "1.4.0"
bitflags = "1.3.2"
pkg-config = "0.3"
+rand = "0.4.6"
[dev-dependencies]
libtests = { path = "../libtests" }
diff --git a/libs/basic/src/fs_util.rs b/libs/basic/src/fs_util.rs
index 5f34e9a..6a6378d 100644
--- a/libs/basic/src/fs_util.rs
+++ b/libs/basic/src/fs_util.rs
@@ -15,11 +15,12 @@
use crate::{error::*, format_proc_fd_path};
use libc::{fchownat, mode_t, timespec, AT_EMPTY_PATH, S_IFLNK, S_IFMT};
use nix::{
- fcntl::OFlag,
+ fcntl::{renameat, OFlag},
sys::stat::{fstat, Mode},
- unistd::{Gid, Uid},
+ unistd::{unlinkat, Gid, Uid, UnlinkatFlags},
};
use pathdiff::diff_paths;
+use rand::Rng;
use std::{fs::remove_dir, io::ErrorKind, os::unix::prelude::PermissionsExt, path::Path};
/// open the parent directory of path
@@ -36,7 +37,7 @@ pub fn symlink(target: &str, link: &str, relative: bool) -> Result<()> {
let link_path = Path::new(&link);
let target_path = Path::new(&target);
- let (target_path, fd) = if relative {
+ let (target_path, dirfd) = if relative {
let link_path_parent = link_path.parent().ok_or(Error::NotExisted {
what: format!("{}'s parent", link_path.to_string_lossy()),
})?;
@@ -53,7 +54,18 @@ pub fn symlink(target: &str, link: &str, relative: bool) -> Result<()> {
(target_path.to_path_buf(), None)
};
- nix::unistd::symlinkat(target_path.as_path(), fd, link_path).context(NixSnafu)
+ let mut rng = rand::thread_rng();
+
+ let tmp_to = format!("{}.{}", link, rng.gen::<u32>());
+
+ nix::unistd::symlinkat(target_path.as_path(), dirfd, tmp_to.as_str()).context(NixSnafu)?;
+
+ if let Err(e) = renameat(dirfd, tmp_to.as_str(), dirfd, link_path) {
+ let _ = unlinkat(dirfd, tmp_to.as_str(), UnlinkatFlags::NoRemoveDir);
+ return Err(Error::Nix { source: e });
+ }
+
+ Ok(())
}
/// chmod based on fd opened with O_PATH
--
2.33.0