78 lines
2.6 KiB
Diff
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
|
|
|