1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//!
//! ## squashfs layout
//! >
//! > A squashfs filesystem consists of a maximum of nine parts, packed together on a byte alignment:
//! >
//! ```text
//!  ---------------
//! |  superblock   |
//! |---------------|
//! |  compression  |
//! |    options    |
//! |---------------|
//! |  datablocks   |
//! |  & fragments  |
//! |---------------|
//! |  inode table  |
//! |---------------|
//! |   directory   |
//! |     table     |
//! |---------------|
//! |   fragment    |
//! |    table      |
//! |---------------|
//! |    export     |
//! |    table      |
//! |---------------|
//! |    uid/gid    |
//! |  lookup table |
//! |---------------|
//! |     xattr     |
//! |     table     |
//!  ---------------
//! ```
//!
//! ## References
//! - https://www.kernel.org/doc/Documentation/filesystems/squashfs.txt
//! - https://dr-emann.github.io/squashfs/
//!

#[macro_use]
extern crate bitflags;
// #[macro_use]
// extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate smart_default;
#[macro_use]
extern crate prettytable;
#[macro_use]
extern crate log;

use flexi_logger::{colored_opt_format, Logger};
use std::fs::File;
use std::io::{Read, Result, Seek};

pub mod compress;
pub mod fragment;
pub mod inode;
pub mod layout;
pub mod metadata;
pub mod uidgids;
pub mod utils;
pub mod xattrs;

pub use fragment::*;
pub use inode::*;
pub use layout::*;
pub use log::LevelFilter;
pub use metadata::*;
pub use uidgids::*;
pub use utils::errors::*;
pub use xattrs::*;

pub trait SqsIoRead: Read + Seek {}

pub type SqsIoReader = Box<dyn SqsIoRead>;

impl SqsIoRead for File {}

pub fn set_logging(level: LevelFilter) -> Result<()> {
    Logger::try_with_env_or_str("trace")
        .unwrap()
        .format(colored_opt_format)
        .start()
        .map_err(|e| map_other_error!(e))?;

    log::set_max_level(level);

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::fs::File;
    use std::io::Result;
    use std::sync::Once;

    static TEST_LOGGER_INIT: Once = Once::new();

    pub fn prepare_tests() -> Result<(SqsIoReader, Superblock)> {
        TEST_LOGGER_INIT.call_once(move || {
            if let Ok(level) = env::var("RUST_LOG") {
                if level == "trace" {
                    set_logging(LevelFilter::Trace).unwrap();
                }
            } else {
                set_logging(LevelFilter::Debug).unwrap();
            }
        });

        let test_sqs_file =
            if let Ok(env) = std::env::var("TEST_SQS_FILE").map_err(|e| map_other_error!(e)) {
                env
            } else {
                String::from("tests/data/gzip-sqs")
            };
        let f = File::open(test_sqs_file).map_err(|e| map_error!(e))?;
        let mut reader = Box::new(f.try_clone()?) as SqsIoReader;

        let mut sb = Superblock::new();
        sb.load(&mut reader)?;

        Ok((reader, sb))
    }
}