Skip to content

Commit

Permalink
Skip hidden files, symlinks, and junk in created torrents
Browse files Browse the repository at this point in the history
By default, skip the following when creating a torrent:

- Junk files, like `Thumbs.db`
- Files and directories that begin with a `.`
- Files and directories that have the OS or Windows hidden attribute set
- Symlinks

These can be overridden with, respectively:
- `--include-junk`
- `--include-hidden`
- `--include-hidden`
- `--follow-symlinks`

type: changed
  • Loading branch information
casey committed Apr 8, 2020
1 parent 3739a92 commit 9158c23
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 62 deletions.
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ pub(crate) enum Error {
Stderr { source: io::Error },
#[snafu(display("Failed to write to standard output: {}", source))]
Stdout { source: io::Error },
#[snafu(display(
"Attempted to create torrent from symlink `{}`. To override, pass the `--follow-symlinks` flag.",
root.display()
))]
SymlinkRoot { root: PathBuf },
#[snafu(display("Failed to retrieve system time: {}", source))]
SystemTime { source: SystemTimeError },
#[snafu(display(
Expand Down
14 changes: 13 additions & 1 deletion src/file_path.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::*;

#[serde(transparent)]
#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub(crate) struct FilePath {
components: Vec<String>,
}
Expand Down Expand Up @@ -45,6 +45,18 @@ impl FilePath {
Ok(FilePath { components })
}

pub(crate) fn name(&self) -> &str {
&self.components[0]
}

pub(crate) fn absolute(&self, root: &Path) -> PathBuf {
let mut absolute = root.to_owned();
for component in &self.components {
absolute.push(component);
}
absolute
}

#[cfg(test)]
pub(crate) fn from_components(components: &[&str]) -> FilePath {
let components: Vec<String> = components
Expand Down
21 changes: 19 additions & 2 deletions src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,34 @@ use crate::common::*;
pub(crate) struct Files {
root: PathBuf,
total_size: Bytes,
contents: Option<Vec<FilePath>>,
}

impl Files {
pub(crate) fn new(root: PathBuf, total_size: Bytes) -> Files {
Files { root, total_size }
pub(crate) fn file(root: PathBuf, total_size: Bytes) -> Files {
Files {
contents: None,
root,
total_size,
}
}

pub(crate) fn dir(root: PathBuf, total_size: Bytes, contents: Vec<FilePath>) -> Files {
Files {
contents: Some(contents),
root,
total_size,
}
}

pub(crate) fn root(&self) -> &Path {
&self.root
}

pub(crate) fn contents(&self) -> Option<&[FilePath]> {
self.contents.as_deref()
}

pub(crate) fn total_size(&self) -> Bytes {
self.total_size
}
Expand Down
62 changes: 25 additions & 37 deletions src/hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl Hasher {
md5sum: bool,
piece_length: u32,
) -> Result<(Mode, Vec<u8>), Error> {
Self::new(md5sum, piece_length).hash_root(files.root())
Self::new(md5sum, piece_length).hash_files(files)
}

fn new(md5sum: bool, piece_length: u32) -> Self {
Expand All @@ -31,56 +31,44 @@ impl Hasher {
}
}

fn hash_root(mut self, root: &Path) -> Result<(Mode, Vec<u8>), Error> {
let metadata = root.metadata().context(error::Filesystem { path: root })?;
fn hash_files(mut self, files: &Files) -> Result<(Mode, Vec<u8>), Error> {
let mode = if let Some(contents) = files.contents() {
let files = self.hash_contents(&files.root(), contents)?;

if metadata.is_file() {
let (md5sum, length) = self.hash_file(&root)?;

if self.piece_bytes_hashed > 0 {
self.pieces.extend(&self.sha1.digest().bytes());
self.sha1.reset();
self.piece_bytes_hashed = 0;
}

Ok((
Mode::Single {
md5sum: md5sum.map(|md5sum| format!("{:x}", md5sum)),
length,
},
self.pieces,
))
Mode::Multiple { files }
} else {
let files = self.hash_dir(root)?;
let (md5sum, length) = self.hash_file(files.root())?;

if self.piece_bytes_hashed > 0 {
self.pieces.extend(&self.sha1.digest().bytes());
self.sha1.reset();
self.piece_bytes_hashed = 0;
Mode::Single {
md5sum: md5sum.map(|md5sum| format!("{:x}", md5sum)),
length,
}
};

Ok((Mode::Multiple { files }, self.pieces))
if self.piece_bytes_hashed > 0 {
self.pieces.extend(&self.sha1.digest().bytes());
self.sha1.reset();
self.piece_bytes_hashed = 0;
}

Ok((mode, self.pieces))
}

fn hash_dir(&mut self, dir: &Path) -> Result<Vec<FileInfo>, Error> {
fn hash_contents(
&mut self,
root: &Path,
file_paths: &[FilePath],
) -> Result<Vec<FileInfo>, Error> {
let mut files = Vec::new();
for result in WalkDir::new(dir).sort_by(|a, b| a.file_name().cmp(b.file_name())) {
let entry = result?;

let path = entry.path();

if !entry.metadata()?.is_file() {
continue;
}

let (md5sum, length) = self.hash_file(path)?;
for file_path in file_paths {
let path = file_path.absolute(root);

let file_path = FilePath::from_prefix_and_path(dir, path)?;
let (md5sum, length) = self.hash_file(&path)?;

files.push(FileInfo {
md5sum: md5sum.map(|md5sum| format!("{:x}", md5sum)),
path: file_path,
path: file_path.clone(),
length,
});
}
Expand Down
Loading

0 comments on commit 9158c23

Please sign in to comment.