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)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
mod item;
|
||||||
mod package;
|
mod package;
|
||||||
mod plist;
|
mod plist;
|
||||||
mod version;
|
mod version;
|
||||||
pub use {
|
pub use {
|
||||||
|
item::Item,
|
||||||
package::{Dependency, Package},
|
package::{Dependency, Package},
|
||||||
plist::*,
|
plist::*,
|
||||||
version::*,
|
version::*,
|
||||||
|
@ -4,7 +4,7 @@ use {
|
|||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Dependency {
|
pub struct Dependency {
|
||||||
name: String,
|
name: String,
|
||||||
version: (Option<Version>, Option<Version>),
|
version: (Option<Version>, Option<Version>),
|
||||||
|
@ -5,7 +5,19 @@ use {
|
|||||||
serde::{Deserialize, Serialize},
|
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 {
|
pub struct Package {
|
||||||
name: String,
|
name: String,
|
||||||
version: Version,
|
version: Version,
|
||||||
@ -13,4 +25,6 @@ pub struct Package {
|
|||||||
plist: Plist,
|
plist: Plist,
|
||||||
size: usize,
|
size: usize,
|
||||||
dependencies: Vec<Dependency>,
|
dependencies: Vec<Dependency>,
|
||||||
|
users: Option<Vec<User>>,
|
||||||
|
groups: Option<Vec<Group>>,
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use {
|
|||||||
walkdir::WalkDir,
|
walkdir::WalkDir,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Plist {
|
pub struct Plist {
|
||||||
pub entries: Vec<Entry>,
|
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 {
|
pub enum Entry {
|
||||||
File {
|
File {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
@ -89,3 +89,4 @@ impl TryFrom<&Path> for Entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct GitRev {
|
pub struct GitRev {
|
||||||
hash: String,
|
hash: String,
|
||||||
datetime: u64,
|
datetime: u64,
|
||||||
|
@ -5,7 +5,7 @@ mod semver;
|
|||||||
|
|
||||||
pub use {gitrev::GitRev, semver::SemVer};
|
pub use {gitrev::GitRev, semver::SemVer};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum Version {
|
pub enum Version {
|
||||||
Number(u32),
|
Number(u32),
|
||||||
SemVer(SemVer),
|
SemVer(SemVer),
|
||||||
|
@ -3,7 +3,7 @@ use {
|
|||||||
std::cmp::Ordering,
|
std::cmp::Ordering,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct SemVer {
|
pub struct SemVer {
|
||||||
pub major: u32,
|
pub major: u32,
|
||||||
pub minor: u32,
|
pub minor: u32,
|
||||||
|
@ -244,7 +244,11 @@ impl Header {
|
|||||||
Ok(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();
|
let mut header = Header::default();
|
||||||
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
|
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
|
||||||
let mode = format!("{:07o}", meta.st_mode());
|
let mode = format!("{:07o}", meta.st_mode());
|
||||||
@ -256,7 +260,7 @@ impl Header {
|
|||||||
gid: meta.st_gid(),
|
gid: meta.st_gid(),
|
||||||
username: get_username_for_uid(meta.st_uid())?.into(),
|
username: get_username_for_uid(meta.st_uid())?.into(),
|
||||||
groupname: get_groupname_for_gid(meta.st_gid())?.into(),
|
groupname: get_groupname_for_gid(meta.st_gid())?.into(),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let uid = format!("{:07o}", owner.uid);
|
let uid = format!("{:07o}", owner.uid);
|
||||||
header.uid[..uid.len()].copy_from_slice(uid.as_bytes());
|
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()
|
group.to_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ mod header;
|
|||||||
mod node;
|
mod node;
|
||||||
pub use {
|
pub use {
|
||||||
error::Error,
|
error::Error,
|
||||||
header::{FileType, Header},
|
header::{FileType, Header, Owner},
|
||||||
node::Node,
|
node::Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{Error, FileType, Header, header::Owner};
|
use crate::{header::Owner, Error, FileType, Header};
|
||||||
use deku::prelude::*;
|
use deku::prelude::*;
|
||||||
use std::{
|
use std::{
|
||||||
fs::{File, Metadata},
|
fs::{File, Metadata},
|
||||||
@ -67,7 +67,12 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a Node from in memory data, given the filename and metadata
|
/// 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)?;
|
let header = Header::new_from_meta(filename, meta, owner)?;
|
||||||
if header.link_indicator[0] != FileType::Normal as u8 {
|
if header.link_indicator[0] != FileType::Normal as u8 {
|
||||||
return Ok(Node {
|
return Ok(Node {
|
||||||
|
Loading…
Reference in New Issue
Block a user