Skip to content

Commit e5cc5ce

Browse files
authored
refactor: change dirfd arg of xxxat() to Option<fd> (#2157)
* refactor: change dirfd arg of xxxat() to Option<fd> * changelog * gate at_rawfd() with features fs or process * fix import * fix test on Android * simplify at_rawfd() * update changelog
1 parent 4b6104c commit e5cc5ce

File tree

7 files changed

+52
-32
lines changed

7 files changed

+52
-32
lines changed

changelog/2157.changed.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
The following APIs now take optional `dirfd`s:
2+
3+
- `readlinkat()`
4+
- `fstatat()`
5+
- `mknodat()`
6+
- `mkdirat()`
7+
- `execveat()`

src/fcntl.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,15 @@ libc_bitflags!(
217217
}
218218
);
219219

220+
/// Computes the raw fd consumed by a function of the form `*at`.
221+
#[cfg(any(
222+
all(feature = "fs", not(target_os = "redox")),
223+
all(feature = "process", any(target_os = "android", target_os = "linux"))
224+
))]
225+
pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
226+
fd.unwrap_or(libc::AT_FDCWD)
227+
}
228+
220229
feature! {
221230
#![feature = "fs"]
222231

@@ -366,7 +375,7 @@ fn inner_readlink<P: ?Sized + NixPath>(
366375
AtFlags::empty()
367376
};
368377
super::sys::stat::fstatat(
369-
dirfd,
378+
Some(dirfd),
370379
path,
371380
flags | AtFlags::AT_SYMLINK_NOFOLLOW,
372381
)
@@ -377,7 +386,7 @@ fn inner_readlink<P: ?Sized + NixPath>(
377386
target_os = "redox"
378387
)))]
379388
Some(dirfd) => super::sys::stat::fstatat(
380-
dirfd,
389+
Some(dirfd),
381390
path,
382391
AtFlags::AT_SYMLINK_NOFOLLOW,
383392
),
@@ -424,20 +433,12 @@ pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
424433

425434
#[cfg(not(target_os = "redox"))]
426435
pub fn readlinkat<P: ?Sized + NixPath>(
427-
dirfd: RawFd,
436+
dirfd: Option<RawFd>,
428437
path: &P,
429438
) -> Result<OsString> {
439+
let dirfd = at_rawfd(dirfd);
430440
inner_readlink(Some(dirfd), path)
431441
}
432-
433-
/// Computes the raw fd consumed by a function of the form `*at`.
434-
#[cfg(not(target_os = "redox"))]
435-
pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
436-
match fd {
437-
None => libc::AT_FDCWD,
438-
Some(fd) => fd,
439-
}
440-
}
441442
}
442443

443444
#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]

