Add Item
struct, which contains both a tar::Node
and a plist entry.
This struct can be created from just a `Path` parameter, allowing to read the data contained in a file only once during package creation or extraction.
This commit is contained in:
parent
4f44290a48
commit
85a85a3810
53
src/item/mod.rs
Normal file
53
src/item/mod.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use crate::Entry;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{error::Error, fmt::Write, fs, path::{Path, PathBuf}, io::Read, os::unix::fs::MetadataExt};
|
||||
use tar::{Node, Owner};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Item {
|
||||
pub entry: Entry,
|
||||
pub node: Node,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn try_create(path: &Path) -> Result<Self, Box<dyn Error>> {
|
||||
let meta = fs::metadata(path)?;
|
||||
let filename = format!("/{}", path.display());
|
||||
let owner = Some(Owner::default());
|
||||
if meta.is_file() {
|
||||
let mut data = vec![];
|
||||
let mut fd = fs::File::open(path)?;
|
||||
let path = PathBuf::from(&filename);
|
||||
let size = fd.read_to_end(&mut data)?;
|
||||
let mut sha256sum = String::new();
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&data);
|
||||
let res = hasher.finalize();
|
||||
for c in res {
|
||||
write!(sha256sum, "{c:02x}")?;
|
||||
}
|
||||
let node = Node::read_data_to_tar(&data, &filename, &meta, owner)?;
|
||||
let mode = meta.mode();
|
||||
Ok(Self {
|
||||
entry: Entry::File { path, sha256sum, mode, size },
|
||||
node,
|
||||
})
|
||||
} else if meta.is_dir() {
|
||||
let mode = meta.mode();
|
||||
let path = PathBuf::from(&filename);
|
||||
Ok(Self {
|
||||
entry: Entry::Directory { path, mode },
|
||||
node: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?,
|
||||
})
|
||||
} else if meta.is_symlink() {
|
||||
let target = fs::read_link(path)?;
|
||||
let path = PathBuf::from(&filename);
|
||||
Ok(Self {
|
||||
entry: Entry::Link { path, target },
|
||||
node: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?,
|
||||
})
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
mod item;
|
||||
mod package;
|
||||
mod plist;
|
||||
mod version;
|
||||
pub use {
|
||||
item::Item,
|
||||
package::{Dependency, Package},
|
||||
plist::*,
|
||||
version::*,
|
||||
|
@ -4,7 +4,7 @@ use {
|
||||
serde::{Deserialize, Serialize},
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Dependency {
|
||||
name: String,
|
||||
version: (Option<Version>, Option<Version>),
|
||||
|
@ -5,7 +5,19 @@ use {
|
||||
serde::{Deserialize, Serialize},
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct User {
|
||||
pub name: String,
|
||||
pub uid: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Group {
|
||||
pub name: String,
|
||||
pub gid: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Package {
|
||||
name: String,
|
||||
version: Version,
|
||||
@ -13,4 +25,6 @@ pub struct Package {
|
||||
plist: Plist,
|
||||
size: usize,
|
||||
dependencies: Vec<Dependency>,
|
||||
users: Option<Vec<User>>,
|
||||
groups: Option<Vec<Group>>,
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use {
|
||||
walkdir::WalkDir,
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Plist {
|
||||
pub entries: Vec<Entry>,
|
||||
}
|
||||
@ -35,7 +35,7 @@ impl TryFrom<&Path> for Plist {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Entry {
|
||||
File {
|
||||
path: PathBuf,
|
||||
@ -89,3 +89,4 @@ impl TryFrom<&Path> for Entry {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct GitRev {
|
||||
hash: String,
|
||||
datetime: u64,
|
||||
|
@ -5,7 +5,7 @@ mod semver;
|
||||
|
||||
pub use {gitrev::GitRev, semver::SemVer};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Version {
|
||||
Number(u32),
|
||||
SemVer(SemVer),
|
||||
|
@ -3,7 +3,7 @@ use {
|
||||
std::cmp::Ordering,
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct SemVer {
|
||||
pub major: u32,
|
||||
pub minor: u32,
|
||||
|
@ -244,7 +244,11 @@ impl Header {
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
pub fn new_from_meta(filename: &str, meta: &Metadata, owner: Option<Owner>) -> Result<Self, Error> {
|
||||
pub fn new_from_meta(
|
||||
filename: &str,
|
||||
meta: &Metadata,
|
||||
owner: Option<Owner>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut header = Header::default();
|
||||
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
|
||||
let mode = format!("{:07o}", meta.st_mode());
|
||||
@ -256,7 +260,7 @@ impl Header {
|
||||
gid: meta.st_gid(),
|
||||
username: get_username_for_uid(meta.st_uid())?.into(),
|
||||
groupname: get_groupname_for_gid(meta.st_gid())?.into(),
|
||||
}
|
||||
},
|
||||
};
|
||||
let uid = format!("{:07o}", owner.uid);
|
||||
header.uid[..uid.len()].copy_from_slice(uid.as_bytes());
|
||||
@ -365,4 +369,3 @@ pub fn get_groupname_for_gid<'a>(gid: u32) -> Result<&'a str, std::str::Utf8Erro
|
||||
};
|
||||
group.to_str()
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ mod header;
|
||||
mod node;
|
||||
pub use {
|
||||
error::Error,
|
||||
header::{FileType, Header},
|
||||
header::{FileType, Header, Owner},
|
||||
node::Node,
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{Error, FileType, Header, header::Owner};
|
||||
use crate::{header::Owner, Error, FileType, Header};
|
||||
use deku::prelude::*;
|
||||
use std::{
|
||||
fs::{File, Metadata},
|
||||
@ -67,7 +67,12 @@ impl Node {
|
||||
}
|
||||
|
||||
/// Create a Node from in memory data, given the filename and metadata
|
||||
pub fn read_data_to_tar(data: &[u8], filename: &str, meta: &Metadata, owner: Option<Owner>) -> Result<Node, Error> {
|
||||
pub fn read_data_to_tar(
|
||||
data: &[u8],
|
||||
filename: &str,
|
||||
meta: &Metadata,
|
||||
owner: Option<Owner>,
|
||||
) -> Result<Node, Error> {
|
||||
let header = Header::new_from_meta(filename, meta, owner)?;
|
||||
if header.link_indicator[0] != FileType::Normal as u8 {
|
||||
return Ok(Node {
|
||||
|
Loading…
Reference in New Issue
Block a user