/// Use a direct syscall (via libc) for `open`. /// /// This is only currently necessary as a workaround for old glibc; see below. #[cfg(all(unix, target_env = "gnu"))] fn open_via_syscall(path: &CStr, oflags: OFlags, mode: Mode) -> io::Result<OwnedFd> { // Linux on aarch64, loongarch64 and riscv64 has no `open` syscall so use // `openat`. #[cfg(any(
target_arch = "aarch64",
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "csky",
target_arch = "loongarch64"
))]
{
openat_via_syscall(CWD, path, oflags, mode)
}
// On these platforms, `mode_t` is `u16` and can't be passed directly to a // variadic function. #[cfg(any(
apple,
freebsdlike,
all(target_os = "android", target_pointer_width = "32")
))] let mode: c::c_uint = mode.bits().into();
// Otherwise, cast to `mode_t` as that's what `open` is documented to take. #[cfg(not(any(
apple,
freebsdlike,
all(target_os = "android", target_pointer_width = "32")
)))] let mode: c::mode_t = mode.bits() as _;
/// Use a direct syscall (via libc) for `openat`. /// /// This is only currently necessary as a workaround for old glibc; see below. #[cfg(all(unix, target_env = "gnu", not(target_os = "hurd")))] fn openat_via_syscall(
dirfd: BorrowedFd<'_>,
path: &CStr,
oflags: OFlags,
mode: Mode,
) -> io::Result<OwnedFd> {
syscall! { fn openat(
base_dirfd: c::c_int,
pathname: *const ffi::c_char,
oflags: c::c_int,
mode: c::mode_t
) via SYS_openat -> c::c_int
}
// On these platforms, `mode_t` is `u16` and can't be passed directly to a // variadic function. #[cfg(any(
apple,
freebsdlike,
all(target_os = "android", target_pointer_width = "32")
))] let mode: c::c_uint = mode.bits().into();
// Otherwise, cast to `mode_t` as that's what `open` is documented to take. #[cfg(not(any(
apple,
freebsdlike,
all(target_os = "android", target_pointer_width = "32")
)))] let mode: c::mode_t = mode.bits() as _;
pub(crate) fn stat(path: &CStr) -> io::Result<Stat> { // See the comments in `fstat` about using `crate::fs::statx` here. #[cfg(all(
linux_kernel,
any(
target_pointer_width = "32",
target_arch = "mips64",
target_arch = "mips64r6"
)
))]
{ matchcrate::fs::statx(CWD, path, AtFlags::empty(), StatxFlags::BASIC_STATS) {
Ok(x) => statx_to_stat(x),
Err(io::Errno::NOSYS) => statat_old(CWD, path, AtFlags::empty()),
Err(err) => Err(err),
}
}
// Main version: libc is y2038 safe. Or, the platform is not y2038 safe and // there's nothing practical we can do. #[cfg(not(all(
linux_kernel,
any(
target_pointer_width = "32",
target_arch = "mips64",
target_arch = "mips64r6"
)
)))] unsafe { #[cfg(test)]
assert_eq_size!(Stat, c::stat);
letmut stat = MaybeUninit::<Stat>::uninit();
ret(c::stat(c_str(path), stat.as_mut_ptr().cast()))?; let stat = stat.assume_init(); #[cfg(apple)] let stat = fix_negative_stat_nsecs(stat);
Ok(stat)
}
}
// Main version: libc is y2038 safe. Or, the platform is not y2038 safe and // there's nothing practical we can do. #[cfg(not(all(
linux_kernel,
any(
target_pointer_width = "32",
target_arch = "mips64",
target_arch = "mips64r6"
)
)))] unsafe { #[cfg(test)]
assert_eq_size!(Stat, c::stat);
letmut stat = MaybeUninit::<Stat>::uninit();
ret(c::lstat(c_str(path), stat.as_mut_ptr().cast()))?; let stat = stat.assume_init(); #[cfg(apple)] let stat = fix_negative_stat_nsecs(stat);
Ok(stat)
}
}
// Main version: libc is y2038 safe. Or, the platform is not y2038 safe and // there's nothing practical we can do. #[cfg(not(all(
linux_kernel,
any(
target_pointer_width = "32",
target_arch = "mips64",
target_arch = "mips64r6"
)
)))] unsafe { #[cfg(test)]
assert_eq_size!(Stat, c::stat);
letmut stat = MaybeUninit::<Stat>::uninit();
ret(c::fstatat(
borrowed_fd(dirfd),
c_str(path),
stat.as_mut_ptr().cast(),
bitflags_bits!(flags),
))?; let stat = stat.assume_init(); #[cfg(apple)] let stat = fix_negative_stat_nsecs(stat);
Ok(stat)
}
}
#[cfg(not(any(
target_os = "espidf",
target_os = "horizon",
target_os = "redox",
target_os = "vita"
)))] pub(crate) fn utimensat(
dirfd: BorrowedFd<'_>,
path: &CStr,
times: &Timestamps,
flags: AtFlags,
) -> io::Result<()> { // Old 32-bit version: libc has `utimensat` but it is not y2038 safe by // default. But there may be a `__utimensat64` we can use. #[cfg(all(fix_y2038, not(apple)))]
{ #[cfg(target_env = "gnu")] iflet Some(libc_utimensat) = __utimensat64.get() { let libc_times: [LibcTimespec; 2] =
[times.last_access.into(), times.last_modification.into()];
// Main version: libc is y2038 safe and has `utimensat`. Or, the platform // is not y2038 safe and there's nothing practical we can do. #[cfg(not(any(apple, fix_y2038)))] unsafe { usecrate::utils::as_ptr;
// If we have `utimensat`, use it. iflet Some(have_utimensat) = utimensat.get() { return ret(have_utimensat(
borrowed_fd(dirfd),
c_str(path),
as_ptr(times).cast(),
bitflags_bits!(flags),
));
}
// Convert `times`. We only need this in the child, but do it before // calling `fork` because it might fail. let (attrbuf_size, times, attrs) = times_to_attrlist(times)?;
// `setattrlistat` was introduced in 10.13 along with `utimensat`, so // if we don't have `utimensat`, we don't have `setattrlistat` either. // Emulate it using `fork`, and `fchdir` and [`setattrlist`]. // // [`setattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setattrlist.2.html match c::fork() {
-1 => Err(io::Errno::IO), 0 => { if c::fchdir(borrowed_fd(dirfd)) != 0 { let code = match libc_errno::errno().0 {
c::EACCES => 2,
c::ENOTDIR => 3,
_ => 1,
};
c::_exit(code);
}
#[cfg(linux_kernel)] pub(crate) fn chmodat(
dirfd: BorrowedFd<'_>,
path: &CStr,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> { // Linux's `fchmodat` does not have a flags argument. // // Use `c::syscall` rather than `c::fchmodat` because some libc // implementations, such as musl, add extra logic to `fchmod` to emulate // support for `AT_SYMLINK_NOFOLLOW`, which uses `/proc` outside our // control.
syscall! { fn fchmodat(
base_dirfd: c::c_int,
pathname: *const ffi::c_char,
mode: c::mode_t
) via SYS_fchmodat -> c::c_int
} if flags == AtFlags::SYMLINK_NOFOLLOW { return Err(io::Errno::OPNOTSUPP);
} if !flags.is_empty() { return Err(io::Errno::INVAL);
} unsafe {
ret(fchmodat(
borrowed_fd(dirfd),
c_str(path),
mode.bits() as c::mode_t,
))
}
}
letmut off_in_val: c::loff_t = 0; letmut off_out_val: c::loff_t = 0; // Silently cast; we'll get `EINVAL` if the value is negative. let off_in_ptr = iflet Some(off_in) = &off_in {
off_in_val = **off_in as i64;
&mut off_in_val
} else {
null_mut()
}; let off_out_ptr = iflet Some(off_out) = &off_out {
off_out_val = **off_out as i64;
&mut off_out_val
} else {
null_mut()
}; let copied = unsafe {
ret_usize(copy_file_range(
borrowed_fd(fd_in),
off_in_ptr,
borrowed_fd(fd_out),
off_out_ptr,
len, 0, // no flags are defined yet
))?
}; iflet Some(off_in) = off_in {
*off_in = off_in_val as u64;
} iflet Some(off_out) = off_out {
*off_out = off_out_val as u64;
}
Ok(copied)
}
#[cfg(not(any(
apple,
netbsdlike,
target_os = "dragonfly",
target_os = "espidf",
target_os = "haiku",
target_os = "horizon",
target_os = "redox",
target_os = "solaris",
target_os = "vita",
)))] pub(crate) fn fadvise(
fd: BorrowedFd<'_>,
offset: u64,
len: Option<NonZeroU64>,
advice: Advice,
) -> io::Result<()> { let offset = offset as i64; let len = match len {
None => 0,
Some(len) => len.get() as i64,
};
// Our public API uses `u64` following the [Rust convention], but the // underlying host APIs use a signed `off_t`. Converting these values may // turn a very large value into a negative value. // // On FreeBSD, this could cause `posix_fadvise` to fail with // `Errno::INVAL`. Because we don't expose the signed type in our API, we // also avoid exposing this artifact of casting an unsigned value to the // signed type. To do this, we use a no-op call in this case. // // [Rust convention]: std::io::SeekFrom::Start #[cfg(target_os = "freebsd")] if offset < 0 { if len < 0 { return Err(io::Errno::INVAL);
}
return fadvise_noop(fd);
#[cold] fn fadvise_noop(fd: BorrowedFd<'_>) -> io::Result<()> { // Use an `fcntl` to report `Errno::BADF` if needed, but otherwise // do nothing.
fcntl_getfl(fd).map(|_| ())
}
}
// Similarly, on FreeBSD, if `offset + len` would overflow an `off_t` in a // way that users using a `u64` interface wouldn't be aware of, reduce the // length so that we only operate on the range that doesn't overflow. #[cfg(target_os = "freebsd")] let len = if len > 0 && offset.checked_add(len).is_none() {
i64::MAX - offset
} else {
len
};
let err = unsafe { c::posix_fadvise(borrowed_fd(fd), offset, len, advice as c::c_int) };
// `posix_fadvise` returns its error status rather than using `errno`. if err == 0 {
Ok(())
} else {
Err(io::Errno(err))
}
}
// When `l_len` is zero, this locks all the bytes from // `l_whence`/`l_start` to the end of the file, even as the // file grows dynamically.
lock.l_whence = SEEK_SET as _;
lock.l_start = 0;
lock.l_len = 0;
ret(c::fcntl(borrowed_fd(fd), cmd, &lock))
}
}
pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { let (whence, offset) = match pos {
SeekFrom::Start(pos) => { let pos: u64 = pos; // Silently cast; we'll get `EINVAL` if the value is negative.
(c::SEEK_SET, pos as i64)
}
SeekFrom::End(offset) => (c::SEEK_END, offset),
SeekFrom::Current(offset) => (c::SEEK_CUR, offset), #[cfg(any(apple, freebsdlike, linux_kernel, solarish))]
SeekFrom::Data(pos) => { let pos: u64 = pos; // Silently cast; we'll get `EINVAL` if the value is negative.
(c::SEEK_DATA, pos as i64)
} #[cfg(any(apple, freebsdlike, linux_kernel, solarish))]
SeekFrom::Hole(pos) => { let pos: u64 = pos; // Silently cast; we'll get `EINVAL` if the value is negative.
(c::SEEK_HOLE, pos as i64)
}
};
// ESP-IDF and Vita don't support 64-bit offsets, for example. let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
let offset = unsafe { ret_off_t(c::lseek(borrowed_fd(fd), offset, whence))? };
Ok(offset as u64)
}
pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> { let offset = unsafe { ret_off_t(c::lseek(borrowed_fd(fd), 0, c::SEEK_CUR))? };
Ok(offset as u64)
}
#[cfg(linux_kernel)] pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { // Use `c::syscall` rather than `c::fchmod` because some libc // implementations, such as musl, add extra logic to `fchmod` to emulate // support for `O_PATH`, which uses `/proc` outside our control and // interferes with our own use of `O_PATH`.
syscall! { fn fchmod(
fd: c::c_int,
mode: c::mode_t
) via SYS_fchmod -> c::c_int
} unsafe { ret(fchmod(borrowed_fd(fd), mode.bits() as c::mode_t)) }
}
#[cfg(linux_kernel)] pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { // Use `c::syscall` rather than `c::fchown` because some libc // implementations, such as musl, add extra logic to `fchown` to emulate // support for `O_PATH`, which uses `/proc` outside our control and // interferes with our own use of `O_PATH`.
syscall! { fn fchown(
fd: c::c_int,
owner: c::uid_t,
group: c::gid_t
) via SYS_fchown -> c::c_int
} unsafe { let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
ret(fchown(borrowed_fd(fd), ow, gr))
}
}
pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> { // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use // `statx`. // // And, some old platforms don't support `statx`, and some fail with a // confusing error code, so we call `crate::fs::statx` to handle that. If // `statx` isn't available, fall back to the buggy system call. #[cfg(all(
linux_kernel,
any(
target_pointer_width = "32",
target_arch = "mips64",
target_arch = "mips64r6"
)
))]
{ matchcrate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
Ok(x) => statx_to_stat(x),
Err(io::Errno::NOSYS) => fstat_old(fd),
Err(err) => Err(err),
}
}
// Main version: libc is y2038 safe. Or, the platform is not y2038 safe and // there's nothing practical we can do. #[cfg(not(all(
linux_kernel,
any(
target_pointer_width = "32",
target_arch = "mips64",
target_arch = "mips64r6"
)
)))] unsafe { #[cfg(test)]
assert_eq_size!(Stat, c::stat);
letmut stat = MaybeUninit::<Stat>::uninit();
ret(c::fstat(borrowed_fd(fd), stat.as_mut_ptr().cast()))?; let stat = stat.assume_init(); #[cfg(apple)] let stat = fix_negative_stat_nsecs(stat);
Ok(stat)
}
}
#[cfg(not(target_os = "wasi"))] fn libc_statvfs_to_statvfs(from: c::statvfs) -> StatVfs {
StatVfs {
f_bsize: from.f_bsize as u64,
f_frsize: from.f_frsize as u64,
f_blocks: from.f_blocks as u64,
f_bfree: from.f_bfree as u64,
f_bavail: from.f_bavail as u64,
f_files: from.f_files as u64,
f_ffree: from.f_ffree as u64,
f_favail: from.f_ffree as u64, #[cfg(not(target_os = "aix"))]
f_fsid: from.f_fsid as u64, #[cfg(target_os = "aix")]
f_fsid: ((from.f_fsid.val[0] as u64) << 32) | from.f_fsid.val[1],
f_flag: StatVfsMountFlags::from_bits_retain(from.f_flag as u64),
f_namemax: from.f_namemax as u64,
}
}
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { // Old 32-bit version: libc has `futimens` but it is not y2038 safe by // default. But there may be a `__futimens64` we can use. #[cfg(all(fix_y2038, not(apple)))]
{ #[cfg(target_env = "gnu")] iflet Some(libc_futimens) = __futimens64.get() { let libc_times: [LibcTimespec; 2] =
[times.last_access.into(), times.last_modification.into()];
// Main version: libc is y2038 safe and has `futimens`. Or, the platform // is not y2038 safe and there's nothing practical we can do. #[cfg(not(any(apple, fix_y2038)))] unsafe { usecrate::utils::as_ptr;
#[cfg(not(any(
apple,
netbsdlike,
target_os = "dragonfly",
target_os = "espidf",
target_os = "horizon",
target_os = "nto",
target_os = "redox",
target_os = "vita",
)))] pub(crate) fn fallocate(
fd: BorrowedFd<'_>,
mode: FallocateFlags,
offset: u64,
len: u64,
) -> io::Result<()> { // Silently cast to `i64`; we'll get `EINVAL` if the value is negative. let offset = offset as i64; let len = len as i64;
// ESP-IDF and Vita don't support 64-bit offsets, for example. let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?; let len = len.try_into().map_err(|_| io::Errno::OVERFLOW)?;
/// Convert from a Linux `statx` value to rustix's `Stat`. #[cfg(all(linux_kernel, target_pointer_width = "32"))] fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> {
Ok(Stat {
st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor).into(),
st_mode: x.stx_mode.into(),
st_nlink: x.stx_nlink.into(),
st_uid: x.stx_uid.into(),
st_gid: x.stx_gid.into(),
st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor).into(),
st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
st_blksize: x.stx_blksize.into(),
st_blocks: x.stx_blocks.into(),
st_atime: bitcast!(i64::from(x.stx_atime.tv_sec)),
st_atime_nsec: x.stx_atime.tv_nsec as _,
st_mtime: bitcast!(i64::from(x.stx_mtime.tv_sec)),
st_mtime_nsec: x.stx_mtime.tv_nsec as _,
st_ctime: bitcast!(i64::from(x.stx_ctime.tv_sec)),
st_ctime_nsec: x.stx_ctime.tv_nsec as _,
st_ino: x.stx_ino.into(),
})
}
/// Convert from a Linux `statx` value to rustix's `Stat`. /// /// mips64' `struct stat64` in libc has private fields, and `stx_blocks` #[cfg(all(linux_kernel, any(target_arch = "mips64", target_arch = "mips64r6")))] fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { letmut result: Stat = unsafe { core::mem::zeroed() };
/// Convert from a Linux `stat64` value to rustix's `Stat`. /// /// mips64' `struct stat64` in libc has private fields, and `st_blocks` has /// type `i64`. #[cfg(all(linux_kernel, any(target_arch = "mips64", target_arch = "mips64r6")))] fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { letmut result: Stat = unsafe { core::mem::zeroed() };
#[cfg(linux_kernel)] #[allow(non_upper_case_globals)] pub(crate) fn statx(
dirfd: BorrowedFd<'_>,
path: &CStr,
flags: AtFlags,
mask: StatxFlags,
) -> io::Result<Statx> { // If a future Linux kernel adds more fields to `struct statx` and users // passing flags unknown to rustix in `StatxFlags`, we could end up // writing outside of the buffer. To prevent this possibility, we mask off // any flags that we don't know about. // // This includes `STATX__RESERVED`, which has a value that we know, but // which could take on arbitrary new meaning in the future. Linux currently // rejects this flag with `EINVAL`, so we do the same. // // This doesn't rely on `STATX_ALL` because [it's deprecated] and already // doesn't represent all the known flags. // // [it's deprecated]: https://patchwork.kernel.org/project/linux-fsdevel/patch/20200505095915.11275-7-mszeredi@redhat.com/ #[cfg(any(not(linux_raw_dep), not(target_env = "musl")))] const STATX__RESERVED: u32 = c::STATX__RESERVED as u32; #[cfg(target_env = "musl")] const STATX__RESERVED: u32 = linux_raw_sys::general::STATX__RESERVED; if (mask.bits() & STATX__RESERVED) == STATX__RESERVED { return Err(io::Errno::INVAL);
} let mask = mask & StatxFlags::all();
#[cfg(all(linux_kernel, not(feature = "linux_4_11")))] #[inline] pub(crate) fn is_statx_available() -> bool { unsafe { // Call `statx` with null pointers so that if it fails for any reason // other than `EFAULT`, we know it's not supported.
matches!(
ret(sys::statx(CWD, null(), 0, 0, null_mut())),
Err(io::Errno::FAULT)
)
}
}
#[cfg(all(apple, feature = "alloc"))] pub(crate) fn getpath(fd: BorrowedFd<'_>) -> io::Result<CString> { // The use of `PATH_MAX` is generally not encouraged, but it // is inevitable in this case because macOS defines `fcntl` with // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. letmut buf = vec![0; c::PATH_MAX as usize];
let l = buf.iter().position(|&c| c == 0).unwrap();
buf.truncate(l);
buf.shrink_to_fit();
Ok(CString::new(buf).unwrap())
}
#[cfg(apple)] pub(crate) fn fcntl_rdadvise(fd: BorrowedFd<'_>, offset: u64, len: u64) -> io::Result<()> { // From the [macOS `fcntl` manual page]: // `F_RDADVISE` - Issue an advisory read async with no copy to user. // // The `F_RDADVISE` command operates on the following structure which holds // information passed from the user to the system: // // ```c // struct radvisory { // off_t ra_offset; /* offset into the file */ // int ra_count; /* size of the read */ // }; // ``` // // [macOS `fcntl` manual page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html let ra_offset = match offset.try_into() {
Ok(len) => len, // If this conversion fails, the user is providing an offset outside // any possible file extent, so just ignore it.
Err(_) => return Ok(()),
}; let ra_count = match len.try_into() {
Ok(len) => len, // If this conversion fails, the user is providing a dubiously large // hint which is unlikely to improve performance.
Err(_) => return Ok(()),
}; unsafe { let radvisory = c::radvisory {
ra_offset,
ra_count,
};
ret(c::fcntl(borrowed_fd(fd), c::F_RDADVISE, &radvisory))
}
}
/// Convert `times` from a `futimens`/`utimensat` argument into `setattrlist` /// arguments. #[cfg(apple)] fn times_to_attrlist(times: &Timestamps) -> io::Result<(c::size_t, [c::timespec; 2], Attrlist)> { // ABI details. const ATTR_CMN_MODTIME: u32 = 0x0000_0400; const ATTR_CMN_ACCTIME: u32 = 0x0000_1000; const ATTR_BIT_MAP_COUNT: u16 = 5;
letmut times = times.clone();
// If we have any `UTIME_NOW` elements, replace them with the current time. if times.last_access.tv_nsec == c::UTIME_NOW.into()
|| times.last_modification.tv_nsec == c::UTIME_NOW.into()
{ let now = { letmut tv = c::timeval {
tv_sec: 0,
tv_usec: 0,
}; unsafe { let r = c::gettimeofday(&mut tv, null_mut());
assert_eq!(r, 0);
}
c::timespec {
tv_sec: tv.tv_sec,
tv_nsec: (tv.tv_usec * 1000) as _,
}
}; if times.last_access.tv_nsec == c::UTIME_NOW.into() {
times.last_access = crate::timespec::Timespec {
tv_sec: now.tv_sec.into(),
tv_nsec: now.tv_nsec as _,
};
} if times.last_modification.tv_nsec == c::UTIME_NOW.into() {
times.last_modification = crate::timespec::Timespec {
tv_sec: now.tv_sec.into(),
tv_nsec: now.tv_nsec as _,
};
}
}
#[cfg(apple)]
{ // Passing an empty to slice to `getxattr` leads to `ERANGE` on macOS. // Pass null instead. let ptr = if value.1 == 0 {
core::ptr::null_mut()
} else {
value.0.cast::<c::c_void>()
};
// Assert that `Timestamps` has the expected layout. If we're not fixing // y2038, libc's type should match ours. If we are, it's smaller. #[cfg(not(fix_y2038))]
assert_eq_size!([c::timespec; 2], Timestamps); #[cfg(fix_y2038)]
assert!(core::mem::size_of::<[c::timespec; 2]>() < core::mem::size_of::<Timestamps>());
}
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.69Bemerkung:
(vorverarbeitet am 2026-10-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Angebot
Hier finden Sie eine Liste der Produkte des Unternehmens