Skip to content

Commit

Permalink
disable renameat2 invocation for glibc < 2.28
Browse files Browse the repository at this point in the history
  • Loading branch information
Qingping Hou committed Mar 23, 2021
1 parent 421fd8e commit adc2837
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 16 deletions.
3 changes: 3 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ datafusion-ext = ["datafusion", "crossbeam"]
azure = ["azure_core", "azure_storage", "reqwest"]
s3 = ["rusoto_core", "rusoto_credential", "rusoto_s3", "rusoto_sts"]

[build-dependencies]
regex = "1"

[dev-dependencies]
utime = "0.3"
serial_test = "*"
Expand Down
56 changes: 56 additions & 0 deletions rust/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#[cfg(all(target_os = "linux", target_env = "gnu"))]
mod platform_cfg {
// glibc version is taken from std/sys/unix/os.rs
pub fn glibc_version() -> (usize, usize) {
use regex::Regex;
use std::process::Command;

let output = Command::new("ldd")
.args(&["--version"])
.output()
.expect("failed to execute ldd");
let output_str = std::str::from_utf8(&output.stdout).unwrap();

let version_reg = Regex::new(r#"ldd \(.+\) ([0-9]+\.[0-9]+)"#).unwrap();
if let Some(captures) = version_reg.captures(output_str) {
let version_str = captures.get(1).unwrap().as_str();
parse_glibc_version(version_str).unwrap()
} else {
panic!(
"ERROR: failed to detect glibc version. ldd output: {}",
output_str
);
}
}

// Returns Some((major, minor)) if the string is a valid "x.y" version,
// ignoring any extra dot-separated parts. Otherwise return None.
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
match (parsed_ints.next(), parsed_ints.next()) {
(Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
_ => None,
}
}

fn detect_glibc_renameat2() {
let (major, minor) = glibc_version();
if major >= 2 && minor >= 28 {
println!("cargo:rustc-cfg=glibc_renameat2");
}
}

pub fn set() {
detect_glibc_renameat2();
}
}

#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
mod platform_cfg {
pub fn set() {}
}

fn main() {
println!("cargo:rerun-if-changed=build.rs");
platform_cfg::set();
}
38 changes: 22 additions & 16 deletions rust/src/storage/file/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,6 @@ mod imp {
use super::*;
use std::ffi::CString;

#[cfg(target_os = "linux")]
const RENAME_NOREPLACE: libc::c_uint = 1;

#[cfg(target_os = "linux")]
extern "C" {
fn renameat2(
olddirfd: libc::c_int,
oldpath: *const libc::c_char,
newdirfd: libc::c_int,
newpath: *const libc::c_char,
flags: libc::c_uint,
) -> libc::c_int;
}

fn to_c_string(p: &str) -> Result<CString, StorageError> {
CString::new(p).map_err(|e| StorageError::Generic(format!("{}", e)))
}
Expand All @@ -58,10 +44,30 @@ mod imp {
Ok(())
}

#[allow(unused_variables)]
unsafe fn platform_specific_rename(from: *const libc::c_char, to: *const libc::c_char) -> i32 {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
renameat2(libc::AT_FDCWD, from, libc::AT_FDCWD, to, RENAME_NOREPLACE)
if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
cfg_if::cfg_if! {
if #[cfg(glibc_renameat2)] {
const RENAME_NOREPLACE: libc::c_uint = 1;

extern "C" {
fn renameat2(
olddirfd: libc::c_int,
oldpath: *const libc::c_char,
newdirfd: libc::c_int,
newpath: *const libc::c_char,
flags: libc::c_uint,
) -> libc::c_int;
}

renameat2(libc::AT_FDCWD, from, libc::AT_FDCWD, to, RENAME_NOREPLACE)
} else {
// target has old glibc (< 2.28), we would need to invoke syscall manually
unimplemented!()
}
}
} else if #[cfg(target_os = "macos")] {
libc::renamex_np(from, to, libc::RENAME_EXCL)
} else {
Expand Down

0 comments on commit adc2837

Please sign in to comment.