Extend tar functionality to turn nodes and archives into byte vectors;
Implement package creation using those methods;
This commit is contained in:
parent
318968db4b
commit
ffcd6820d0
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -398,6 +398,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"cli",
|
"cli",
|
||||||
|
"deku",
|
||||||
"rayon",
|
"rayon",
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -15,9 +15,11 @@ path = "src/hpk.rs"
|
|||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
clap = "4.1"
|
clap = "4.1"
|
||||||
|
deku = "0.16"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
|
deku.workspace = true
|
||||||
cli = { path = "cli" }
|
cli = { path = "cli" }
|
||||||
rayon = "1.7"
|
rayon = "1.7"
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
|
@ -20,7 +20,7 @@ impl Hooks {
|
|||||||
match self {
|
match self {
|
||||||
Self::Man => makeinfo(),
|
Self::Man => makeinfo(),
|
||||||
Self::GlibSchema => compile_schemas(),
|
Self::GlibSchema => compile_schemas(),
|
||||||
Self::Info(path) => install_info(&path),
|
Self::Info(path) => install_info(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ use crate::Entry;
|
|||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
|
ffi::OsStr,
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
fs,
|
fs,
|
||||||
io::Read,
|
io::Read,
|
||||||
@ -13,13 +14,14 @@ use tar::{Node, Owner};
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub entry: Entry,
|
pub entry: Entry,
|
||||||
pub node: Node,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
pub fn try_create(path: &Path) -> Result<Self, Box<dyn Error>> {
|
pub fn try_create(path: &Path) -> Result<Self, Box<dyn Error>> {
|
||||||
let meta = fs::metadata(path)?;
|
let path = fix_path(path);
|
||||||
let filename = format!("/{}", path.display());
|
let meta = fs::metadata(&path)?;
|
||||||
|
let filename = format!("{}", path.display());
|
||||||
let owner = Some(Owner::default());
|
let owner = Some(Owner::default());
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
@ -41,24 +43,44 @@ impl Item {
|
|||||||
mode,
|
mode,
|
||||||
size,
|
size,
|
||||||
},
|
},
|
||||||
node: Node::read_data_to_tar(&data, &filename, &meta, owner)?,
|
data: Node::read_data_to_tar(&data, &filename, &meta, owner)?.to_vec()?,
|
||||||
})
|
})
|
||||||
} else if meta.is_dir() {
|
} else if meta.is_dir() {
|
||||||
let mode = meta.mode();
|
let mode = meta.mode();
|
||||||
let path = PathBuf::from(&filename);
|
let path = PathBuf::from(&filename);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entry: Entry::Directory { path, mode },
|
entry: Entry::Directory { path, mode },
|
||||||
node: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?,
|
data: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?.to_vec()?,
|
||||||
})
|
})
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
let target = fs::read_link(path)?;
|
let target = fs::read_link(path)?;
|
||||||
let path = PathBuf::from(&filename);
|
let path = PathBuf::from(&filename);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entry: Entry::Link { path, target },
|
entry: Entry::Link { path, target },
|
||||||
node: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?,
|
data: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?.to_vec()?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fix_path(path: &Path) -> PathBuf {
|
||||||
|
if path.is_file() || path.is_symlink() {
|
||||||
|
match path.ancestors().last().and_then(Path::to_str) {
|
||||||
|
Some("etc" | "var") => {
|
||||||
|
let ext = if let Some(x) = path.extension().and_then(OsStr::to_str) {
|
||||||
|
format!("{x}.new")
|
||||||
|
} else {
|
||||||
|
"new".to_string()
|
||||||
|
};
|
||||||
|
let mut path = path.to_path_buf();
|
||||||
|
path.set_extension(ext);
|
||||||
|
path
|
||||||
|
}
|
||||||
|
_ => path.to_path_buf(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path.to_path_buf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ mod version;
|
|||||||
pub use {
|
pub use {
|
||||||
hooks::Hooks,
|
hooks::Hooks,
|
||||||
item::Item,
|
item::Item,
|
||||||
package::{Dependency, Package, Specs},
|
package::{create as create_package, Dependency, Package, Specs},
|
||||||
plist::*,
|
plist::*,
|
||||||
repository::Repository,
|
repository::Repository,
|
||||||
tar,
|
tar,
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
|
use crate::Item;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use zstd::Encoder;
|
||||||
|
|
||||||
mod dependency;
|
mod dependency;
|
||||||
mod specs;
|
mod specs;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{Plist, Version},
|
crate::{Entry, Plist, Version},
|
||||||
|
rayon::prelude::*,
|
||||||
|
ron::ser::{to_string_pretty, PrettyConfig},
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
|
std::{
|
||||||
|
error::Error,
|
||||||
|
fs::File,
|
||||||
|
io::{BufWriter, Write},
|
||||||
|
path::Path,
|
||||||
|
},
|
||||||
|
tar::Node,
|
||||||
|
walkdir::WalkDir,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use {dependency::Dependency, specs::Specs};
|
pub use {dependency::Dependency, specs::Specs};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
@ -18,7 +34,7 @@ pub struct Group {
|
|||||||
pub gid: Option<u32>,
|
pub gid: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Package {
|
pub struct Package {
|
||||||
/// The name of the package minus all version information
|
/// The name of the package minus all version information
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -48,3 +64,83 @@ pub struct Package {
|
|||||||
/// an optional post installation shell script to be run
|
/// an optional post installation shell script to be run
|
||||||
pub post_install: Option<String>,
|
pub post_install: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Specs> for Package {
|
||||||
|
fn from(value: Specs) -> Self {
|
||||||
|
let mut package = Package::default();
|
||||||
|
package.name = value.name;
|
||||||
|
package.version = value.version;
|
||||||
|
package.release = value.release;
|
||||||
|
package.description = value.description;
|
||||||
|
package.long_description = value.long_description;
|
||||||
|
package.appstream_data = value.appstream_data;
|
||||||
|
package.dependencies = value.dependencies;
|
||||||
|
package.users = value.users;
|
||||||
|
package.groups = value.groups;
|
||||||
|
package.post_install = value.post_install;
|
||||||
|
package
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Package {
|
||||||
|
fn as_ron(&self) -> Result<String, ron::Error> {
|
||||||
|
let cfg = PrettyConfig::new().struct_names(true);
|
||||||
|
to_string_pretty(self, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_ron_and_create_tar_node(&self) -> Result<Node, Box<dyn Error>> {
|
||||||
|
let buf = File::open("package.ron")?;
|
||||||
|
let meta = buf.metadata()?;
|
||||||
|
let s = self.as_ron()?;
|
||||||
|
let mut writer = BufWriter::new(buf);
|
||||||
|
writer.write_all(s.as_bytes())?;
|
||||||
|
let node = Node::read_data_to_tar(s.as_bytes(), "package.ron", &meta, None)?;
|
||||||
|
Ok(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fullname(&self) -> String {
|
||||||
|
format!("{}-{}_{}", self.name, self.version, self.release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(path: &Path, specs: Specs) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut items = WalkDir::new(path)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.par_iter()
|
||||||
|
.filter(|x| x.is_ok())
|
||||||
|
.filter_map(|x| {
|
||||||
|
Item::try_create(x.as_ref().unwrap().path().to_path_buf().as_path()).ok()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut plist = Plist::default();
|
||||||
|
let mut archive = vec![];
|
||||||
|
let mut totalsize = 0;
|
||||||
|
while let Some(item) = items.pop() {
|
||||||
|
match &item.entry {
|
||||||
|
Entry::File {
|
||||||
|
path: _,
|
||||||
|
sha256sum: _,
|
||||||
|
mode: _,
|
||||||
|
size,
|
||||||
|
} => totalsize += size,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
plist.entries.push(item.entry);
|
||||||
|
archive.extend(item.data);
|
||||||
|
}
|
||||||
|
let mut package: Package = specs.into();
|
||||||
|
package.plist = plist;
|
||||||
|
package.size = totalsize;
|
||||||
|
let node = package.save_ron_and_create_tar_node()?.to_vec()?;
|
||||||
|
archive.extend(node);
|
||||||
|
archive.write_all(&[0; 9216])?;
|
||||||
|
let name = package.fullname();
|
||||||
|
let mut path = PathBuf::from(&name);
|
||||||
|
path.set_extension("tar.zst");
|
||||||
|
let fd = File::open(&path)?;
|
||||||
|
let mut writer = Encoder::new(fd, 0)?;
|
||||||
|
writer.write_all(&archive)?;
|
||||||
|
let _fd = writer.finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use {
|
|||||||
crate::{Dependency, Version},
|
crate::{Dependency, Version},
|
||||||
clap::ArgMatches,
|
clap::ArgMatches,
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
std::{env, error::Error},
|
std::{env, error::Error, ffi::OsStr},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
@ -35,34 +35,29 @@ pub struct Specs {
|
|||||||
impl TryFrom<&ArgMatches> for Specs {
|
impl TryFrom<&ArgMatches> for Specs {
|
||||||
type Error = Box<dyn Error>;
|
type Error = Box<dyn Error>;
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
fn try_from(matches: &ArgMatches) -> Result<Self, Self::Error> {
|
fn try_from(matches: &ArgMatches) -> Result<Self, Self::Error> {
|
||||||
let mut specs = Specs::default();
|
let mut specs = Specs::default();
|
||||||
let mut name: Option<String> = None;
|
let mut name: Option<String> = None;
|
||||||
let mut version: Option<Version> = None;
|
let mut version: Option<Version> = None;
|
||||||
let cwd = env::current_dir()?;
|
let cwd = env::current_dir()?;
|
||||||
if let Some(dir) = cwd.file_name() {
|
if let Some(dir) = cwd.file_name().and_then(OsStr::to_str) {
|
||||||
if let Some(n) = dir.to_str() {
|
if let Some((n, v)) = dir.split_once('-') {
|
||||||
if let Some((n, v)) = n.split_once('-') {
|
name = Some(n.to_string());
|
||||||
name = Some(n.to_string());
|
if let Ok(v) = v.parse() {
|
||||||
if let Ok(v) = v.parse() {
|
version = Some(v);
|
||||||
version = Some(v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(name) = matches.get_one::<String>("name") {
|
if let Some(name) = matches.get_one::<String>("name") {
|
||||||
specs.name = name.to_string();
|
specs.name = name.to_string();
|
||||||
} else {
|
} else if let Some(n) = name {
|
||||||
if let Some(n) = name {
|
specs.name = n;
|
||||||
specs.name = n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(version) = matches.get_one::<String>("package-version") {
|
if let Some(version) = matches.get_one::<String>("package-version") {
|
||||||
specs.version = version.parse()?;
|
specs.version = version.parse()?;
|
||||||
} else {
|
} else if let Some(v) = version {
|
||||||
if let Some(v) = version {
|
specs.version = v;
|
||||||
specs.version = v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(release) = matches.get_one::<usize>("release") {
|
if let Some(release) = matches.get_one::<usize>("release") {
|
||||||
specs.release = *release as u8;
|
specs.release = *release as u8;
|
||||||
|
@ -13,7 +13,7 @@ use {
|
|||||||
walkdir::WalkDir,
|
walkdir::WalkDir,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Plist {
|
pub struct Plist {
|
||||||
pub entries: Vec<Entry>,
|
pub entries: Vec<Entry>,
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,33 @@ impl Default for Version {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Version {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Number(n) => write!(f, "{n}"),
|
||||||
|
Self::SemVer {
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
patch,
|
||||||
|
} => {
|
||||||
|
let v = SemVer {
|
||||||
|
major: *major,
|
||||||
|
minor: *minor,
|
||||||
|
patch: *patch,
|
||||||
|
};
|
||||||
|
write!(f, "{v}")
|
||||||
|
}
|
||||||
|
Self::Git { hash, datetime } => {
|
||||||
|
let v = GitRev {
|
||||||
|
hash: hash.to_owned(),
|
||||||
|
datetime: *datetime,
|
||||||
|
};
|
||||||
|
write!(f, "{v}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<SemVer> for Version {
|
impl From<SemVer> for Version {
|
||||||
fn from(value: SemVer) -> Self {
|
fn from(value: SemVer) -> Self {
|
||||||
Self::SemVer {
|
Self::SemVer {
|
||||||
@ -45,7 +72,10 @@ impl From<SemVer> for Version {
|
|||||||
|
|
||||||
impl From<GitRev> for Version {
|
impl From<GitRev> for Version {
|
||||||
fn from(value: GitRev) -> Self {
|
fn from(value: GitRev) -> Self {
|
||||||
Self::Git { hash: value.hash, datetime: value.datetime }
|
Self::Git {
|
||||||
|
hash: value.hash,
|
||||||
|
datetime: value.datetime,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +86,7 @@ impl From<u32> for Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Version {
|
impl PartialOrd for Version {
|
||||||
|
#[allow(clippy::many_single_char_names)]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Self::Number(s), Self::Number(o)) => s.partial_cmp(o),
|
(Self::Number(s), Self::Number(o)) => s.partial_cmp(o),
|
||||||
|
@ -70,7 +70,7 @@ impl FromStr for SemVer {
|
|||||||
let split = s.split('.').collect::<Vec<_>>();
|
let split = s.split('.').collect::<Vec<_>>();
|
||||||
match split.len() {
|
match split.len() {
|
||||||
3 => {
|
3 => {
|
||||||
let major = split.get(0).unwrap().parse::<u8>()?;
|
let major = split.first().unwrap().parse::<u8>()?;
|
||||||
let minor = split.get(1).unwrap().parse::<u8>()?;
|
let minor = split.get(1).unwrap().parse::<u8>()?;
|
||||||
let patch = split.get(2).unwrap().parse::<u8>()?;
|
let patch = split.get(2).unwrap().parse::<u8>()?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -5,6 +5,6 @@ edition = "2021"
|
|||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
deku = "0.16"
|
deku = { workspace = true }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.40"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, BufReader},
|
io::{self, BufReader, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
@ -12,11 +12,21 @@ pub use {
|
|||||||
node::Node,
|
node::Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Archive {
|
pub struct Archive {
|
||||||
pub nodes: Vec<Node>,
|
pub nodes: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Archive {
|
impl Archive {
|
||||||
|
pub fn to_vec(self) -> Result<Vec<u8>, Error> {
|
||||||
|
let mut buf = vec![];
|
||||||
|
for node in self.nodes {
|
||||||
|
buf.extend(node.to_vec()?);
|
||||||
|
}
|
||||||
|
buf.write_all(&[0; 9216])?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
/// Write out a vector of `TarNodes` to a file or something that implements ``std::io::Write`` and ``std::io::Copy``.
|
/// Write out a vector of `TarNodes` to a file or something that implements ``std::io::Write`` and ``std::io::Copy``.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -13,6 +13,14 @@ pub struct Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
|
pub fn to_vec(self) -> Result<Vec<u8>, DekuError> {
|
||||||
|
let mut buf = self.header.to_bytes()?;
|
||||||
|
for block in self.data {
|
||||||
|
buf.extend(block.to_vec());
|
||||||
|
}
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
/// Write out a single file within the tar to a file or something with a ``std::io::Write`` trait.
|
/// Write out a single file within the tar to a file or something with a ``std::io::Write`` trait.
|
||||||
pub fn write<T: io::Write>(self, mut input: T) -> Result<usize, Error> {
|
pub fn write<T: io::Write>(self, mut input: T) -> Result<usize, Error> {
|
||||||
input.write_all(&self.header.to_bytes()?)?;
|
input.write_all(&self.header.to_bytes()?)?;
|
||||||
@ -26,7 +34,7 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a TarNode in from a file or something with a ``std::io::Read`` trait.
|
/// Read a TarNode in from a file or something with a ``std::io::Read`` trait.
|
||||||
pub fn read<T: io::Read>(mut input: T) -> Result<Node, Error> {
|
pub fn read<T: io::Read>(mut input: T) -> Result<Self, Error> {
|
||||||
let mut h = vec![0u8; 512];
|
let mut h = vec![0u8; 512];
|
||||||
input.read_exact(&mut h)?;
|
input.read_exact(&mut h)?;
|
||||||
|
|
||||||
@ -49,7 +57,7 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Open and read a file from the ``filename`` argument to a TarNode.
|
/// Open and read a file from the ``filename`` argument to a TarNode.
|
||||||
pub fn read_file_to_tar(filename: String) -> Result<Node, Error> {
|
pub fn read_file_to_tar(filename: String) -> Result<Self, Error> {
|
||||||
let header = Header::new(&filename)?;
|
let header = Header::new(&filename)?;
|
||||||
if header.link_indicator[0] != FileType::Normal as u8 {
|
if header.link_indicator[0] != FileType::Normal as u8 {
|
||||||
return Ok(Node {
|
return Ok(Node {
|
||||||
@ -72,7 +80,7 @@ impl Node {
|
|||||||
filename: &str,
|
filename: &str,
|
||||||
meta: &Metadata,
|
meta: &Metadata,
|
||||||
owner: Option<Owner>,
|
owner: Option<Owner>,
|
||||||
) -> Result<Node, Error> {
|
) -> Result<Self, 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