Skip to content

Commit

Permalink
parallel iter
Browse files Browse the repository at this point in the history
  • Loading branch information
QaidVoid committed Nov 15, 2024
1 parent e338003 commit d84e33a
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 22 deletions.
53 changes: 53 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion squishy-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ name = "squishy"
path = "src/main.rs"

[dependencies]
squishy = { path = "../squishy", version = "0.2.0" }
squishy = { path = "../squishy", version = "0.2.0", features = ["rayon"] }
clap = { version = "4.5.20", features = ["cargo", "derive"] }
goblin = { version = "0.9.2", default-features = false, features = ["elf32", "elf64", "endian_fd", "std"] }
rayon = "1.10.0"
23 changes: 14 additions & 9 deletions squishy-cli/src/appimage.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use std::{ffi::{OsStr, OsString}, fs, path::Path};
use std::{
ffi::{OsStr, OsString},
fs,
path::Path,
};

use rayon::iter::ParallelIterator;
use squishy::{error::SquishyError, EntryKind, SquashFS, SquashFSEntry};

use crate::common::get_offset;
Expand Down Expand Up @@ -44,8 +49,8 @@ impl<'a> AppImage<'a> {

fn search_diricon(&self) -> Option<SquashFSEntry> {
self.squashfs
.entries()
.find(|entry| entry.path.to_string_lossy() == "/.DirIcon")
.par_entries()
.find_first(|entry| entry.path.to_string_lossy() == "/.DirIcon")
}

fn filter_path(&self, path: &str) -> bool {
Expand All @@ -55,7 +60,7 @@ impl<'a> AppImage<'a> {
}

fn find_largest_icon_path(&self) -> Option<SquashFSEntry> {
let png_entries = self.squashfs.entries().filter(|entry| {
let png_entries = self.squashfs.par_entries().filter(|entry| {
let path = entry.path.to_string_lossy().to_lowercase();
path.starts_with("/usr/share/icons/")
&& self.filter_path(&path)
Expand All @@ -66,7 +71,7 @@ impl<'a> AppImage<'a> {
return Some(entry);
}

self.squashfs.entries().find(|entry| {
self.squashfs.par_entries().find_first(|entry| {
let path = entry.path.to_string_lossy().to_lowercase();
path.starts_with("/usr/share/icons")
&& self.filter_path(&path)
Expand All @@ -75,7 +80,7 @@ impl<'a> AppImage<'a> {
}

fn find_png_icon(&self) -> Option<SquashFSEntry> {
let png_entries = self.squashfs.entries().filter(|entry| {
let png_entries = self.squashfs.par_entries().filter(|entry| {
let p = entry.path.to_string_lossy().to_lowercase();
self.filter_path(&p) && p.ends_with(".png")
});
Expand All @@ -86,14 +91,14 @@ impl<'a> AppImage<'a> {
}

fn find_svg_icon(&self) -> Option<SquashFSEntry> {
self.squashfs.entries().find(|entry| {
self.squashfs.par_entries().find_first(|entry| {
let path = entry.path.to_string_lossy().to_lowercase();
self.filter_path(&path) && path.ends_with(".svg")
})
}

pub fn find_desktop(&self) -> Option<SquashFSEntry> {
let desktop = self.squashfs.entries().find(|entry| {
let desktop = self.squashfs.par_entries().find_first(|entry| {
let path = entry.path.to_string_lossy().to_lowercase();
self.filter_path(&path) && path.ends_with(".desktop")
});
Expand All @@ -108,7 +113,7 @@ impl<'a> AppImage<'a> {
}

pub fn find_appstream(&self) -> Option<SquashFSEntry> {
let appstream = self.squashfs.entries().find(|entry| {
let appstream = self.squashfs.par_entries().find_first(|entry| {
let path = entry.path.to_string_lossy().to_lowercase();
self.filter_path(&path)
&& (path.ends_with("appdata.xml") || path.ends_with("metadata.xml"))
Expand Down
43 changes: 31 additions & 12 deletions squishy-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::{fs, os::unix};
use std::{
fs::{self, Permissions},
os::unix::{self, fs::PermissionsExt},
};

use appimage::AppImage;
use clap::Parser;
use cli::Args;
use common::get_offset;
use rayon::iter::ParallelIterator;
use squishy::{error::SquishyError, EntryKind, SquashFS};

mod appimage;
Expand Down Expand Up @@ -132,40 +136,55 @@ fn main() {
})
.unwrap();

squashfs.entries().for_each(|entry| {
squashfs.par_entries().for_each(|entry| {
if let Some(output_dir) = &write_path {
let file_path = entry.path.strip_prefix("/").unwrap_or(&entry.path);
let output_path = output_dir.join(file_path);
fs::create_dir_all(output_path.parent().unwrap()).unwrap();

match entry.kind {
EntryKind::File(basic_file) => {
let output_path = output_dir.join(file_path);
squashfs
.write_file_with_permissions(basic_file, &output_path, entry.header)
.unwrap();
if output_path.exists() {
return;
}
let _ = squashfs.write_file_with_permissions(
basic_file,
&output_path,
entry.header,
);
log!(
args.quiet,
"Wrote {} to {}",
file.display(),
entry.path.display(),
output_path.display()
);
}
EntryKind::Directory => {
let output_path = output_dir.join(file_path);
if output_path.exists() {
return;
}
fs::create_dir_all(&output_path).unwrap();
fs::set_permissions(
&output_path,
Permissions::from_mode(u32::from(entry.header.permissions)),
).unwrap();
log!(
args.quiet,
"Wrote {} to {}",
file.display(),
entry.path.display(),
output_path.display()
);
}
EntryKind::Symlink(e) => {
if output_path.exists() {
return;
}
let original_path = e.strip_prefix("/").unwrap_or(&e);
let output_path = output_dir.join(file_path);
unix::fs::symlink(original_path, &output_path).unwrap();
let _ = unix::fs::symlink(original_path, &output_path);
log!(
args.quiet,
"Wrote {} to {}",
file.display(),
entry.path.display(),
output_path.display()
);
}
Expand Down
5 changes: 5 additions & 0 deletions squishy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ keywords.workspace = true
name = "squishy"
path = "src/lib.rs"

[features]
default = []
rayon = ["dep:rayon"]

[dependencies]
backhand = "0.18.0"
rayon = { version = "1.10.0", optional = true }
thiserror = "2.0.0"
34 changes: 34 additions & 0 deletions squishy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use std::{
use backhand::{kind::Kind, BasicFile, FilesystemReader, InnerNode, NodeHeader};
use error::SquishyError;

#[cfg(feature = "rayon")]
use rayon::iter::{IntoParallelIterator, ParallelIterator};

pub mod error;

pub type Result<T> = std::result::Result<T, SquishyError>;
Expand Down Expand Up @@ -135,6 +138,37 @@ impl<'a> SquashFS<'a> {
})
}

#[cfg(feature = "rayon")]
/// Returns a parallel iterator over all the entries in the SquashFS filesystem.
pub fn par_entries(&self) -> impl ParallelIterator<Item = SquashFSEntry> + '_ {
self.reader
.files()
.map(|node| {
let size = match &node.inner {
InnerNode::File(file) => file.basic.file_size,
_ => 0,
};

let kind = match &node.inner {
InnerNode::File(file) => EntryKind::File(&file.basic),
InnerNode::Dir(_) => EntryKind::Directory,
InnerNode::Symlink(symlink) => EntryKind::Symlink(
PathBuf::from(format!("/{}", symlink.link.display())).clone(),
),
_ => EntryKind::Unknown,
};

SquashFSEntry {
header: node.header,
path: node.fullpath.clone(),
size,
kind,
}
})
.collect::<Vec<SquashFSEntry>>()
.into_par_iter()
}

/// Returns an iterator over all the entries in the SquashFS filesystem
/// that match the provided predicate function.
///
Expand Down

0 comments on commit d84e33a

Please sign in to comment.