Skip to content

Commit cb5b893

Browse files
committed
enhanced renameat2 to support raw syscalls
- replace libc::renameat2() with libc::syscall() for broader compatibility - define syscall numbers manually for multiple architectures - update conditional compilation to support all Linux environments - expand test coverage for additional architectures
1 parent a72936d commit cb5b893

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

src/fcntl.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -444,22 +444,24 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath, Fd1: std::os::fd::As
444444
}
445445
}
446446

447-
#[cfg(all(target_os = "linux", target_env = "gnu"))]
447+
#[cfg(target_os = "linux")]
448448
#[cfg(feature = "fs")]
449-
libc_bitflags! {
449+
bitflags::bitflags! {
450450
/// Flags for use with [`renameat2`].
451451
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
452+
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
453+
#[repr(transparent)]
452454
pub struct RenameFlags: u32 {
453455
/// Atomically exchange `old_path` and `new_path`.
454-
RENAME_EXCHANGE;
456+
const RENAME_EXCHANGE = 1 << 1;
455457
/// Don't overwrite `new_path` of the rename. Return an error if `new_path` already
456458
/// exists.
457-
RENAME_NOREPLACE;
459+
const RENAME_NOREPLACE = 1 << 0;
458460
/// creates a "whiteout" object at the source of the rename at the same time as performing
459461
/// the rename.
460462
///
461463
/// This operation makes sense only for overlay/union filesystem implementations.
462-
RENAME_WHITEOUT;
464+
const RENAME_WHITEOUT = 1 << 2;
463465
}
464466
}
465467

@@ -471,7 +473,7 @@ feature! {
471473
///
472474
/// # See Also
473475
/// * [`rename`](https://man7.org/linux/man-pages/man2/rename.2.html)
474-
#[cfg(all(target_os = "linux", target_env = "gnu"))]
476+
#[cfg(target_os = "linux")]
475477
pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath, Fd1: std::os::fd::AsFd, Fd2: std::os::fd::AsFd>(
476478
old_dirfd: Fd1,
477479
old_path: &P1,
@@ -483,7 +485,25 @@ pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath, Fd1: std::os::fd::A
483485

484486
let res = old_path.with_nix_path(|old_cstr| {
485487
new_path.with_nix_path(|new_cstr| unsafe {
486-
libc::renameat2(
488+
// Use raw syscall instead of libc::renameat2 to support musl libc and other
489+
// environments where the libc function may not be available.
490+
//
491+
// Syscall numbers from the Linux kernel source:
492+
// https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl
493+
// https://github.com/torvalds/linux/blob/master/arch/arm64/include/asm/unistd32.h
494+
#[cfg(target_arch = "x86_64")]
495+
const SYS_RENAMEAT2: libc::c_long = 316;
496+
#[cfg(target_arch = "x86")]
497+
const SYS_RENAMEAT2: libc::c_long = 353;
498+
#[cfg(target_arch = "aarch64")]
499+
const SYS_RENAMEAT2: libc::c_long = 276;
500+
#[cfg(target_arch = "arm")]
501+
const SYS_RENAMEAT2: libc::c_long = 382;
502+
#[cfg(target_arch = "riscv64")]
503+
const SYS_RENAMEAT2: libc::c_long = 276;
504+
505+
libc::syscall(
506+
SYS_RENAMEAT2,
487507
old_dirfd.as_fd().as_raw_fd(),
488508
old_cstr.as_ptr(),
489509
new_dirfd.as_fd().as_raw_fd(),
@@ -492,7 +512,7 @@ pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath, Fd1: std::os::fd::A
492512
)
493513
})
494514
})??;
495-
Errno::result(res).map(drop)
515+
Errno::result(res as c_int).map(drop)
496516
}
497517

498518
fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> {

test/test_fcntl.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ use nix::fcntl::{openat2, OpenHow, ResolveFlag};
1010

1111
#[cfg(all(
1212
target_os = "linux",
13-
target_env = "gnu",
1413
any(
1514
target_arch = "x86_64",
15+
target_arch = "x86",
16+
target_arch = "aarch64",
17+
target_arch = "arm",
18+
target_arch = "riscv64",
1619
target_arch = "powerpc",
1720
target_arch = "s390x"
1821
)
@@ -134,9 +137,12 @@ fn test_renameat() {
134137
#[test]
135138
#[cfg(all(
136139
target_os = "linux",
137-
target_env = "gnu",
138140
any(
139141
target_arch = "x86_64",
142+
target_arch = "x86",
143+
target_arch = "aarch64",
144+
target_arch = "arm",
145+
target_arch = "riscv64",
140146
target_arch = "powerpc",
141147
target_arch = "s390x"
142148
)
@@ -163,9 +169,12 @@ fn test_renameat2_behaves_like_renameat_with_no_flags() {
163169
#[test]
164170
#[cfg(all(
165171
target_os = "linux",
166-
target_env = "gnu",
167172
any(
168173
target_arch = "x86_64",
174+
target_arch = "x86",
175+
target_arch = "aarch64",
176+
target_arch = "arm",
177+
target_arch = "riscv64",
169178
target_arch = "powerpc",
170179
target_arch = "s390x"
171180
)
@@ -208,9 +217,12 @@ fn test_renameat2_exchange() {
208217
#[test]
209218
#[cfg(all(
210219
target_os = "linux",
211-
target_env = "gnu",
212220
any(
213221
target_arch = "x86_64",
222+
target_arch = "x86",
223+
target_arch = "aarch64",
224+
target_arch = "arm",
225+
target_arch = "riscv64",
214226
target_arch = "powerpc",
215227
target_arch = "s390x"
216228
)

0 commit comments

Comments
 (0)