coreutils_rs/common/
io.rs1use std::fs::{self, File};
2use std::io::{self, Read};
3use std::ops::Deref;
4use std::path::Path;
5
6use memmap2::{Mmap, MmapOptions};
7
8pub enum FileData {
11 Mmap(Mmap),
12 Owned(Vec<u8>),
13}
14
15impl Deref for FileData {
16 type Target = [u8];
17
18 fn deref(&self) -> &[u8] {
19 match self {
20 FileData::Mmap(m) => m,
21 FileData::Owned(v) => v,
22 }
23 }
24}
25
26const MMAP_THRESHOLD: u64 = 256 * 1024;
30
31#[cfg(target_os = "linux")]
34fn open_noatime(path: &Path) -> io::Result<File> {
35 use std::os::unix::fs::OpenOptionsExt;
36 match fs::OpenOptions::new()
38 .read(true)
39 .custom_flags(libc::O_NOATIME)
40 .open(path)
41 {
42 Ok(f) => Ok(f),
43 Err(_) => File::open(path),
44 }
45}
46
47#[cfg(not(target_os = "linux"))]
48fn open_noatime(path: &Path) -> io::Result<File> {
49 File::open(path)
50}
51
52pub fn read_file(path: &Path) -> io::Result<FileData> {
55 let file = open_noatime(path)?;
56 let metadata = file.metadata()?;
57 let len = metadata.len();
58
59 if len > 0 && metadata.file_type().is_file() {
60 if len < MMAP_THRESHOLD {
62 let mut buf = Vec::with_capacity(len as usize);
63 let mut reader = file;
64 reader.read_to_end(&mut buf)?;
65 return Ok(FileData::Owned(buf));
66 }
67
68 match unsafe { MmapOptions::new().map(&file) } {
72 Ok(mmap) => {
73 #[cfg(target_os = "linux")]
74 {
75 let _ = mmap.advise(memmap2::Advice::Sequential);
76 unsafe {
78 libc::madvise(
79 mmap.as_ptr() as *mut libc::c_void,
80 mmap.len(),
81 libc::MADV_WILLNEED,
82 );
83 }
84 if len >= 2 * 1024 * 1024 {
85 unsafe {
86 libc::madvise(
87 mmap.as_ptr() as *mut libc::c_void,
88 mmap.len(),
89 libc::MADV_HUGEPAGE,
90 );
91 }
92 }
93 }
94 Ok(FileData::Mmap(mmap))
95 }
96 Err(_) => {
97 let mut buf = Vec::with_capacity(len as usize);
99 let mut reader = file;
100 reader.read_to_end(&mut buf)?;
101 Ok(FileData::Owned(buf))
102 }
103 }
104 } else if len > 0 {
105 let mut buf = Vec::new();
107 let mut reader = file;
108 reader.read_to_end(&mut buf)?;
109 Ok(FileData::Owned(buf))
110 } else {
111 Ok(FileData::Owned(Vec::new()))
112 }
113}
114
115pub fn file_size(path: &Path) -> io::Result<u64> {
117 Ok(fs::metadata(path)?.len())
118}
119
120pub fn read_stdin() -> io::Result<Vec<u8>> {
122 let mut buf = Vec::new();
123 io::stdin().lock().read_to_end(&mut buf)?;
124 Ok(buf)
125}