Skip to content

Commit 15cb3e0

Browse files
committed
Fix cfgs for current libc
1 parent 43f398b commit 15cb3e0

File tree

1 file changed

+139
-89
lines changed

1 file changed

+139
-89
lines changed

src/libstd/sys/unix/fs.rs

+139-89
Original file line numberDiff line numberDiff line change
@@ -41,88 +41,137 @@ pub use crate::sys_common::fs::remove_dir_all;
4141

4242
pub struct File(FileDesc);
4343

44-
#[derive(Clone)]
45-
pub struct FileAttr {
46-
stat: stat64,
47-
#[cfg(target_os = "linux")]
48-
statx_extra_fields: Option<StatxExtraFields>,
49-
}
50-
51-
#[cfg(target_os = "linux")]
52-
#[derive(Clone)]
53-
struct StatxExtraFields {
54-
// This is needed to check if btime is supported by the filesystem.
55-
stx_mask: u32,
56-
stx_btime: libc::statx_timestamp,
44+
// FIXME: This should be available on Linux with all `target_arch` and `target_env`.
45+
// https://github.com/rust-lang/libc/issues/1545
46+
macro_rules! cfg_has_statx {
47+
({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
48+
cfg_if::cfg_if! {
49+
if #[cfg(all(target_os = "linux", target_env = "gnu", any(
50+
target_arch = "x86",
51+
target_arch = "arm",
52+
// target_arch = "mips",
53+
target_arch = "powerpc",
54+
target_arch = "x86_64",
55+
// target_arch = "aarch64",
56+
target_arch = "powerpc64",
57+
// target_arch = "mips64",
58+
// target_arch = "s390x",
59+
target_arch = "sparc64",
60+
)))] {
61+
$($then_tt)*
62+
} else {
63+
$($else_tt)*
64+
}
65+
}
66+
};
67+
($($block_inner:tt)*) => {
68+
#[cfg(all(target_os = "linux", target_env = "gnu", any(
69+
target_arch = "x86",
70+
target_arch = "arm",
71+
// target_arch = "mips",
72+
target_arch = "powerpc",
73+
target_arch = "x86_64",
74+
// target_arch = "aarch64",
75+
target_arch = "powerpc64",
76+
// target_arch = "mips64",
77+
// target_arch = "s390x",
78+
target_arch = "sparc64",
79+
)))]
80+
{
81+
$($block_inner)*
82+
}
83+
};
5784
}
5885

