1//! Tests for extreme `u64` file offsets.
2//!
3//! POSIX-ish interfaces tend to use signed integers for file offsets, while
4//! Rust APIs tend to use `u64`. Test that extreme `u64` values in APIs that
5//! take file offsets are properly diagnosed.
6//!
7//! These tests are disabled on ios/macos since those platforms kill the
8//! process with `SIGXFSZ` instead of returning an error.
9
10#![cfg(not(any(target_os = "redox", target_os = "wasi")))]
11
12use rustix::io::SeekFrom;
13
14#[test]
15fn invalid_offset_seek() {
16    use rustix::fs::{cwd, openat, seek, Mode, OFlags};
17    let tmp = tempfile::tempdir().unwrap();
18    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
19    let file = openat(
20        &dir,
21        "foo",
22        OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE,
23        Mode::RUSR | Mode::WUSR,
24    )
25    .unwrap();
26
27    seek(&file, SeekFrom::Start(u64::MAX)).unwrap_err();
28    seek(&file, SeekFrom::Start(i64::MAX as u64 + 1)).unwrap_err();
29    seek(&file, SeekFrom::End(-1)).unwrap_err();
30    seek(&file, SeekFrom::End(i64::MIN)).unwrap_err();
31    seek(&file, SeekFrom::Current(-1)).unwrap_err();
32    seek(&file, SeekFrom::Current(i64::MIN)).unwrap_err();
33}
34
35#[cfg(not(any(
36    target_os = "dragonfly",
37    target_os = "illumos",
38    target_os = "netbsd",
39    target_os = "openbsd",
40    target_os = "redox",
41    target_os = "solaris",
42)))]
43#[test]
44fn invalid_offset_fallocate() {
45    use rustix::fs::{cwd, fallocate, openat, FallocateFlags, Mode, OFlags};
46    let tmp = tempfile::tempdir().unwrap();
47    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
48    let file = openat(
49        &dir,
50        "foo",
51        OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE,
52        Mode::RUSR | Mode::WUSR,
53    )
54    .unwrap();
55
56    fallocate(&file, FallocateFlags::empty(), u64::MAX, 1).unwrap_err();
57    fallocate(&file, FallocateFlags::empty(), i64::MAX as u64 + 1, 1).unwrap_err();
58    fallocate(&file, FallocateFlags::empty(), 0, u64::MAX).unwrap_err();
59    fallocate(&file, FallocateFlags::empty(), 0, i64::MAX as u64 + 1).unwrap_err();
60}
61
62#[cfg(not(any(
63    target_os = "dragonfly",
64    target_os = "haiku",
65    target_os = "illumos",
66    target_os = "ios",
67    target_os = "macos",
68    target_os = "netbsd",
69    target_os = "openbsd",
70    target_os = "redox",
71    target_os = "solaris",
72)))]
73#[test]
74fn invalid_offset_fadvise() {
75    use rustix::fs::{cwd, fadvise, openat, Advice, Mode, OFlags};
76    let tmp = tempfile::tempdir().unwrap();
77    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
78    let file = openat(
79        &dir,
80        "foo",
81        OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE,
82        Mode::RUSR | Mode::WUSR,
83    )
84    .unwrap();
85
86    // `fadvise` never fails on invalid offsets.
87    fadvise(&file, i64::MAX as u64, i64::MAX as u64, Advice::Normal).unwrap();
88    fadvise(&file, u64::MAX, 0, Advice::Normal).unwrap();
89    fadvise(&file, i64::MAX as u64, 1, Advice::Normal).unwrap();
90    fadvise(&file, 1, i64::MAX as u64, Advice::Normal).unwrap();
91    fadvise(&file, i64::MAX as u64 + 1, 0, Advice::Normal).unwrap();
92    fadvise(&file, u64::MAX, i64::MAX as u64, Advice::Normal).unwrap();
93
94    // `fadvise` fails on invalid lengths.
95    fadvise(&file, u64::MAX, u64::MAX, Advice::Normal).unwrap_err();
96    fadvise(&file, i64::MAX as u64, u64::MAX, Advice::Normal).unwrap_err();
97    fadvise(&file, 0, u64::MAX, Advice::Normal).unwrap_err();
98    fadvise(&file, u64::MAX, i64::MAX as u64 + 1, Advice::Normal).unwrap_err();
99    fadvise(&file, i64::MAX as u64 + 1, u64::MAX, Advice::Normal).unwrap_err();
100    fadvise(&file, i64::MAX as u64, i64::MAX as u64 + 1, Advice::Normal).unwrap_err();
101    fadvise(&file, 0, i64::MAX as u64 + 1, Advice::Normal).unwrap_err();
102}
103
104#[test]
105fn invalid_offset_pread() {
106    use rustix::fs::{cwd, openat, Mode, OFlags};
107    use rustix::io::pread;
108    let tmp = tempfile::tempdir().unwrap();
109    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
110    let file = openat(
111        &dir,
112        "foo",
113        OFlags::RDWR | OFlags::TRUNC | OFlags::CREATE,
114        Mode::RUSR | Mode::WUSR,
115    )
116    .unwrap();
117
118    let mut buf = [0_u8; 1];
119    pread(&file, &mut buf, u64::MAX).unwrap_err();
120    pread(&file, &mut buf, i64::MAX as u64 + 1).unwrap_err();
121}
122
123#[cfg(not(any(target_os = "ios", target_os = "macos")))]
124#[test]
125fn invalid_offset_pwrite() {
126    use rustix::fs::{cwd, openat, Mode, OFlags};
127    use rustix::io::pwrite;
128    let tmp = tempfile::tempdir().unwrap();
129    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
130    let file = openat(
131        &dir,
132        "foo",
133        OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE,
134        Mode::RUSR | Mode::WUSR,
135    )
136    .unwrap();
137
138    let buf = [0_u8; 1];
139    pwrite(&file, &buf, u64::MAX).unwrap_err();
140    pwrite(&file, &buf, i64::MAX as u64 + 1).unwrap_err();
141}
142
143#[cfg(any(target_os = "android", target_os = "linux"))]
144#[test]
145fn invalid_offset_copy_file_range() {
146    use rustix::fs::{copy_file_range, cwd, openat, Mode, OFlags};
147    use rustix::io::write;
148    let tmp = tempfile::tempdir().unwrap();
149    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
150    let foo = openat(
151        &dir,
152        "foo",
153        OFlags::RDWR | OFlags::TRUNC | OFlags::CREATE,
154        Mode::RUSR | Mode::WUSR,
155    )
156    .unwrap();
157    let bar = openat(
158        &dir,
159        "bar",
160        OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE,
161        Mode::RUSR | Mode::WUSR,
162    )
163    .unwrap();
164    write(&foo, b"a").unwrap();
165
166    let mut off_in = u64::MAX;
167    let mut off_out = 0;
168    copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err();
169
170    let mut off_in = i64::MAX as u64 + 1;
171    let mut off_out = 0;
172    copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err();
173
174    let mut off_in = 0;
175    let mut off_out = u64::MAX;
176    copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err();
177
178    let mut off_in = 0;
179    let mut off_out = i64::MAX as u64;
180    copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err();
181
182    let mut off_in = 0;
183    let mut off_out = i64::MAX as u64 + 1;
184    copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err();
185}
186