readfilez/
backend.rs

1use crate::{get_file_len, FileHandle, FileHandle::*, LengthSpec};
2use std::{
3    fs::File,
4    io::{self, Read, Seek},
5};
6
7// private interface
8
9fn open_as_mmap(fh: &File, offset: u64, len: usize) -> io::Result<memmap2::Mmap> {
10    unsafe {
11        memmap2::MmapOptions::new()
12            .offset(offset)
13            .len(len)
14            .map_copy_read_only(fh)
15    }
16}
17
18/// Reads a part of the file contents,
19/// use this if the file is too big and needs to be read in parts,
20/// starting at [`offset`] and until the given LengthSpec is met.
21///
22/// @param flen_hint : used to cache the call to [`get_file_len`]
23pub(crate) fn read_part_from_file_intern(
24    fh: &mut File,
25    offset: u64,
26    lenspec: LengthSpec,
27    flen_hint: Option<u64>,
28) -> io::Result<FileHandle> {
29    // evaluate file length
30    let evl: Option<usize> = {
31        let maxlen_i = std::isize::MAX as usize;
32
33        if lenspec.is_exact && lenspec.bound.map(|len| len > maxlen_i) == Some(true) {
34            return Err(io::Error::new(
35                io::ErrorKind::InvalidInput,
36                "length is too big",
37            ));
38        }
39
40        [
41            lenspec.bound,
42            flen_hint
43                .or_else(|| get_file_len(fh))
44                .map(|lx| (lx - offset) as usize),
45        ]
46        .iter()
47        .flatten()
48        .min()
49        .and_then(|&mxl| if mxl < maxlen_i { Some(mxl) } else { None })
50    };
51
52    // check common cases
53    match evl {
54        Some(0) => {
55            return Ok(Buffered(Vec::new().into()));
56        }
57        Some(lx) => {
58            // do NOT try to map the file if the size is unknown
59            if let Ok(ret) = open_as_mmap(fh, offset, lx) {
60                return Ok(Mapped(ret));
61            }
62        }
63        None => {}
64    }
65
66    // use Buffered as fallback
67    fh.seek(io::SeekFrom::Start(offset))?;
68    let contents = match evl {
69        Some(0) => Vec::new(),
70        Some(lx) => {
71            let mut contents = core::iter::repeat(0u8).take(lx).collect::<Vec<_>>();
72            if lenspec.is_exact {
73                fh.read_exact(&mut contents)?;
74            } else {
75                let bcnt = fh.read(&mut contents)?;
76                contents.truncate(bcnt);
77            }
78            contents
79        }
80        None => {
81            let mut contents = Vec::new();
82            if let Err(x) = fh.read_to_end(&mut contents) {
83                if lenspec.is_exact || contents.is_empty() {
84                    return Err(x);
85                }
86            }
87            contents
88        }
89    };
90    Ok(Buffered(contents.into_boxed_slice()))
91}
92
93#[inline]
94pub(crate) fn do_offset_add(offset: u64, x: i64) -> Option<u64> {
95    if x < 0 {
96        let xn = (-x) as u64;
97        if xn <= offset {
98            Some(offset - xn)
99        } else {
100            None
101        }
102    } else {
103        Some(offset + (x as u64))
104    }
105}