59-
// We prefer `statx` on Linux if available, which contains file creation time.
60-
// Default `stat64` contains no creation time.
61-
#[cfg(target_os = "linux")]
62-
unsafe fn try_statx(
63-
fd: c_int,
64-
path: *const libc::c_char,
65-
flags: i32,
66-
mask: u32,
67-
) -> Option<io::Result<FileAttr>> {
68-
use crate::sync::atomic::{AtomicBool, Ordering};
86+
cfg_has_statx! {{
87+
#[derive(Clone)]
88+
pub struct FileAttr {
89+
stat: stat64,
90+
statx_extra_fields: Option<StatxExtraFields>,
91+
}
92+
93+
#[derive(Clone)]
94+
struct StatxExtraFields {
95+
// This is needed to check if btime is supported by the filesystem.
96+
stx_mask: u32,
97+
stx_btime: libc::statx_timestamp,
98+
}
99+
100+
// We prefer `statx` on Linux if available, which contains file creation time.
101+
// Default `stat64` contains no creation time.
102+
unsafe fn try_statx(
103+
fd: c_int,
104+
path: *const libc::c_char,
105+
flags: i32,
106+
mask: u32,
107+
) -> Option<io::Result<FileAttr>> {
108+
use crate::sync::atomic::{AtomicBool, Ordering};
109+
110+
// Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
111+
// We store the availability in a global to avoid unnecessary syscalls
112+
static HAS_STATX: AtomicBool = AtomicBool::new(true);
113+
syscall! {
114+
fn statx(
115+
fd: c_int,
116+
pathname: *const libc::c_char,
117+
flags: c_int,
118+
mask: libc::c_uint,
119+
statxbuf: *mut libc::statx
120+
) -> c_int
121+
}
69122

70-
// Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
71-
// We store the availability in a global to avoid unnecessary syscalls
72-
static HAS_STATX: AtomicBool = AtomicBool::new(true);
73-
syscall! {
74-
fn statx(
75-
fd: c_int,
76-
pathname: *const libc::c_char,
77-
flags: c_int,
78-
mask: libc::c_uint,
79-
statxbuf: *mut libc::statx
80-
) -> c_int
81-
}
123+
if !HAS_STATX.load(Ordering::Relaxed) {
124+
return None;
125+
}
82126

83-
if !HAS_STATX.load(Ordering::Relaxed) {
84-
return None;
85-
}
127+
let mut buf: libc::statx = mem::zeroed();
128+
let ret = cvt(statx(fd, path, flags, mask, &mut buf));
129+
match ret {
130+
Err(err) => match err.raw_os_error() {
131+
Some(libc::ENOSYS) => {
132+
HAS_STATX.store(false, Ordering::Relaxed);
133+
return None;
134+
}
135+
_ => return Some(Err(err)),
136+
}
137+
Ok(_) => {
138+
// We cannot fill `stat64` exhaustively because of private padding fields.
139+
let mut stat: stat64 = mem::zeroed();
140+
// `c_ulong` on gnu-mips, `dev_t` otherwise
141+
stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _;
142+
stat.st_ino = buf.stx_ino as libc::ino64_t;
143+
stat.st_nlink = buf.stx_nlink as libc::nlink_t;
144+
stat.st_mode = buf.stx_mode as libc::mode_t;
145+
stat.st_uid = buf.stx_uid as libc::uid_t;
146+
stat.st_gid = buf.stx_gid as libc::gid_t;
147+
stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _;
148+
stat.st_size = buf.stx_size as off64_t;
149+
stat.st_blksize = buf.stx_blksize as libc::blksize_t;
150+
stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t;
151+
stat.st_atime = buf.stx_atime.tv_sec as libc::time_t;
152+
// `i64` on gnu-x86_64-x32, `c_ulong` otherwise.
153+
stat.st_atime_nsec = buf.stx_atime.tv_nsec as _;
154+
stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t;
155+
stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _;
156+
stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t;
157+
stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _;
158+
159+
let extra = StatxExtraFields {
160+
stx_mask: buf.stx_mask,
161+
stx_btime: buf.stx_btime,
162+
};
86163

87-
let mut buf: libc::statx = mem::zeroed();
88-
let ret = cvt(statx(fd, path, flags, mask, &mut buf));
89-
match ret {
90-
Err(err) => match err.raw_os_error() {
91-
Some(libc::ENOSYS) => {
92-
HAS_STATX.store(false, Ordering::Relaxed);
93-
return None;
164+
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
94165
}
95-
_ => return Some(Err(err)),
96166
}
97-
Ok(_) => {
98-
// We cannot fill `stat64` exhaustively because of private padding fields.
99-
let mut stat: stat64 = mem::zeroed();
100-
stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor);
101-
stat.st_ino = buf.stx_ino as libc::ino64_t;
102-
stat.st_nlink = buf.stx_nlink as libc::nlink_t;
103-
stat.st_mode = buf.stx_mode as libc::mode_t;
104-
stat.st_uid = buf.stx_uid as libc::uid_t;
105-
stat.st_gid = buf.stx_gid as libc::gid_t;
106-
stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor);
107-
stat.st_size = buf.stx_size as off64_t;
108-
stat.st_blksize = buf.stx_blksize as libc::blksize_t;
109-
stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t;
110-
stat.st_atime = buf.stx_atime.tv_sec as libc::time_t;
111-
stat.st_atime_nsec = buf.stx_atime.tv_nsec as libc::c_long;
112-
stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t;
113-
stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as libc::c_long;
114-
stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t;
115-
stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as libc::c_long;
116-
117-
let extra = StatxExtraFields {
118-
stx_mask: buf.stx_mask,
119-
stx_btime: buf.stx_btime,
120-
};
167+
}
121168

122-
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
123-
}
169+
} else {
170+
#[derive(Clone)]
171+
pub struct FileAttr {
172+
stat: stat64,
124173
}
125-
}
174+
}}
126175

127176
// all DirEntry's will have a reference to this struct
128177
struct InnerReadDir {
@@ -175,15 +224,21 @@ pub struct FileType { mode: mode_t }
175224
#[derive(Debug)]
176225
pub struct DirBuilder { mode: mode_t }
177226

178-
impl FileAttr {
179-
fn from_stat64(stat: stat64) -> Self {
180-
Self {
181-
stat,
182-
#[cfg(target_os = "linux")]
183-
statx_extra_fields: None,
227+
cfg_has_statx! {{
228+
impl FileAttr {
229+
fn from_stat64(stat: stat64) -> Self {
230+
Self { stat, statx_extra_fields: None }
184231
}
185232
}
233+
} else {
234+
impl FileAttr {
235+
fn from_stat64(stat: stat64) -> Self {
236+
Self { stat }
237+
}
238+
}
239+
}}
186240

241+
impl FileAttr {
187242
pub fn size(&self) -> u64 { self.stat.st_size as u64 }
188243
pub fn perm(&self) -> FilePermissions {
189244
FilePermissions { mode: (self.stat.st_mode as mode_t) }
@@ -250,8 +305,7 @@ impl FileAttr {
250305
target_os = "macos",
251306
target_os = "ios")))]
252307
pub fn created(&self) -> io::Result<SystemTime> {
253-
#[cfg(target_os = "linux")]
254-
{
308+
cfg_has_statx! {
255309
if let Some(ext) = &self.statx_extra_fields {
256310
return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
257311
Ok(SystemTime::from(libc::timespec {
@@ -412,8 +466,7 @@ impl DirEntry {
412466
let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?;
413467
let name = self.entry.d_name.as_ptr();
414468

415-
#[cfg(target_os = "linux")]
416-
{
469+
cfg_has_statx! {
417470
if let Some(ret) = unsafe { try_statx(
418471
fd,
419472
name,
@@ -636,8 +689,7 @@ impl File {
636689
pub fn file_attr(&self) -> io::Result<FileAttr> {
637690
let fd = self.0.raw();
638691

639-
#[cfg(target_os = "linux")]
640-
{
692+
cfg_has_statx! {
641693
if let Some(ret) = unsafe { try_statx(
642694
fd,
643695
b"\0" as *const _ as *const libc::c_char,
@@ -930,8 +982,7 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
930982
pub fn stat(p: &Path) -> io::Result<FileAttr> {
931983
let p = cstr(p)?;
932984

933-
#[cfg(target_os = "linux")]
934-
{
985+
cfg_has_statx! {
935986
if let Some(ret) = unsafe { try_statx(
936987
libc::AT_FDCWD,
937988
p.as_ptr(),
@@ -952,8 +1003,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
9521003
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
9531004
let p = cstr(p)?;
9541005

955-
#[cfg(target_os = "linux")]
956-
{
1006+
cfg_has_statx! {
9571007
if let Some(ret) = unsafe { try_statx(
9581008
libc::AT_FDCWD,
9591009
p.as_ptr(),

0 commit comments

Comments
 (0)