Skip to main content

tectonic_bundles/
dir.rs

1// Copyright 2017-2021 the Tectonic Project
2// Licensed under the MIT License.
3
4//! A module for the directory bundle [`DirBundle`].
5
6use std::{
7    fs,
8    io::Read,
9    path::{Path, PathBuf},
10    str::FromStr,
11};
12use tectonic_errors::prelude::*;
13use tectonic_io_base::{digest, filesystem::FilesystemIo, InputHandle, IoProvider, OpenResult};
14use tectonic_status_base::{NoopStatusBackend, StatusBackend};
15
16use super::Bundle;
17
18/// A "bundle" of a bunch of files in a directory.
19///
20/// This implementation essentially just wraps
21/// [`tectonic_io_base::filesystem::FilesystemIo`], ensuring that it is
22/// read-only, self-contained, and implements the [`Bundle`] trait. The
23/// directory should contain a file named `SHA256SUM` if the bundle fingerprint
24/// will be needed.
25pub struct DirBundle(FilesystemIo);
26
27impl DirBundle {
28    /// Create a new directory bundle.
29    ///
30    /// No validation of the input path is performed, which is why this function
31    /// is infallible.
32    pub fn new<P: AsRef<Path>>(dir: P) -> DirBundle {
33        DirBundle(FilesystemIo::new(
34            dir.as_ref(),
35            false,              // no writes
36            false,              // no absolute paths
37            Default::default(), // no hidden files
38        ))
39    }
40}
41
42impl IoProvider for DirBundle {
43    fn input_open_name(
44        &mut self,
45        name: &str,
46        status: &mut dyn StatusBackend,
47    ) -> OpenResult<InputHandle> {
48        self.0.input_open_name(name, status)
49    }
50
51    fn input_open_name_with_abspath(
52        &mut self,
53        name: &str,
54        status: &mut dyn StatusBackend,
55    ) -> OpenResult<(InputHandle, Option<PathBuf>)> {
56        self.0.input_open_name_with_abspath(name, status)
57    }
58}
59
60impl Bundle for DirBundle {
61    fn all_files(&self) -> Vec<String> {
62        fs::read_dir(self.0.root())
63            .unwrap()
64            .filter_map(|x| x.ok())
65            .filter(|x| !x.file_type().map(|x| x.is_dir()).unwrap_or(false))
66            .map(|x| x.file_name().to_str().unwrap_or("").to_owned())
67            .filter(|x| !x.is_empty())
68            .collect()
69    }
70
71    fn get_digest(&mut self) -> Result<tectonic_io_base::digest::DigestData> {
72        let digest_text = match self.input_open_name(digest::DIGEST_NAME, &mut NoopStatusBackend {})
73        {
74            OpenResult::Ok(h) => {
75                let mut text = String::new();
76                h.take(64).read_to_string(&mut text)?;
77                text
78            }
79
80            OpenResult::NotAvailable => {
81                bail!("bundle does not provide needed SHA256SUM file");
82            }
83
84            OpenResult::Err(e) => {
85                return Err(e);
86            }
87        };
88
89        Ok(atry!(digest::DigestData::from_str(&digest_text); ["corrupted SHA256 digest data"]))
90    }
91}