Repository navigation
fs::openat2 is unavailable when building with --cfg=rustix_no_linux_raw (e.g., in AOSP) - #1713
tylersaunders wants to merge 1 commit into
Conversation
`rustix::fs::openat2` and its libc backend implementation were gated on `#[cfg(linux_raw_dep)]` in commit fda7cbe ("rustix: on Linux, support a build without linux-raw-sys (bytecodealliance#1478)") because `backend::fs::syscalls::openat2` imported `linux_raw_sys::general::open_how`. Meanwhile, the supporting `ResolveFlags` bitflags and `SYS_OPENAT2` constant in the libc backend remained gated on `#[cfg(linux_kernel)]`. Because `libc::open_how` is not defined for `target_os = "android"` and is marked `#[non_exhaustive]` on `target_os = "linux"`, define `#[repr(C)] struct open_how` locally in `backend::fs::syscalls::openat2` when `#[cfg(not(linux_raw_dep))]` and gate `openat2` on `#[cfg(linux_kernel)]`. This makes `rustix::fs::openat2` usable on Android and Linux when building with `--cfg=rustix_no_linux_raw`.
| flags: u64, | ||
| mode: u64, | ||
| resolve: u64, | ||
| } |
There was a problem hiding this comment.
libc (now?) has an open_how declaration. Should we use that instead of declaring this type manually?
There was a problem hiding this comment.
Unfortunately we can't use libc::open_how here for two reasons (I'd love to be wrong here, but this is my read after looking into this):
- Not exposed on target_os = "android": In libc, open_how (along with the RESOLVE_* constants) is defined in src/unix/linux_like/linux/mod.rs
(#[cfg(target_os = "linux")])rather than the shared linux_like or android modules, so it is absent on *-linux-android targets (compare x86_64-unknown-linux-gnu docs https://docs.rs/libc/latest/libc/struct.open_how.html vs. aarch64-linux-android docs https://docs.rs/libc/latest/aarch64-linux-android/libc/?search=open_how).
This is the same reason ResolveFlags and SYS_OPENAT2 in rustix's libc backend are defined inline under #[cfg(linux_kernel)] rather than imported from libc.
- #[non_exhaustive]: Even on target_os = "linux", libc::open_how is marked #[non_exhaustive], which disallows constructing it via the open_how { flags, mode, resolve } struct literal (E0639) and would require unsafe {core::mem::zeroed() } + field assignment.
Since the kernel ABI for openat2(2) explicitly versions struct open_how by passing size_of::<open_how>() (24 bytes for v0) as the size syscall argument, defining the 3-field #[repr(C)] struct open_how locally when not(linux_raw_dep) works uniformly across both target_os = "linux" and target_os = "android" while keeping the existing struct literal initialization intact.
There was a problem hiding this comment.
It seems that Android does declare open_how in linux/openat2.h, so an issue should be opened in the libc crate to expose it on Android targets.
Also, open_how should probably be non-exhaustive, per openat2(2):
Any future extensions to openat2() will be implemented as new fields appended to the above structure, with a zero value in a new field resulting in the kernel behaving as though that extension field was not present. Therefore, the caller must zero-fill this structure on initialization.
Context: rust-lang/libc#2477
Hello, while moving some cpp code over to rust inside of AOSP, I encounted openat2 not being useable on android linux due to some configuration, and a minor issue with the
open_howstruct not being available outside oflinux_raw_sysrustix::fs::openat2is currently gated on#[cfg(linux_raw_dep)]insrc/fs/mod.rs,src/backend/libc/fs/syscalls.rs, andtests/fs/main.rs, making it unavailable on Linux and Android when building with--cfg=rustix_no_linux_raw(such as in AOSP, which buildsrustixwith thelibcbackend and withoutlinux-raw-sys).Background Context
In #1478 (
fda7cbe6),--cfg=rustix_no_linux_rawwas introduced so projects like AOSP and Mesa3D can buildrustixon Linux and Android using thelibcbackend without depending onlinux-raw-sys.In that change,
openat2was switched from#[cfg(linux_kernel)]to#[cfg(linux_raw_dep)]in:src/fs/mod.rs(mod openat2;andpub use openat2::openat2;)src/backend/libc/fs/syscalls.rs(pub(crate) fn openat2)However, all other
openat2support in thelibcbackend is already independent oflinux-raw-sysand gated on#[cfg(linux_kernel)]:rustix::fs::ResolveFlagsinsrc/backend/libc/fs/types.rsis gated on#[cfg(linux_kernel)](and its rustdoc links to[openat2]: crate::fs::openat2, which is broken whennot(linux_raw_dep)).use crate::fs::ResolveFlagsandconst SYS_OPENAT2 = 437insrc/backend/libc/fs/syscalls.rsare already gated on#[cfg(linux_kernel)].The only dependency on
linux-raw-sysinsidesrc/backend/libc/fs/syscalls.rs::openat2isuse linux_raw_sys::general::open_how;for the 24-byte kernel ABI struct (struct open_how { flags: u64, mode: u64, resolve: u64 }). Note thatlibc::open_howcannot be used directly because it is not defined fortarget_os = "android"inlibcand is marked#[non_exhaustive]ontarget_os = "linux".Proposed Solution (see attached commit)
src/backend/libc/fs/syscalls.rs::openat2, define#[repr(C)] struct open_how { flags: u64, mode: u64, resolve: u64 }when#[cfg(not(linux_raw_dep))](retaininguse linux_raw_sys::general::open_how;when#[cfg(linux_raw_dep)]).cfggate onopenat2insrc/fs/mod.rs,src/backend/libc/fs/syscalls.rs, andtests/fs/main.rsfrom#[cfg(linux_raw_dep)]back to#[cfg(linux_kernel)].I've tested & verified the behavior of this patch in one of our cpp -> rust migrations inside of AOSP. Ideally I'd like to land this upstream rather than maintaining our own AOSP patch downstream.