src/sys/stat.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,13 @@ pub fn mknod<P: ?Sized + NixPath>(
192192
)))]
193193
#[cfg_attr(docsrs, doc(cfg(all())))]
194194
pub fn mknodat<P: ?Sized + NixPath>(
195-
dirfd: RawFd,
195+
dirfd: Option<RawFd>,
196196
path: &P,
197197
kind: SFlag,
198198
perm: Mode,
199199
dev: dev_t,
200200
) -> Result<()> {
201+
let dirfd = at_rawfd(dirfd);
201202
let res = path.with_nix_path(|cstr| unsafe {
202203
libc::mknodat(
203204
dirfd,
@@ -270,10 +271,11 @@ pub fn fstat(fd: RawFd) -> Result<FileStat> {
270271
#[cfg(not(target_os = "redox"))]
271272
#[cfg_attr(docsrs, doc(cfg(all())))]
272273
pub fn fstatat<P: ?Sized + NixPath>(
273-
dirfd: RawFd,
274+
dirfd: Option<RawFd>,
274275
pathname: &P,
275276
f: AtFlags,
276277
) -> Result<FileStat> {
278+
let dirfd = at_rawfd(dirfd);
277279
let mut dst = mem::MaybeUninit::uninit();
278280
let res = pathname.with_nix_path(|cstr| unsafe {
279281
libc::fstatat(
@@ -468,10 +470,11 @@ pub fn utimensat<P: ?Sized + NixPath>(
468470
#[cfg(not(target_os = "redox"))]
469471
#[cfg_attr(docsrs, doc(cfg(all())))]
470472
pub fn mkdirat<P: ?Sized + NixPath>(
471-
fd: RawFd,
473+
fd: Option<RawFd>,
472474
path: &P,
473475
mode: Mode,
474476
) -> Result<()> {
477+
let fd = at_rawfd(fd);
475478
let res = path.with_nix_path(|cstr| unsafe {
476479
libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t)
477480
})?;

src/unistd.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
//! Safe wrappers around functions found in libc "unistd.h" header
22
33
use crate::errno::{self, Errno};
4+
5+
#[cfg(any(
6+
all(feature = "fs", not(target_os = "redox")),
7+
all(feature = "process", any(target_os = "android", target_os = "linux"))
8+
))]
9+
use crate::fcntl::at_rawfd;
410
#[cfg(not(target_os = "redox"))]
511
#[cfg(feature = "fs")]
6-
use crate::fcntl::{at_rawfd, AtFlags};
12+
use crate::fcntl::AtFlags;
13+
714
#[cfg(feature = "fs")]
815
use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag};
916
#[cfg(all(
@@ -939,12 +946,13 @@ pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
939946
#[cfg(any(target_os = "android", target_os = "linux"))]
940947
#[inline]
941948
pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>(
942-
dirfd: RawFd,
949+
dirfd: Option<RawFd>,
943950
pathname: &CStr,
944951
args: &[SA],
945952
env: &[SE],
946953
flags: super::fcntl::AtFlags,
947954
) -> Result<Infallible> {
955+
let dirfd = at_rawfd(dirfd);
948956
let args_p = to_exec_array(args);
949957
let env_p = to_exec_array(env);
950958

test/test_fcntl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ fn test_readlink() {
222222

223223
assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
224224
assert_eq!(
225-
readlinkat(dirfd, "b").unwrap().to_str().unwrap(),
225+
readlinkat(Some(dirfd), "b").unwrap().to_str().unwrap(),
226226
expected_dir
227227
);
228228
}

test/test_stat.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn test_fstatat() {
117117
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty());
118118

119119
let result =
120-
stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty());
120+
stat::fstatat(Some(dirfd.unwrap()), &filename, fcntl::AtFlags::empty());
121121
assert_stat_results(result);
122122
}
123123

@@ -323,7 +323,7 @@ fn test_mkdirat_success_path() {
323323
let dirfd =
324324
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
325325
.unwrap();
326-
mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed");
326+
mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed");
327327
assert!(Path::exists(&tempdir.path().join(filename)));
328328
}
329329

@@ -337,7 +337,7 @@ fn test_mkdirat_success_mode() {
337337
let dirfd =
338338
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
339339
.unwrap();
340-
mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed");
340+
mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed");
341341
let permissions = fs::metadata(tempdir.path().join(filename))
342342
.unwrap()
343343
.permissions();
@@ -357,7 +357,7 @@ fn test_mkdirat_fail() {
357357
stat::Mode::empty(),
358358
)
359359
.unwrap();
360-
let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
360+
let result = mkdirat(Some(dirfd), filename, Mode::S_IRWXU).unwrap_err();
361361
assert_eq!(result, Errno::ENOTDIR);
362362
}
363363

@@ -402,15 +402,15 @@ fn test_mknodat() {
402402
let target_dir =
403403
Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap();
404404
mknodat(
405-
target_dir.as_raw_fd(),
405+
Some(target_dir.as_raw_fd()),
406406
file_name,
407407
SFlag::S_IFREG,
408408
Mode::S_IRWXU,
409409
0,
410410
)
411411
.unwrap();
412412
let mode = fstatat(
413-
target_dir.as_raw_fd(),
413+
Some(target_dir.as_raw_fd()),
414414
file_name,
415415
AtFlags::AT_SYMLINK_NOFOLLOW,
416416
)

test/test_unistd.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ fn test_mkfifoat() {
163163
mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap();
164164

165165
let stats =
166-
stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap();
166+
stat::fstatat(Some(dirfd), mkfifoat_name, fcntl::AtFlags::empty())
167+
.unwrap();
167168
let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
168169
assert_eq!(typ, SFlag::S_IFIFO);
169170
}
@@ -197,7 +198,7 @@ fn test_mkfifoat_directory() {
197198
let tempdir = tempdir().unwrap();
198199
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
199200
let mkfifoat_dir = "mkfifoat_dir";
200-
stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap();
201+
stat::mkdirat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).unwrap();
201202

202203
mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR)
203204
.expect_err("assertion failed");
@@ -429,21 +430,21 @@ cfg_if! {
429430
if #[cfg(target_os = "android")] {
430431
use nix::fcntl::AtFlags;
431432
execve_test_factory!(test_execveat_empty, execveat,
432-
File::open("/system/bin/sh").unwrap().into_raw_fd(),
433+
Some(File::open("/system/bin/sh").unwrap().into_raw_fd()),
433434
"", AtFlags::AT_EMPTY_PATH);
434435
execve_test_factory!(test_execveat_relative, execveat,
435-
File::open("/system/bin/").unwrap().into_raw_fd(),
436+
Some(File::open("/system/bin/").unwrap().into_raw_fd()),
436437
"./sh", AtFlags::empty());
437438
execve_test_factory!(test_execveat_absolute, execveat,
438-
File::open("/").unwrap().into_raw_fd(),
439+
Some(File::open("/").unwrap().into_raw_fd()),
439440
"/system/bin/sh", AtFlags::empty());
440441
} else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] {
441442
use nix::fcntl::AtFlags;
442-
execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
443+
execve_test_factory!(test_execveat_empty, execveat, Some(File::open("/bin/sh").unwrap().into_raw_fd()),
443444
"", AtFlags::AT_EMPTY_PATH);
444-
execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(),
445+
execve_test_factory!(test_execveat_relative, execveat, Some(File::open("/bin/").unwrap().into_raw_fd()),
445446
"./sh", AtFlags::empty());
446-
execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
447+
execve_test_factory!(test_execveat_absolute, execveat, Some(File::open("/").unwrap().into_raw_fd()),
447448
"/bin/sh", AtFlags::empty());
448449
}
449450
}

0 commit comments

Comments
 (0)