1#[cfg(feature = "fs")]
2use std::io::{IoSlice, IoSliceMut};
3
4#[cfg(feature = "fs")]
5#[cfg(not(target_os = "solaris"))] // no preadv/pwritev
6#[cfg(not(target_os = "haiku"))] // no preadv/pwritev
7#[test]
8fn test_readwrite_pv() {
9    use rustix::fs::{cwd, openat, Mode, OFlags};
10    use rustix::io::{preadv, pwritev};
11
12    let tmp = tempfile::tempdir().unwrap();
13    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
14    let foo = openat(
15        &dir,
16        "foo",
17        OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC,
18        Mode::RUSR | Mode::WUSR,
19    )
20    .unwrap();
21
22    // For most targets, just call `pwritev`.
23    #[cfg(not(any(target_os = "ios", target_os = "macos")))]
24    {
25        pwritev(&foo, &[IoSlice::new(b"hello")], 200).unwrap();
26    }
27    // macOS only has pwritev in newer versions; allow it to fail with `ENOSYS`.
28    #[cfg(any(target_os = "ios", target_os = "macos"))]
29    {
30        match pwritev(&foo, &[IoSlice::new(b"hello")], 200) {
31            Ok(_) => (),
32            Err(rustix::io::Errno::NOSYS) => return,
33            Err(err) => Err(err).unwrap(),
34        }
35    }
36    pwritev(&foo, &[IoSlice::new(b"world")], 300).unwrap();
37    let mut buf = [0_u8; 5];
38    preadv(&foo, &mut [IoSliceMut::new(&mut buf)], 200).unwrap();
39    assert_eq!(&buf, b"hello");
40    preadv(&foo, &mut [IoSliceMut::new(&mut buf)], 300).unwrap();
41    assert_eq!(&buf, b"world");
42}
43
44#[cfg(feature = "fs")]
45#[test]
46fn test_readwrite_p() {
47    use rustix::fs::{cwd, openat, Mode, OFlags};
48    use rustix::io::{pread, pwrite};
49
50    let tmp = tempfile::tempdir().unwrap();
51    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
52    let foo = openat(
53        &dir,
54        "foo",
55        OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC,
56        Mode::RUSR | Mode::WUSR,
57    )
58    .unwrap();
59
60    pwrite(&foo, b"hello", 200).unwrap();
61    pwrite(&foo, b"world", 300).unwrap();
62    let mut buf = [0_u8; 5];
63    pread(&foo, &mut buf, 200).unwrap();
64    assert_eq!(&buf, b"hello");
65    pread(&foo, &mut buf, 300).unwrap();
66    assert_eq!(&buf, b"world");
67}
68
69#[cfg(feature = "fs")]
70#[test]
71fn test_readwrite_v() {
72    use rustix::fs::{cwd, openat, seek, Mode, OFlags};
73    use rustix::io::{readv, writev, SeekFrom};
74
75    let tmp = tempfile::tempdir().unwrap();
76    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
77    let foo = openat(
78        &dir,
79        "foo",
80        OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC,
81        Mode::RUSR | Mode::WUSR,
82    )
83    .unwrap();
84
85    writev(&foo, &[IoSlice::new(b"hello")]).unwrap();
86    writev(&foo, &[IoSlice::new(b"world")]).unwrap();
87    seek(&foo, SeekFrom::Start(0)).unwrap();
88    let mut buf = [0_u8; 5];
89    readv(&foo, &mut [IoSliceMut::new(&mut buf)]).unwrap();
90    assert_eq!(&buf, b"hello");
91    readv(&foo, &mut [IoSliceMut::new(&mut buf)]).unwrap();
92    assert_eq!(&buf, b"world");
93}
94
95#[cfg(feature = "fs")]
96#[test]
97fn test_readwrite() {
98    use rustix::fs::{cwd, openat, seek, Mode, OFlags};
99    use rustix::io::{read, write};
100    use std::io::SeekFrom;
101
102    let tmp = tempfile::tempdir().unwrap();
103    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
104    let foo = openat(
105        &dir,
106        "foo",
107        OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC,
108        Mode::RUSR | Mode::WUSR,
109    )
110    .unwrap();
111
112    write(&foo, b"hello").unwrap();
113    write(&foo, b"world").unwrap();
114    seek(&foo, SeekFrom::Start(0)).unwrap();
115    let mut buf = [0_u8; 5];
116    read(&foo, &mut buf).unwrap();
117    assert_eq!(&buf, b"hello");
118    read(&foo, &mut buf).unwrap();
119    assert_eq!(&buf, b"world");
120}
121
122#[cfg(all(target_os = "linux", target_env = "gnu"))]
123#[test]
124fn test_rwf_values() {
125    // We use the kernel's values for these flags; check that libc doesn't
126    // have different values.
127    assert_eq!(
128        rustix::io::ReadWriteFlags::APPEND.bits() as i32,
129        libc::RWF_APPEND
130    );
131    assert_eq!(
132        rustix::io::ReadWriteFlags::DSYNC.bits() as i32,
133        libc::RWF_DSYNC
134    );
135    assert_eq!(
136        rustix::io::ReadWriteFlags::HIPRI.bits() as i32,
137        libc::RWF_HIPRI
138    );
139    assert_eq!(
140        rustix::io::ReadWriteFlags::NOWAIT.bits() as i32,
141        libc::RWF_NOWAIT
142    );
143    assert_eq!(
144        rustix::io::ReadWriteFlags::SYNC.bits() as i32,
145        libc::RWF_SYNC
146    );
147}
148
149#[cfg(any(target_os = "android", target_os = "linux"))]
150#[cfg(feature = "fs")]
151#[test]
152fn test_pwritev2() {
153    use rustix::fs::{cwd, openat, seek, Mode, OFlags};
154    use rustix::io::{preadv2, pwritev2, writev, ReadWriteFlags, SeekFrom};
155
156    let tmp = tempfile::tempdir().unwrap();
157    let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
158    let foo = openat(
159        &dir,
160        "foo",
161        OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC,
162        Mode::RUSR | Mode::WUSR,
163    )
164    .unwrap();
165
166    writev(&foo, &[IoSlice::new(b"hello")]).unwrap();
167    seek(&foo, SeekFrom::Start(0)).unwrap();
168
169    // pwritev2 to append with a 0 offset: don't update the current position.
170    match pwritev2(&foo, &[IoSlice::new(b"world")], 0, ReadWriteFlags::APPEND) {
171        Ok(_) => {}
172        // Skip the rest of the test if we don't have `pwritev2` and `RWF_APPEND`.
173        Err(rustix::io::Errno::NOSYS) | Err(rustix::io::Errno::NOTSUP) => return,
174        Err(err) => Err(err).unwrap(),
175    }
176    assert_eq!(seek(&foo, SeekFrom::Current(0)).unwrap(), 0);
177
178    // pwritev2 to append with a !0 offset: do update the current position.
179    pwritev2(&foo, &[IoSlice::new(b"world")], !0, ReadWriteFlags::APPEND).unwrap();
180    assert_eq!(seek(&foo, SeekFrom::Current(0)).unwrap(), 15);
181
182    seek(&foo, SeekFrom::Start(0)).unwrap();
183    let mut buf = [0_u8; 5];
184    preadv2(
185        &foo,
186        &mut [IoSliceMut::new(&mut buf)],
187        0,
188        ReadWriteFlags::empty(),
189    )
190    .unwrap();
191    assert_eq!(&buf, b"hello");
192    preadv2(
193        &foo,
194        &mut [IoSliceMut::new(&mut buf)],
195        5,
196        ReadWriteFlags::empty(),
197    )
198    .unwrap();
199    assert_eq!(&buf, b"world");
200}
201