Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support 64-bit file offsets on systems with 32-bit off_t #2032

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 49 additions & 24 deletions src/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::errno::Errno;
#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
use core::slice;
use libc::{c_int, c_uint, size_t, ssize_t};
use libc::{self, c_int, c_uint, size_t, ssize_t};
#[cfg(any(
target_os = "netbsd",
apple_targets,
Expand Down Expand Up @@ -163,8 +163,12 @@ libc_bitflags!(
all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos")),
target_os = "redox"))]
O_FSYNC;
/// Allow files whose sizes can't be represented in an `off_t` to be opened.
/// On 32-bit Linux, O_LARGEFILE allows the use of file
/// offsets greater than 32 bits. Nix accepts the flag for
/// compatibility, but always opens files in large file mode
/// even if it isn't specified.
#[cfg(linux_android)]
#[cfg_attr(docsrs, doc(cfg(all())))]
O_LARGEFILE;
/// Do not update the file last access time during `read(2)`s.
#[cfg(linux_android)]
Expand Down Expand Up @@ -249,7 +253,7 @@ pub fn open<P: ?Sized + NixPath>(
use std::os::fd::FromRawFd;

let fd = path.with_nix_path(|cstr| unsafe {
libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
largefile_fn![open](cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
})?;
Errno::result(fd)?;

Expand Down Expand Up @@ -280,7 +284,12 @@ pub fn openat<P: ?Sized + NixPath, Fd: std::os::fd::AsFd>(
use std::os::fd::FromRawFd;

let fd = path.with_nix_path(|cstr| unsafe {
libc::openat(dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
largefile_fn![openat](
dirfd.as_fd().as_raw_fd(),
cstr.as_ptr(),
oflag.bits(),
mode.bits() as c_uint,
)
})?;
Errno::result(fd)?;

Expand Down Expand Up @@ -1303,23 +1312,26 @@ feature! {
/// file referred to by fd.
#[cfg(target_os = "linux")]
#[cfg(feature = "fs")]
pub fn fallocate<Fd: std::os::fd::AsFd>(
pub fn fallocate<Fd: std::os::fd::AsFd, Off: Into<i64>>(
fd: Fd,
mode: FallocateFlags,
offset: libc::off_t,
len: libc::off_t,
offset: Off,
len: Off,
) -> Result<()> {
use std::os::fd::AsRawFd;

let res = unsafe { libc::fallocate(fd.as_fd().as_raw_fd(), mode.bits(), offset, len) };
let res = unsafe {
largefile_fn![fallocate](
fd.as_fd().as_raw_fd(), mode.bits(), offset.into(), len.into())
};
Errno::result(res).map(drop)
}

/// Argument to [`fspacectl`] describing the range to zero. The first member is
/// the file offset, and the second is the length of the region.
#[cfg(any(target_os = "freebsd"))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SpacectlRange(pub libc::off_t, pub libc::off_t);
pub struct SpacectlRange(pub i64, pub i64);

#[cfg(any(target_os = "freebsd"))]
impl SpacectlRange {
Expand All @@ -1334,13 +1346,13 @@ impl SpacectlRange {

/// Remaining length of the range
#[inline]
pub fn len(&self) -> libc::off_t {
pub fn len(&self) -> i64 {
self.1
}

/// Next file offset to operate on
#[inline]
pub fn offset(&self) -> libc::off_t {
pub fn offset(&self) -> i64 {
self.0
}
}
Expand Down Expand Up @@ -1437,16 +1449,16 @@ pub fn fspacectl<Fd: std::os::fd::AsFd>(fd: Fd, range: SpacectlRange) -> Result<
/// ```
#[cfg(target_os = "freebsd")]
#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined
pub fn fspacectl_all<Fd: std::os::fd::AsFd>(
pub fn fspacectl_all<Fd: std::os::fd::AsFd, Off: Into<i64>>(
fd: Fd,
offset: libc::off_t,
len: libc::off_t,
offset: Off,
len: Off,
) -> Result<()> {
use std::os::fd::AsRawFd;

let mut rqsr = libc::spacectl_range {
r_offset: offset,
r_len: len,
r_offset: offset.into(),
r_len: len.into(),
};
while rqsr.r_len > 0 {
let res = unsafe {
Expand Down Expand Up @@ -1505,15 +1517,22 @@ mod posix_fadvise {
///
/// # See Also
/// * [`posix_fadvise`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html)
pub fn posix_fadvise<Fd: std::os::fd::AsFd>(
pub fn posix_fadvise<Fd: std::os::fd::AsFd, Off: Into<i64>>(
fd: Fd,
offset: libc::off_t,
len: libc::off_t,
offset: Off,
len: Off,
advice: PosixFadviseAdvice,
) -> Result<()> {
use std::os::fd::AsRawFd;

let res = unsafe { libc::posix_fadvise(fd.as_fd().as_raw_fd(), offset, len, advice as libc::c_int) };
let res = unsafe {
largefile_fn![posix_fadvise](
fd.as_fd().as_raw_fd(),
offset.into(),
len.into(),
advice as libc::c_int,
)
};

if res == 0 {
Ok(())
Expand All @@ -1535,14 +1554,20 @@ mod posix_fadvise {
target_os = "fuchsia",
target_os = "wasi",
))]
pub fn posix_fallocate<Fd: std::os::fd::AsFd>(
pub fn posix_fallocate<Fd: std::os::fd::AsFd, Off: Into<i64>>(
fd: Fd,
offset: libc::off_t,
len: libc::off_t,
offset: Off,
len: Off,
) -> Result<()> {
use std::os::fd::AsRawFd;

let res = unsafe { libc::posix_fallocate(fd.as_fd().as_raw_fd(), offset, len) };
let res = unsafe {
largefile_fn![posix_fallocate](
fd.as_fd().as_raw_fd(),
offset.into(),
len.into(),
)
};
match Errno::result(res) {
Err(err) => Err(err),
Ok(0) => Ok(()),
Expand Down
47 changes: 47 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use cfg_if::cfg_if;

// Thanks to Tokio for this macro
macro_rules! feature {
(
Expand Down Expand Up @@ -329,3 +331,48 @@ macro_rules! libc_enum {
}
};
}

cfg_if! {
if #[cfg(any(
all(target_os = "linux", target_env = "gnu"),
target_os = "android",
))] {
/// Function variant that supports large file positions.
///
/// On some platforms, the standard I/O functions support a limited
/// range of file positions, and there is an alternate set of
/// functions that support larger file positions. This macro takes
/// the identifier of a standard I/O function and returns the
/// identifier of the corresponding I/O function with large file
/// support.
#[allow(unused_macro_rules)]
macro_rules! largefile_fn {
[fallocate] => (libc::fallocate64);
[ftruncate] => (libc::ftruncate64);
[lseek] => (libc::lseek64);
[mmap] => (libc::mmap64);
[open] => (libc::open64);
[openat] => (libc::openat64);
[posix_fadvise] => (libc::posix_fadvise64);
[posix_fallocate] => (libc::posix_fallocate64);
[pread] => (libc::pread64);
[preadv] => (libc::preadv64);
[pwrite] => (libc::pwrite64);
[pwritev] => (libc::pwritev64);
[sendfile] => (libc::sendfile64);
[truncate] => (libc::truncate64);
}
} else {
/// Function variant that supports large file positions.
///
/// On some platforms, the standard I/O functions support a limited
/// range of file positions, and there is an alternate set of
/// functions that support larger file positions. This macro takes
/// the identifier of a standard I/O function and returns the
/// identifier of the corresponding I/O function with large file
/// support.
macro_rules! largefile_fn {
[$id:ident] => (libc::$id);
}
}
}
9 changes: 5 additions & 4 deletions src/sys/mman.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::Result;
#[cfg(not(target_os = "android"))]
#[cfg(feature = "fs")]
use crate::{fcntl::OFlag, sys::stat::Mode};
use libc::{self, c_int, c_void, off_t, size_t};
use libc::{self, c_int, c_void, size_t};
use std::ptr::NonNull;
use std::{
num::NonZeroUsize,
Expand Down Expand Up @@ -392,19 +392,20 @@ pub fn munlockall() -> Result<()> {
/// See the [`mmap(2)`] man page for detailed requirements.
///
/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html
pub unsafe fn mmap<F: AsFd>(
pub unsafe fn mmap<F: AsFd, Off: Into<i64>>(
addr: Option<NonZeroUsize>,
length: NonZeroUsize,
prot: ProtFlags,
flags: MapFlags,
f: F,
offset: off_t,
offset: Off,
) -> Result<NonNull<c_void>> {
let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void);

let fd = f.as_fd().as_raw_fd();
let ret = unsafe {
libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset)
largefile_fn![mmap](
ptr, length.into(), prot.bits(), flags.bits(), fd, offset.into())
};

if ret == libc::MAP_FAILED {
Expand Down
42 changes: 21 additions & 21 deletions src/sys/sendfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use cfg_if::cfg_if;
use std::os::unix::io::{AsFd, AsRawFd};
use std::ptr;

use libc::{self, off_t};
use libc;

use crate::errno::Errno;
use crate::Result;
Expand All @@ -26,14 +26,14 @@ use crate::Result;
pub fn sendfile<F1: AsFd, F2: AsFd>(
out_fd: F1,
in_fd: F2,
offset: Option<&mut off_t>,
offset: Option<&mut i64>,
count: usize,
) -> Result<usize> {
let offset = offset
.map(|offset| offset as *mut _)
.unwrap_or(ptr::null_mut());
let ret = unsafe {
libc::sendfile(
largefile_fn![sendfile](
out_fd.as_fd().as_raw_fd(),
in_fd.as_fd().as_raw_fd(),
offset,
Expand Down Expand Up @@ -133,20 +133,20 @@ cfg_if! {
impl<'fd> SendfileVec<'fd> {
/// initialises SendfileVec to send data directly from the process's address space
/// same in C with sfv_fd set to SFV_FD_SELF.
pub fn newself(
off: off_t,
pub fn newself<Off: Into<i64>>(
off: Off,
len: usize
) -> Self {
Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData}
Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off.into(), sfv_len: len}, phantom: PhantomData}
}

/// initialises SendfileVec to send data from `fd`.
pub fn new(
pub fn new<Off: Into<i64>>(
fd: BorrowedFd<'fd>,
off: off_t,
off: Off,
len: usize
) -> SendfileVec<'fd> {
Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData}
Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off.into(), sfv_len: len}, phantom: PhantomData}
}
}

Expand Down Expand Up @@ -208,19 +208,19 @@ cfg_if! {
pub fn sendfile<F1: AsFd, F2: AsFd>(
in_fd: F1,
out_sock: F2,
offset: off_t,
offset: i64,
count: Option<usize>,
headers: Option<&[&[u8]]>,
trailers: Option<&[&[u8]]>,
flags: SfFlags,
readahead: u16
) -> (Result<()>, off_t) {
) -> (Result<()>, i64) {
// Readahead goes in upper 16 bits
// Flags goes in lower 16 bits
// see `man 2 sendfile`
let ra32 = u32::from(readahead);
let flags: u32 = (ra32 << 16) | (flags.bits() as u32);
let mut bytes_sent: off_t = 0;
let mut bytes_sent: i64 = 0;
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
let return_code = unsafe {
Expand All @@ -229,7 +229,7 @@ cfg_if! {
offset,
count.unwrap_or(0),
hdtr_ptr as *mut libc::sf_hdtr,
&mut bytes_sent as *mut off_t,
&mut bytes_sent as *mut i64,
flags as c_int)
};
(Errno::result(return_code).and(Ok(())), bytes_sent)
Expand Down Expand Up @@ -258,12 +258,12 @@ cfg_if! {
pub fn sendfile<F1: AsFd, F2: AsFd>(
in_fd: F1,
out_sock: F2,
offset: off_t,
offset: i64,
count: Option<usize>,
headers: Option<&[&[u8]]>,
trailers: Option<&[&[u8]]>,
) -> (Result<()>, off_t) {
let mut bytes_sent: off_t = 0;
) -> (Result<()>, i64) {
let mut bytes_sent: i64 = 0;
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
let return_code = unsafe {
Expand All @@ -272,7 +272,7 @@ cfg_if! {
offset,
count.unwrap_or(0),
hdtr_ptr as *mut libc::sf_hdtr,
&mut bytes_sent as *mut off_t,
&mut bytes_sent as *mut i64,
0)
};
(Errno::result(return_code).and(Ok(())), bytes_sent)
Expand Down Expand Up @@ -304,19 +304,19 @@ cfg_if! {
pub fn sendfile<F1: AsFd, F2: AsFd>(
in_fd: F1,
out_sock: F2,
offset: off_t,
count: Option<off_t>,
offset: i64,
count: Option<i64>,
headers: Option<&[&[u8]]>,
trailers: Option<&[&[u8]]>
) -> (Result<()>, off_t) {
) -> (Result<()>, i64) {
let mut len = count.unwrap_or(0);
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
let return_code = unsafe {
libc::sendfile(in_fd.as_fd().as_raw_fd(),
out_sock.as_fd().as_raw_fd(),
offset,
&mut len as *mut off_t,
&mut len as *mut i64,
hdtr_ptr as *mut libc::sf_hdtr,
0)
};
Expand Down
Loading