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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! # sqlar - an SQLite Archive utility
//!
//! > An "SQLite Archive" is a file container similar to a ZIP archive or Tarball but based on an SQLite database.
//!
//! See the [SQLite Archive Files][sqlar] documentation for all information.
//!
//! This library allows to list archive contents, extract files from archives or create a new
//! archive.
//! It's main usage is throug the command line utility `sqlar`.
//!
//! # Installation
//!
//! The command line utility `sqlar` can be installed through `cargo`:
//!
//! ```text
//! cargo install sqlar
//! ```
//!
//! # Usage
//!
//! ## List the content of an archive
//!
//! ```text
//! sqlar l path/to/file.sqlar
//! ```
//!
//! ## Extract an archive
//!
//! ```text
//! sqlar x path/to/file.sqlar path/to/dest/
//! ```
//!
//! ## Create an archive
//!
//! ```text
//! sqlar c path/to/new-archive.sqlar path/to/source/
//! ```
//!
//! # Example
//!
//! The library can also be used progamatically.
//!
//! ## List files in an archive
//!
//! ```rust,no_run
//! use sqlar::with_each_entry;
//!
//! with_each_entry("path/to/archive.sqlar", false, |entry| {
//!    println!("File: {}, file type: {:?}, mode: {}", entry.name, entry.filetype, entry.mode);
//!    Ok(())
//! });
//! ```
//!
//! ## Create an archive
//!
//! ```rust,no_run
//! use sqlar::create;
//!
//! create("path/to/new-archive.sqlar", &["path/to/source"]);
//! ```
//!
//! ## Extract all files from an archive
//!
//! ```rust,no_run
//! use sqlar::extract;
//!
//! extract("path/to/archive.sqlar", "path/to/dest");
//! ```
//!
//! [sqlar]: https://www.sqlite.org/sqlar.html

use std::fs;

pub use rusqlite::Result;

mod compress;
mod create;
mod extract;
mod list;

pub use create::create;
pub use extract::extract;
pub use list::with_each_entry;

/// A file entry in the archive
#[derive(Debug, Clone)]
pub struct Entry {
    /// Name of the file
    pub name: String,
    /// Access permissions
    pub mode: u32,
    /// Either a file or directory.
    /// Other file types are unsupported and will not be created or extracted.
    pub filetype: FileType,
    /// Last modification time
    pub mtime: i64,
    /// Original file size
    pub size: usize,
    /// Compressed file size
    pub compressed_size: usize,
    /// Uncompressed content
    pub data: Option<Vec<u8>>,
}

/// A file's type
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum FileType {
    /// Regular file
    File,
    /// Directory
    Dir,
    /// Other file types are not supported
    Unsupported,
}

// `stat.st_mode` values
// via https://man7.org/linux/man-pages/man7/inode.7.html
/// bit mask for the file type bit field
const S_IFMT: u32 = 0o0170000;
/// regular file
const S_IFREG: u32 = 0o0100000;
/// directory
const S_IFDIR: u32 = 0o0040000;

impl From<u32> for FileType {
    fn from(mode: u32) -> FileType {
        if mode & S_IFMT == S_IFREG {
            return FileType::File;
        }
        if mode & S_IFMT == S_IFDIR {
            return FileType::Dir;
        }

        FileType::Unsupported
    }
}

impl From<fs::FileType> for FileType {
    fn from(ft: fs::FileType) -> FileType {
        if ft.is_file() {
            return FileType::File;
        }
        if ft.is_dir() {
            return FileType::Dir;
        }
        FileType::Unsupported
    }
}