Remove support for zeroed files (#461)
This commit is contained in:
parent
29129d3ec0
commit
78b49dee3d
|
@ -21,7 +21,6 @@
|
|||
- Temporary Files - Finds temporary files
|
||||
- Similar Images - Finds images which are not exactly the same (different resolution, watermarks)
|
||||
- Similar Videos - Looks for similar visually videos
|
||||
- Zeroed Files - Finds files which are filled with zeros (usually corrupted)
|
||||
- Same Music - Searches for music with the same artist, album etc.
|
||||
- Invalid Symbolic Links - Shows symbolic links which point to non-existent files/directories
|
||||
- Broken Files - Finds files with an invalid extension or that are corrupted
|
||||
|
@ -103,7 +102,6 @@ Bleachbit is a master at finding and removing temporary files, while Czkawka onl
|
|||
| Big files | • | | | |
|
||||
| Similar images | • | | • | |
|
||||
| Similar videos | • | | | |
|
||||
| Zeroed files | • | | | |
|
||||
| Music duplicates(tags) | • | | • | |
|
||||
| Invalid symlinks | • | • | | |
|
||||
| Broken files | • | | | |
|
||||
|
|
|
@ -128,27 +128,6 @@ pub enum Commands {
|
|||
#[structopt(short = "c", long, default_value = "8", parse(try_from_str = parse_image_hash_size), help="Hash size (allowed: 4, 8, 16)")]
|
||||
hash_size: u8,
|
||||
},
|
||||
#[structopt(name = "zeroed", about = "Finds zeroed files", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka zeroed -d /home/rafal -e /home/rafal/Pulpit -f results.txt")]
|
||||
ZeroedFiles {
|
||||
#[structopt(flatten)]
|
||||
directories: Directories,
|
||||
#[structopt(flatten)]
|
||||
excluded_directories: ExcludedDirectories,
|
||||
#[structopt(flatten)]
|
||||
excluded_items: ExcludedItems,
|
||||
#[structopt(flatten)]
|
||||
allowed_extensions: AllowedExtensions,
|
||||
#[structopt(short = "D", long, help = "Delete found files")]
|
||||
delete_files: bool,
|
||||
#[structopt(flatten)]
|
||||
file_to_save: FileToSave,
|
||||
#[structopt(flatten)]
|
||||
not_recursive: NotRecursive,
|
||||
#[structopt(short, long, parse(try_from_str = parse_minimal_file_size), default_value = "8192", help = "Minimum size in bytes", long_help = "Minimum size of checked files in bytes, assigning bigger value may speed up searching")]
|
||||
minimal_file_size: u64,
|
||||
#[structopt(short = "i", long, parse(try_from_str = parse_maximal_file_size), default_value = "18446744073709551615", help = "Maximum size in bytes", long_help = "Maximum size of checked files in bytes, assigning lower value may speed up searching")]
|
||||
maximal_file_size: u64,
|
||||
},
|
||||
#[structopt(name = "music", about = "Finds same music by tags", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka music -d /home/rafal -f results.txt")]
|
||||
SameMusic {
|
||||
#[structopt(flatten)]
|
||||
|
@ -464,7 +443,6 @@ EXAMPLES:
|
|||
{bin} empty-files -d /home/rafal /home/szczekacz -e /home/rafal/Pulpit -R -f results.txt
|
||||
{bin} temp -d /home/rafal/ -E */.git */tmp* *Pulpit -f results.txt -D
|
||||
{bin} image -d /home/rafal -e /home/rafal/Pulpit -f results.txt
|
||||
{bin} zeroed -d /home/rafal -e /home/krzak -f results.txt"
|
||||
{bin} music -d /home/rafal -e /home/rafal/Pulpit -z "artist,year, ARTISTALBUM, ALBUM___tiTlE" -f results.txt
|
||||
{bin} symlinks -d /home/kicikici/ /home/szczek -e /home/kicikici/jestempsem -x jpg -f results.txt
|
||||
{bin} broken -d /home/mikrut/ -e /home/mikrut/trakt -f results.txt"#;
|
||||
|
|
|
@ -18,7 +18,6 @@ use czkawka_core::{
|
|||
similar_images::{return_similarity_from_similarity_preset, SimilarImages},
|
||||
similar_videos::SimilarVideos,
|
||||
temporary::{self, Temporary},
|
||||
zeroed::{self, ZeroedFiles},
|
||||
};
|
||||
use std::process;
|
||||
use structopt::StructOpt;
|
||||
|
@ -243,44 +242,6 @@ fn main() {
|
|||
sf.print_results();
|
||||
sf.get_text_messages().print_messages();
|
||||
}
|
||||
Commands::ZeroedFiles {
|
||||
directories,
|
||||
excluded_directories,
|
||||
excluded_items,
|
||||
allowed_extensions,
|
||||
delete_files,
|
||||
file_to_save,
|
||||
not_recursive,
|
||||
minimal_file_size,
|
||||
maximal_file_size,
|
||||
} => {
|
||||
let mut zf = ZeroedFiles::new();
|
||||
|
||||
zf.set_included_directory(directories.directories);
|
||||
zf.set_excluded_directory(excluded_directories.excluded_directories);
|
||||
zf.set_excluded_items(excluded_items.excluded_items);
|
||||
zf.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
|
||||
zf.set_minimal_file_size(minimal_file_size);
|
||||
zf.set_maximal_file_size(maximal_file_size);
|
||||
zf.set_recursive_search(!not_recursive.not_recursive);
|
||||
|
||||
if delete_files {
|
||||
zf.set_delete_method(zeroed::DeleteMethod::Delete);
|
||||
}
|
||||
|
||||
zf.find_zeroed_files(None, None);
|
||||
|
||||
if let Some(file_name) = file_to_save.file_name() {
|
||||
if !zf.save_results_to_file(file_name) {
|
||||
zf.get_text_messages().print_messages();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))] // This will show too much probably unnecessary data to debug, comment line only if needed
|
||||
zf.print_results();
|
||||
zf.get_text_messages().print_messages();
|
||||
}
|
||||
Commands::SameMusic {
|
||||
directories,
|
||||
excluded_directories,
|
||||
|
|
|
@ -11,7 +11,6 @@ pub mod same_music;
|
|||
pub mod similar_images;
|
||||
pub mod similar_videos;
|
||||
pub mod temporary;
|
||||
pub mod zeroed;
|
||||
|
||||
pub mod common;
|
||||
pub mod common_directory;
|
||||
|
|
|
@ -1,513 +0,0 @@
|
|||
use std::fs::{File, Metadata};
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use std::{fs, thread};
|
||||
|
||||
use crate::common::Common;
|
||||
use crate::common_directory::Directories;
|
||||
use crate::common_extensions::Extensions;
|
||||
use crate::common_items::ExcludedItems;
|
||||
use crate::common_messages::Messages;
|
||||
use crate::common_traits::*;
|
||||
use crossbeam_channel::Receiver;
|
||||
use rayon::prelude::*;
|
||||
use std::io::BufWriter;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread::sleep;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProgressData {
|
||||
pub current_stage: u8,
|
||||
pub max_stage: u8,
|
||||
pub files_checked: usize,
|
||||
pub files_to_check: usize,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
pub enum DeleteMethod {
|
||||
None,
|
||||
Delete,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FileEntry {
|
||||
pub path: PathBuf,
|
||||
pub size: u64,
|
||||
pub modified_date: u64,
|
||||
}
|
||||
|
||||
/// Info struck with helpful information's about results
|
||||
#[derive(Default)]
|
||||
pub struct Info {
|
||||
pub number_of_zeroed_files: usize,
|
||||
pub number_of_removed_files: usize,
|
||||
pub number_of_failed_to_remove_files: usize,
|
||||
}
|
||||
impl Info {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct with required information's to work
|
||||
pub struct ZeroedFiles {
|
||||
text_messages: Messages,
|
||||
information: Info,
|
||||
zeroed_files: Vec<FileEntry>,
|
||||
directories: Directories,
|
||||
allowed_extensions: Extensions,
|
||||
excluded_items: ExcludedItems,
|
||||
recursive_search: bool,
|
||||
delete_method: DeleteMethod,
|
||||
stopped_search: bool,
|
||||
minimal_file_size: u64,
|
||||
maximal_file_size: u64,
|
||||
files_to_check: Vec<FileEntry>,
|
||||
}
|
||||
|
||||
impl ZeroedFiles {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
text_messages: Messages::new(),
|
||||
information: Info::new(),
|
||||
recursive_search: true,
|
||||
allowed_extensions: Extensions::new(),
|
||||
directories: Directories::new(),
|
||||
excluded_items: ExcludedItems::new(),
|
||||
zeroed_files: vec![],
|
||||
delete_method: DeleteMethod::None,
|
||||
stopped_search: false,
|
||||
minimal_file_size: 8192,
|
||||
maximal_file_size: u64::MAX,
|
||||
files_to_check: Vec::with_capacity(1024),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_zeroed_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
||||
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
|
||||
if !self.check_files(stop_receiver, progress_sender) {
|
||||
self.stopped_search = true;
|
||||
return;
|
||||
}
|
||||
if !self.check_for_zeroed_files(stop_receiver, progress_sender) {
|
||||
self.stopped_search = true;
|
||||
return;
|
||||
}
|
||||
self.delete_files();
|
||||
self.debug_print();
|
||||
}
|
||||
|
||||
pub fn get_stopped_search(&self) -> bool {
|
||||
self.stopped_search
|
||||
}
|
||||
|
||||
pub const fn get_zeroed_files(&self) -> &Vec<FileEntry> {
|
||||
&self.zeroed_files
|
||||
}
|
||||
|
||||
pub const fn get_text_messages(&self) -> &Messages {
|
||||
&self.text_messages
|
||||
}
|
||||
|
||||
pub const fn get_information(&self) -> &Info {
|
||||
&self.information
|
||||
}
|
||||
|
||||
pub fn set_delete_method(&mut self, delete_method: DeleteMethod) {
|
||||
self.delete_method = delete_method;
|
||||
}
|
||||
|
||||
pub fn set_minimal_file_size(&mut self, minimal_file_size: u64) {
|
||||
self.minimal_file_size = match minimal_file_size {
|
||||
0 => 1,
|
||||
t => t,
|
||||
};
|
||||
}
|
||||
pub fn set_maximal_file_size(&mut self, maximal_file_size: u64) {
|
||||
self.maximal_file_size = match maximal_file_size {
|
||||
0 => 1,
|
||||
t => t,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn set_recursive_search(&mut self, recursive_search: bool) {
|
||||
self.recursive_search = recursive_search;
|
||||
}
|
||||
|
||||
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>) -> bool {
|
||||
self.directories.set_included_directory(included_directory, &mut self.text_messages)
|
||||
}
|
||||
|
||||
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
||||
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
||||
}
|
||||
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) {
|
||||
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
|
||||
}
|
||||
|
||||
pub fn set_excluded_items(&mut self, excluded_items: Vec<String>) {
|
||||
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
|
||||
}
|
||||
|
||||
/// Check files for files which have 0
|
||||
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
|
||||
|
||||
// Add root folders for finding
|
||||
for id in &self.directories.included_directories {
|
||||
folders_to_check.push(id.clone());
|
||||
}
|
||||
|
||||
//// PROGRESS THREAD START
|
||||
const LOOP_DURATION: u32 = 200; //in ms
|
||||
let progress_thread_run = Arc::new(AtomicBool::new(true));
|
||||
|
||||
let atomic_file_counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let progress_thread_handle;
|
||||
if let Some(progress_sender) = progress_sender {
|
||||
let progress_send = progress_sender.clone();
|
||||
let progress_thread_run = progress_thread_run.clone();
|
||||
let atomic_file_counter = atomic_file_counter.clone();
|
||||
progress_thread_handle = thread::spawn(move || loop {
|
||||
progress_send
|
||||
.unbounded_send(ProgressData {
|
||||
current_stage: 0,
|
||||
max_stage: 1,
|
||||
files_checked: atomic_file_counter.load(Ordering::Relaxed) as usize,
|
||||
files_to_check: 0,
|
||||
})
|
||||
.unwrap();
|
||||
if !progress_thread_run.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
sleep(Duration::from_millis(LOOP_DURATION as u64));
|
||||
});
|
||||
} else {
|
||||
progress_thread_handle = thread::spawn(|| {});
|
||||
}
|
||||
//// PROGRESS THREAD END
|
||||
while !folders_to_check.is_empty() {
|
||||
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
|
||||
// End thread which send info to gui
|
||||
progress_thread_run.store(false, Ordering::Relaxed);
|
||||
progress_thread_handle.join().unwrap();
|
||||
return false;
|
||||
}
|
||||
let current_folder = folders_to_check.pop().unwrap();
|
||||
|
||||
// Read current dir, if permission are denied just go to next
|
||||
let read_dir = match fs::read_dir(¤t_folder) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
self.text_messages.warnings.push(format!("Cannot open dir {}, reason {}", current_folder.display(), e));
|
||||
continue;
|
||||
} // Permissions denied
|
||||
};
|
||||
|
||||
// Check every sub folder/file/link etc.
|
||||
'dir: for entry in read_dir {
|
||||
let entry_data = match entry {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
self.text_messages.warnings.push(format!("Cannot read entry in dir {}, reason {}", current_folder.display(), e));
|
||||
continue;
|
||||
} //Permissions denied
|
||||
};
|
||||
let metadata: Metadata = match entry_data.metadata() {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
self.text_messages.warnings.push(format!("Cannot read metadata in dir {}, reason {}", current_folder.display(), e));
|
||||
continue;
|
||||
} //Permissions denied
|
||||
};
|
||||
if metadata.is_dir() {
|
||||
if !self.recursive_search {
|
||||
continue;
|
||||
}
|
||||
|
||||
let next_folder = current_folder.join(entry_data.file_name());
|
||||
if self.directories.is_excluded(&next_folder) || self.excluded_items.is_excluded(&next_folder) {
|
||||
continue 'dir;
|
||||
}
|
||||
|
||||
folders_to_check.push(next_folder);
|
||||
} else if metadata.is_file() {
|
||||
atomic_file_counter.fetch_add(1, Ordering::Relaxed);
|
||||
if metadata.len() == 0 || !(self.minimal_file_size..=self.maximal_file_size).contains(&metadata.len()) {
|
||||
continue 'dir;
|
||||
}
|
||||
|
||||
let file_name_lowercase: String = match entry_data.file_name().into_string() {
|
||||
Ok(t) => t,
|
||||
Err(_inspected) => {
|
||||
println!("File {:?} has not valid UTF-8 name", entry_data);
|
||||
continue 'dir;
|
||||
}
|
||||
}
|
||||
.to_lowercase();
|
||||
|
||||
// Checking allowed extensions
|
||||
if !self.allowed_extensions.file_extensions.is_empty() {
|
||||
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
|
||||
if !allowed {
|
||||
// Not an allowed extension, ignore it.
|
||||
continue 'dir;
|
||||
}
|
||||
}
|
||||
// Checking files
|
||||
let current_file_name = current_folder.join(entry_data.file_name());
|
||||
if self.excluded_items.is_excluded(¤t_file_name) {
|
||||
continue 'dir;
|
||||
}
|
||||
|
||||
// Creating new file entry
|
||||
let fe: FileEntry = FileEntry {
|
||||
path: current_file_name.clone(),
|
||||
size: metadata.len(),
|
||||
modified_date: match metadata.modified() {
|
||||
Ok(t) => match t.duration_since(UNIX_EPOCH) {
|
||||
Ok(d) => d.as_secs(),
|
||||
Err(_inspected) => {
|
||||
self.text_messages.warnings.push(format!("File {} seems to be modified before Unix Epoch.", current_file_name.display()));
|
||||
0
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
self.text_messages.warnings.push(format!("Unable to get modification date from file {}, reason {}", current_file_name.display(), e));
|
||||
0
|
||||
} // Permissions Denied
|
||||
},
|
||||
};
|
||||
|
||||
// Adding files to Vector
|
||||
self.files_to_check.push(fe);
|
||||
}
|
||||
}
|
||||
}
|
||||
// End thread which send info to gui
|
||||
progress_thread_run.store(false, Ordering::Relaxed);
|
||||
progress_thread_handle.join().unwrap();
|
||||
|
||||
Common::print_time(start_time, SystemTime::now(), "check_files".to_string());
|
||||
true
|
||||
}
|
||||
|
||||
/// Check files for files which have 0
|
||||
fn check_for_zeroed_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
|
||||
//// PROGRESS THREAD START
|
||||
const LOOP_DURATION: u32 = 200; //in ms
|
||||
let progress_thread_run = Arc::new(AtomicBool::new(true));
|
||||
|
||||
let atomic_file_counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let progress_thread_handle;
|
||||
if let Some(progress_sender) = progress_sender {
|
||||
let progress_send = progress_sender.clone();
|
||||
let progress_thread_run = progress_thread_run.clone();
|
||||
let atomic_file_counter = atomic_file_counter.clone();
|
||||
let files_to_check = self.files_to_check.len();
|
||||
progress_thread_handle = thread::spawn(move || loop {
|
||||
progress_send
|
||||
.unbounded_send(ProgressData {
|
||||
current_stage: 1,
|
||||
max_stage: 1,
|
||||
files_checked: atomic_file_counter.load(Ordering::Relaxed) as usize,
|
||||
files_to_check,
|
||||
})
|
||||
.unwrap();
|
||||
if !progress_thread_run.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
sleep(Duration::from_millis(LOOP_DURATION as u64));
|
||||
});
|
||||
} else {
|
||||
progress_thread_handle = thread::spawn(|| {});
|
||||
}
|
||||
//// PROGRESS THREAD END
|
||||
|
||||
self.zeroed_files = self
|
||||
.files_to_check
|
||||
.par_iter()
|
||||
.map(|file_entry| {
|
||||
atomic_file_counter.fetch_add(1, Ordering::Relaxed);
|
||||
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
|
||||
// This will not break
|
||||
return None;
|
||||
}
|
||||
|
||||
let file_entry = file_entry.clone();
|
||||
let mut n;
|
||||
let mut file_handler: File = match File::open(&file_entry.path) {
|
||||
Ok(t) => t,
|
||||
Err(_inspected) => {
|
||||
return Some(None);
|
||||
}
|
||||
};
|
||||
|
||||
// First search
|
||||
let mut buffer = [0u8; 64];
|
||||
n = match file_handler.read(&mut buffer) {
|
||||
Ok(t) => t,
|
||||
Err(_inspected) => {
|
||||
return Some(None);
|
||||
}
|
||||
};
|
||||
for i in buffer[0..n].iter() {
|
||||
if *i != 0 {
|
||||
return Some(None);
|
||||
}
|
||||
}
|
||||
// Second search
|
||||
loop {
|
||||
let mut buffer = [0u8; 1024 * 32];
|
||||
n = match file_handler.read(&mut buffer) {
|
||||
Ok(t) => t,
|
||||
Err(_inspected) => {
|
||||
return Some(None);
|
||||
}
|
||||
};
|
||||
for i in buffer[0..n].iter() {
|
||||
if *i != 0 {
|
||||
return Some(None);
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Some(Some(file_entry))
|
||||
})
|
||||
.while_some()
|
||||
.filter(|file_entry| file_entry.is_some())
|
||||
.map(|file_entry| file_entry.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// End thread which send info to gui
|
||||
progress_thread_run.store(false, Ordering::Relaxed);
|
||||
progress_thread_handle.join().unwrap();
|
||||
|
||||
self.information.number_of_zeroed_files = self.zeroed_files.len();
|
||||
|
||||
Common::print_time(start_time, SystemTime::now(), "search for zeroed_files".to_string());
|
||||
|
||||
//Clean unused data
|
||||
self.files_to_check.clear();
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Function to delete files, from filed Vector
|
||||
fn delete_files(&mut self) {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
|
||||
match self.delete_method {
|
||||
DeleteMethod::Delete => {
|
||||
for file_entry in &self.zeroed_files {
|
||||
if fs::remove_file(file_entry.path.clone()).is_err() {
|
||||
self.text_messages.warnings.push(file_entry.path.display().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
DeleteMethod::None => {
|
||||
//Just do nothing
|
||||
}
|
||||
}
|
||||
|
||||
Common::print_time(start_time, SystemTime::now(), "delete_files".to_string());
|
||||
}
|
||||
}
|
||||
impl Default for ZeroedFiles {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugPrint for ZeroedFiles {
|
||||
#[allow(dead_code)]
|
||||
#[allow(unreachable_code)]
|
||||
/// Debugging printing - only available on debug build
|
||||
fn debug_print(&self) {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
return;
|
||||
}
|
||||
println!("---------------DEBUG PRINT---------------");
|
||||
println!("### Information's");
|
||||
|
||||
println!("Errors size - {}", self.text_messages.errors.len());
|
||||
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||
println!("Messages size - {}", self.text_messages.messages.len());
|
||||
println!("Number of removed files - {}", self.information.number_of_removed_files);
|
||||
println!("Number of failed to remove files - {}", self.information.number_of_failed_to_remove_files);
|
||||
|
||||
println!("### Other");
|
||||
|
||||
println!("Zeroed list size - {}", self.zeroed_files.len());
|
||||
println!("Allowed extensions - {:?}", self.allowed_extensions.file_extensions);
|
||||
println!("Excluded items - {:?}", self.excluded_items.items);
|
||||
println!("Included directories - {:?}", self.directories.included_directories);
|
||||
println!("Excluded directories - {:?}", self.directories.excluded_directories);
|
||||
println!("Recursive search - {}", self.recursive_search);
|
||||
println!("Delete Method - {:?}", self.delete_method);
|
||||
println!("Minimal File Size - {:?}", self.minimal_file_size);
|
||||
println!("-----------------------------------------");
|
||||
}
|
||||
}
|
||||
impl SaveResults for ZeroedFiles {
|
||||
fn save_results_to_file(&mut self, file_name: &str) -> bool {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
let file_name: String = match file_name {
|
||||
"" => "results.txt".to_string(),
|
||||
k => k.to_string(),
|
||||
};
|
||||
|
||||
let file_handler = match File::create(&file_name) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
self.text_messages.errors.push(format!("Failed to create file {}, reason {}", file_name, e));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let mut writer = BufWriter::new(file_handler);
|
||||
|
||||
if let Err(e) = writeln!(
|
||||
writer,
|
||||
"Results of searching {:?} with excluded directories {:?} and excluded items {:?}",
|
||||
self.directories.included_directories, self.directories.excluded_directories, self.excluded_items.items
|
||||
) {
|
||||
self.text_messages.errors.push(format!("Failed to save results to file {}, reason {}", file_name, e));
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.zeroed_files.is_empty() {
|
||||
writeln!(writer, "Found {} zeroed files.", self.information.number_of_zeroed_files).unwrap();
|
||||
for file_entry in self.zeroed_files.iter() {
|
||||
writeln!(writer, "{}", file_entry.path.display()).unwrap();
|
||||
}
|
||||
} else {
|
||||
write!(writer, "Not found any zeroed files.").unwrap();
|
||||
}
|
||||
Common::print_time(start_time, SystemTime::now(), "save_results_to_file".to_string());
|
||||
true
|
||||
}
|
||||
}
|
||||
impl PrintResults for ZeroedFiles {
|
||||
/// Print information's about duplicated entries
|
||||
/// Only needed for CLI
|
||||
fn print_results(&self) {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
println!("Found {} zeroed files.\n", self.information.number_of_zeroed_files);
|
||||
for file_entry in self.zeroed_files.iter() {
|
||||
println!("{}", file_entry.path.display());
|
||||
}
|
||||
|
||||
Common::print_time(start_time, SystemTime::now(), "print_entries".to_string());
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ pub fn connect_button_delete(gui_data: &GuiData) {
|
|||
let tree_view_temporary_files_finder = gui_data.main_notebook.tree_view_temporary_files_finder.clone();
|
||||
let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone();
|
||||
let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone();
|
||||
let tree_view_zeroed_files_finder = gui_data.main_notebook.tree_view_zeroed_files_finder.clone();
|
||||
let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone();
|
||||
let tree_view_invalid_symlinks = gui_data.main_notebook.tree_view_invalid_symlinks.clone();
|
||||
let tree_view_broken_files = gui_data.main_notebook.tree_view_broken_files.clone();
|
||||
|
@ -126,15 +125,6 @@ pub fn connect_button_delete(gui_data: &GuiData) {
|
|||
);
|
||||
}
|
||||
}
|
||||
NotebookMainEnum::Zeroed => {
|
||||
basic_remove(
|
||||
&tree_view_zeroed_files_finder.clone(),
|
||||
ColumnsZeroedFiles::Name as i32,
|
||||
ColumnsZeroedFiles::Path as i32,
|
||||
ColumnsZeroedFiles::ActiveSelectButton as i32,
|
||||
&gui_data,
|
||||
);
|
||||
}
|
||||
NotebookMainEnum::SameMusic => {
|
||||
if !check_button_settings_confirm_group_deletion.is_active()
|
||||
|| !check_if_deleting_all_files_in_group(
|
||||
|
|
|
@ -16,7 +16,6 @@ pub fn connect_button_move(gui_data: &GuiData) {
|
|||
let tree_view_empty_files_finder = gui_data.main_notebook.tree_view_empty_files_finder.clone();
|
||||
let tree_view_temporary_files_finder = gui_data.main_notebook.tree_view_temporary_files_finder.clone();
|
||||
let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone();
|
||||
let tree_view_zeroed_files_finder = gui_data.main_notebook.tree_view_zeroed_files_finder.clone();
|
||||
let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone();
|
||||
let tree_view_invalid_symlinks = gui_data.main_notebook.tree_view_invalid_symlinks.clone();
|
||||
let tree_view_broken_files = gui_data.main_notebook.tree_view_broken_files.clone();
|
||||
|
@ -75,16 +74,6 @@ pub fn connect_button_move(gui_data: &GuiData) {
|
|||
&gui_data,
|
||||
);
|
||||
}
|
||||
NotebookMainEnum::Zeroed => {
|
||||
move_things(
|
||||
tree_view_zeroed_files_finder.clone(),
|
||||
ColumnsZeroedFiles::Name as i32,
|
||||
ColumnsZeroedFiles::Path as i32,
|
||||
None,
|
||||
ColumnsZeroedFiles::ActiveSelectButton as i32,
|
||||
&gui_data,
|
||||
);
|
||||
}
|
||||
NotebookMainEnum::BrokenFiles => {
|
||||
move_things(
|
||||
tree_view_broken_files.clone(),
|
||||
|
|
|
@ -14,7 +14,6 @@ pub fn connect_button_save(gui_data: &GuiData) {
|
|||
let shared_similar_images_state = gui_data.shared_similar_images_state.clone();
|
||||
let shared_similar_videos_state = gui_data.shared_similar_videos_state.clone();
|
||||
let shared_same_music_state = gui_data.shared_same_music_state.clone();
|
||||
let shared_zeroed_files_state = gui_data.shared_zeroed_files_state.clone();
|
||||
let shared_same_invalid_symlinks = gui_data.shared_same_invalid_symlinks.clone();
|
||||
let shared_broken_files_state = gui_data.shared_broken_files_state.clone();
|
||||
let notebook_main = gui_data.main_notebook.notebook_main.clone();
|
||||
|
@ -57,11 +56,6 @@ pub fn connect_button_save(gui_data: &GuiData) {
|
|||
|
||||
shared_similar_videos_state.borrow_mut().save_results_to_file(file_name);
|
||||
}
|
||||
NotebookMainEnum::Zeroed => {
|
||||
file_name = "results_zeroed_files.txt";
|
||||
|
||||
shared_zeroed_files_state.borrow_mut().save_results_to_file(file_name);
|
||||
}
|
||||
NotebookMainEnum::SameMusic => {
|
||||
file_name = "results_same_music.txt";
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ use czkawka_core::same_music::{MusicSimilarity, SameMusic};
|
|||
use czkawka_core::similar_images::SimilarImages;
|
||||
use czkawka_core::similar_videos::SimilarVideos;
|
||||
use czkawka_core::temporary::Temporary;
|
||||
use czkawka_core::zeroed::ZeroedFiles;
|
||||
use glib::Sender;
|
||||
use gtk::prelude::*;
|
||||
use gtk::WindowPosition;
|
||||
|
@ -36,7 +35,6 @@ pub fn connect_button_search(
|
|||
futures_sender_similar_images: futures::channel::mpsc::UnboundedSender<similar_images::ProgressData>,
|
||||
futures_sender_similar_videos: futures::channel::mpsc::UnboundedSender<similar_videos::ProgressData>,
|
||||
futures_sender_temporary: futures::channel::mpsc::UnboundedSender<temporary::ProgressData>,
|
||||
futures_sender_zeroed: futures::channel::mpsc::UnboundedSender<zeroed::ProgressData>,
|
||||
futures_sender_invalid_symlinks: futures::channel::mpsc::UnboundedSender<invalid_symlinks::ProgressData>,
|
||||
futures_sender_broken_files: futures::channel::mpsc::UnboundedSender<broken_files::ProgressData>,
|
||||
) {
|
||||
|
@ -80,7 +78,6 @@ pub fn connect_button_search(
|
|||
let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone();
|
||||
let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone();
|
||||
let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone();
|
||||
let tree_view_zeroed_files_finder = gui_data.main_notebook.tree_view_zeroed_files_finder.clone();
|
||||
let tree_view_invalid_symlinks = gui_data.main_notebook.tree_view_invalid_symlinks.clone();
|
||||
let tree_view_broken_files = gui_data.main_notebook.tree_view_broken_files.clone();
|
||||
let text_view_errors = gui_data.text_view_errors.clone();
|
||||
|
@ -382,27 +379,6 @@ pub fn connect_button_search(
|
|||
let _ = glib_stop_sender.send(Message::SimilarVideos(sf));
|
||||
});
|
||||
}
|
||||
NotebookMainEnum::Zeroed => {
|
||||
label_stage.show();
|
||||
grid_progress_stages.show_all();
|
||||
window_progress.resize(1, 1);
|
||||
|
||||
get_list_store(&tree_view_zeroed_files_finder).clear();
|
||||
|
||||
let futures_sender_zeroed = futures_sender_zeroed.clone();
|
||||
// Find zeroed files
|
||||
thread::spawn(move || {
|
||||
let mut zf = ZeroedFiles::new();
|
||||
|
||||
zf.set_included_directory(included_directories);
|
||||
zf.set_excluded_directory(excluded_directories);
|
||||
zf.set_recursive_search(recursive_search);
|
||||
zf.set_excluded_items(excluded_items);
|
||||
zf.set_allowed_extensions(allowed_extensions);
|
||||
zf.find_zeroed_files(Some(&stop_receiver), Some(&futures_sender_zeroed));
|
||||
let _ = glib_stop_sender.send(Message::ZeroedFiles(zf));
|
||||
});
|
||||
}
|
||||
NotebookMainEnum::SameMusic => {
|
||||
label_stage.show();
|
||||
grid_progress_stages.show_all();
|
||||
|
|
|
@ -17,6 +17,7 @@ pub fn connect_button_select(gui_data: &GuiData) {
|
|||
{
|
||||
// Remember to update connect_popovers file, because this data are connected to each others
|
||||
hashmap.insert(NotebookMainEnum::SimilarImages, vec!["all", "image_size", "reverse", "custom", "date"]);
|
||||
hashmap.insert(NotebookMainEnum::SimilarVideos, vec!["all", "reverse", "custom", "date"]);
|
||||
hashmap.insert(NotebookMainEnum::Duplicate, vec!["all", "reverse", "custom", "date"]);
|
||||
hashmap.insert(NotebookMainEnum::SameMusic, vec!["all", "reverse", "custom", "date"]);
|
||||
|
||||
|
@ -24,7 +25,6 @@ pub fn connect_button_select(gui_data: &GuiData) {
|
|||
hashmap.insert(NotebookMainEnum::EmptyDirectories, vec!["all", "reverse", "custom"]);
|
||||
hashmap.insert(NotebookMainEnum::BigFiles, vec!["all", "reverse", "custom"]);
|
||||
hashmap.insert(NotebookMainEnum::Symlinks, vec!["all", "reverse", "custom"]);
|
||||
hashmap.insert(NotebookMainEnum::Zeroed, vec!["all", "reverse", "custom"]);
|
||||
hashmap.insert(NotebookMainEnum::Temporary, vec!["all", "reverse", "custom"]);
|
||||
hashmap.insert(NotebookMainEnum::BrokenFiles, vec!["all", "reverse", "custom"]);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
|||
let text_view_errors = gui_data.text_view_errors.clone();
|
||||
let shared_duplication_state = gui_data.shared_duplication_state.clone();
|
||||
let shared_buttons = gui_data.shared_buttons.clone();
|
||||
let tree_view_zeroed_files_finder = gui_data.main_notebook.tree_view_zeroed_files_finder.clone();
|
||||
let shared_empty_folders_state = gui_data.shared_empty_folders_state.clone();
|
||||
let shared_empty_files_state = gui_data.shared_empty_files_state.clone();
|
||||
let shared_broken_files_state = gui_data.shared_broken_files_state.clone();
|
||||
|
@ -37,7 +36,6 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
|||
let shared_temporary_files_state = gui_data.shared_temporary_files_state.clone();
|
||||
let shared_similar_images_state = gui_data.shared_similar_images_state.clone();
|
||||
let shared_similar_videos_state = gui_data.shared_similar_videos_state.clone();
|
||||
let shared_zeroed_files_state = gui_data.shared_zeroed_files_state.clone();
|
||||
let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone();
|
||||
let shared_same_music_state = gui_data.shared_same_music_state.clone();
|
||||
let buttons_names = gui_data.bottom_buttons.buttons_names.clone();
|
||||
|
@ -679,64 +677,6 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
|||
}
|
||||
}
|
||||
}
|
||||
Message::ZeroedFiles(zf) => {
|
||||
if zf.get_stopped_search() {
|
||||
entry_info.set_text("Searching for zeroed files was stopped by user");
|
||||
} else {
|
||||
let information = zf.get_information();
|
||||
let text_messages = zf.get_text_messages();
|
||||
|
||||
let zeroed_files_number: usize = information.number_of_zeroed_files;
|
||||
|
||||
entry_info.set_text(format!("Found {} zeroed files.", zeroed_files_number).as_str());
|
||||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = get_list_store(&tree_view_zeroed_files_finder);
|
||||
|
||||
let vector = zf.get_zeroed_files();
|
||||
|
||||
// Sort
|
||||
let mut vector = vector.clone();
|
||||
vector.sort_by_key(|e| {
|
||||
let t = split_path(e.path.as_path());
|
||||
(t.0, t.1)
|
||||
});
|
||||
|
||||
for file_entry in vector {
|
||||
let (directory, file) = split_path(&file_entry.path);
|
||||
let values: [(u32, &dyn ToValue); 6] = [
|
||||
(0, &false),
|
||||
(1, &(file_entry.size.file_size(options::BINARY).unwrap())),
|
||||
(2, &(file_entry.size)),
|
||||
(3, &file),
|
||||
(4, &directory),
|
||||
(5, &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())),
|
||||
];
|
||||
list_store.set(&list_store.append(), &values);
|
||||
}
|
||||
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||
}
|
||||
|
||||
// Set state
|
||||
{
|
||||
*shared_zeroed_files_state.borrow_mut() = zf;
|
||||
|
||||
if zeroed_files_number > 0 {
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("save").unwrap() = true;
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("delete").unwrap() = true;
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("select").unwrap() = true;
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("move").unwrap() = true;
|
||||
} else {
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("save").unwrap() = false;
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("delete").unwrap() = false;
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("select").unwrap() = false;
|
||||
*shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap().get_mut("move").unwrap() = false;
|
||||
}
|
||||
set_buttons(&mut *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::Zeroed).unwrap(), &buttons_array, &buttons_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::SameMusic(mf) => {
|
||||
if mf.get_stopped_search() {
|
||||
entry_info.set_text("Searching for same music was stopped by user");
|
||||
|
|
|
@ -699,6 +699,19 @@ pub fn connect_popovers(gui_data: &GuiData) {
|
|||
column_size_as_bytes: Some(ColumnsSimilarImages::SizeAsBytes as i32),
|
||||
column_modification_as_secs: Some(ColumnsSimilarImages::ModificationAsSecs as i32),
|
||||
},
|
||||
PopoverObject {
|
||||
notebook_type: NotebookMainEnum::SimilarVideos,
|
||||
available_modes: vec!["all", "reverse", "custom", "date"].iter().map(|e| e.to_string()).collect(),
|
||||
tree_view: gui_data.main_notebook.tree_view_similar_videos_finder.clone(),
|
||||
column_path: ColumnsSimilarVideos::Path as i32,
|
||||
column_name: ColumnsSimilarVideos::Name as i32,
|
||||
column_selection: ColumnsSimilarVideos::ActiveSelectButton as u32,
|
||||
column_color: Some(ColumnsSimilarVideos::Color as i32),
|
||||
column_dimensions: None,
|
||||
column_size: Some(ColumnsSimilarVideos::Size as i32),
|
||||
column_size_as_bytes: Some(ColumnsSimilarVideos::SizeAsBytes as i32),
|
||||
column_modification_as_secs: Some(ColumnsSimilarVideos::ModificationAsSecs as i32),
|
||||
},
|
||||
PopoverObject {
|
||||
notebook_type: NotebookMainEnum::EmptyDirectories,
|
||||
available_modes: vec!["all", "reverse", "custom"].iter().map(|e| e.to_string()).collect(),
|
||||
|
@ -751,19 +764,6 @@ pub fn connect_popovers(gui_data: &GuiData) {
|
|||
column_size_as_bytes: None,
|
||||
column_modification_as_secs: None,
|
||||
},
|
||||
PopoverObject {
|
||||
notebook_type: NotebookMainEnum::Zeroed,
|
||||
available_modes: vec!["all", "reverse", "custom"].iter().map(|e| e.to_string()).collect(),
|
||||
tree_view: gui_data.main_notebook.tree_view_zeroed_files_finder.clone(),
|
||||
column_path: ColumnsZeroedFiles::Path as i32,
|
||||
column_name: ColumnsZeroedFiles::Name as i32,
|
||||
column_selection: ColumnsZeroedFiles::ActiveSelectButton as u32,
|
||||
column_color: None,
|
||||
column_dimensions: None,
|
||||
column_size: None,
|
||||
column_size_as_bytes: Some(ColumnsZeroedFiles::SizeAsBytes as i32),
|
||||
column_modification_as_secs: None,
|
||||
},
|
||||
PopoverObject {
|
||||
notebook_type: NotebookMainEnum::BrokenFiles,
|
||||
available_modes: vec!["all", "reverse", "custom"].iter().map(|e| e.to_string()).collect(),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::gui_data::GuiData;
|
||||
use crate::taskbar_progress::tbp_flags::TBPF_INDETERMINATE;
|
||||
|
||||
use czkawka_core::{big_file, broken_files, duplicate, empty_files, empty_folder, invalid_symlinks, same_music, similar_images, similar_videos, temporary, zeroed};
|
||||
use czkawka_core::{big_file, broken_files, duplicate, empty_files, empty_folder, invalid_symlinks, same_music, similar_images, similar_videos, temporary};
|
||||
|
||||
use futures::StreamExt;
|
||||
|
||||
|
@ -18,7 +18,6 @@ pub fn connect_progress_window(
|
|||
mut futures_receiver_similar_images: futures::channel::mpsc::UnboundedReceiver<similar_images::ProgressData>,
|
||||
mut futures_receiver_similar_videos: futures::channel::mpsc::UnboundedReceiver<similar_videos::ProgressData>,
|
||||
mut futures_receiver_temporary: futures::channel::mpsc::UnboundedReceiver<temporary::ProgressData>,
|
||||
mut futures_receiver_zeroed: futures::channel::mpsc::UnboundedReceiver<zeroed::ProgressData>,
|
||||
mut futures_receiver_invalid_symlinks: futures::channel::mpsc::UnboundedReceiver<invalid_symlinks::ProgressData>,
|
||||
mut futures_receiver_broken_files: futures::channel::mpsc::UnboundedReceiver<broken_files::ProgressData>,
|
||||
) {
|
||||
|
@ -279,41 +278,6 @@ pub fn connect_progress_window(
|
|||
};
|
||||
main_context.spawn_local(future);
|
||||
}
|
||||
{
|
||||
// Zeroed Files
|
||||
let label_stage = gui_data.progress_window.label_stage.clone();
|
||||
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
|
||||
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
|
||||
let taskbar_state = gui_data.taskbar_state.clone();
|
||||
let future = async move {
|
||||
while let Some(item) = futures_receiver_zeroed.next().await {
|
||||
match item.current_stage {
|
||||
0 => {
|
||||
progress_bar_current_stage.hide();
|
||||
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
|
||||
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
|
||||
}
|
||||
1 => {
|
||||
progress_bar_current_stage.show();
|
||||
if item.files_to_check != 0 {
|
||||
progress_bar_all_stages.set_fraction((1f64 + (item.files_checked) as f64 / item.files_to_check as f64) / (item.max_stage + 1) as f64);
|
||||
progress_bar_current_stage.set_fraction((item.files_checked) as f64 / item.files_to_check as f64);
|
||||
taskbar_state.borrow().set_progress_value((item.files_to_check + item.files_checked) as u64, item.files_to_check as u64 * (item.max_stage + 1) as u64);
|
||||
} else {
|
||||
progress_bar_all_stages.set_fraction((1f64) / (item.max_stage + 1) as f64);
|
||||
progress_bar_current_stage.set_fraction(0f64);
|
||||
taskbar_state.borrow().set_progress_value(1, (item.max_stage + 1) as u64);
|
||||
}
|
||||
label_stage.set_text(format!("Checking {}/{} file", item.files_checked, item.files_to_check).as_str());
|
||||
}
|
||||
_ => {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
main_context.spawn_local(future);
|
||||
}
|
||||
{
|
||||
// Invalid Symlinks
|
||||
let label_stage = gui_data.progress_window.label_stage.clone();
|
||||
|
|
|
@ -439,65 +439,6 @@ pub fn create_tree_view_directories(tree_view: &mut gtk::TreeView) {
|
|||
tree_view.set_headers_visible(false);
|
||||
}
|
||||
|
||||
pub fn create_tree_view_zeroed_files(tree_view: &mut gtk::TreeView) {
|
||||
let model = get_list_store(tree_view);
|
||||
|
||||
let renderer = gtk::CellRendererToggle::new();
|
||||
renderer.connect_toggled(move |_r, path| {
|
||||
let iter = model.iter(&path).unwrap();
|
||||
let mut fixed = model
|
||||
.value(&iter, ColumnsZeroedFiles::ActiveSelectButton as i32)
|
||||
.get::<bool>()
|
||||
.unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err));
|
||||
fixed = !fixed;
|
||||
model.set_value(&iter, ColumnsZeroedFiles::ActiveSelectButton as u32, &fixed.to_value());
|
||||
});
|
||||
let column = gtk::TreeViewColumn::new();
|
||||
column.pack_start(&renderer, true);
|
||||
column.set_resizable(false);
|
||||
column.set_fixed_width(30);
|
||||
column.add_attribute(&renderer, "active", ColumnsZeroedFiles::ActiveSelectButton as i32);
|
||||
tree_view.append_column(&column);
|
||||
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
column.pack_start(&renderer, true);
|
||||
column.set_title("Size");
|
||||
column.set_resizable(true);
|
||||
column.set_min_width(50);
|
||||
column.add_attribute(&renderer, "text", ColumnsZeroedFiles::Size as i32);
|
||||
tree_view.append_column(&column);
|
||||
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
column.pack_start(&renderer, true);
|
||||
column.set_title("File Name");
|
||||
column.set_resizable(true);
|
||||
column.set_min_width(50);
|
||||
column.add_attribute(&renderer, "text", ColumnsZeroedFiles::Name as i32);
|
||||
tree_view.append_column(&column);
|
||||
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
column.pack_start(&renderer, true);
|
||||
column.set_title("Path");
|
||||
column.set_resizable(true);
|
||||
column.set_min_width(50);
|
||||
column.add_attribute(&renderer, "text", ColumnsZeroedFiles::Path as i32);
|
||||
tree_view.append_column(&column);
|
||||
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
column.pack_start(&renderer, true);
|
||||
column.set_title("Modification Date");
|
||||
column.set_resizable(true);
|
||||
column.set_min_width(50);
|
||||
column.add_attribute(&renderer, "text", ColumnsZeroedFiles::Modification as i32);
|
||||
tree_view.append_column(&column);
|
||||
|
||||
tree_view.set_vexpand(true);
|
||||
}
|
||||
|
||||
pub fn create_tree_view_same_music(tree_view: &mut gtk::TreeView) {
|
||||
let model = get_list_store(tree_view);
|
||||
|
||||
|
|
|
@ -66,18 +66,6 @@ pub fn opening_enter_function_big_files(tree_view: >k::TreeView, event: &gdk::
|
|||
handle_tree_keypress(tree_view, event, ColumnsBigFiles::Name as u32, ColumnsBigFiles::Path as u32, ColumnsBigFiles::ActiveSelectButton as u32)
|
||||
}
|
||||
|
||||
pub fn opening_double_click_function_zeroed_files(tree_view: >k::TreeView, event: &gdk::EventButton) -> gtk::Inhibit {
|
||||
if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 1 {
|
||||
common_open_function(tree_view, ColumnsZeroedFiles::Name as i32, ColumnsZeroedFiles::Path as i32, OpenMode::PathAndName);
|
||||
} else if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 3 {
|
||||
common_open_function(tree_view, ColumnsZeroedFiles::Name as i32, ColumnsZeroedFiles::Path as i32, OpenMode::OnlyPath);
|
||||
}
|
||||
gtk::Inhibit(false)
|
||||
}
|
||||
pub fn opening_enter_function_zeroed_files(tree_view: >k::TreeView, event: &gdk::EventKey) -> gtk::Inhibit {
|
||||
handle_tree_keypress(tree_view, event, ColumnsZeroedFiles::Name as u32, ColumnsZeroedFiles::Path as u32, ColumnsZeroedFiles::ActiveSelectButton as u32)
|
||||
}
|
||||
|
||||
pub fn opening_double_click_function_same_music(tree_view: >k::TreeView, event: &gdk::EventButton) -> gtk::Inhibit {
|
||||
if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 1 {
|
||||
common_open_function(tree_view, ColumnsSameMusic::Name as i32, ColumnsSameMusic::Path as i32, OpenMode::PathAndName);
|
||||
|
|
|
@ -19,7 +19,6 @@ use czkawka_core::same_music::SameMusic;
|
|||
use czkawka_core::similar_images::SimilarImages;
|
||||
use czkawka_core::similar_videos::SimilarVideos;
|
||||
use czkawka_core::temporary::Temporary;
|
||||
use czkawka_core::zeroed::ZeroedFiles;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Builder, WindowPosition};
|
||||
use std::cell::RefCell;
|
||||
|
@ -61,7 +60,6 @@ pub struct GuiData {
|
|||
pub shared_big_files_state: Rc<RefCell<BigFile>>,
|
||||
pub shared_similar_images_state: Rc<RefCell<SimilarImages>>,
|
||||
pub shared_similar_videos_state: Rc<RefCell<SimilarVideos>>,
|
||||
pub shared_zeroed_files_state: Rc<RefCell<ZeroedFiles>>,
|
||||
pub shared_same_music_state: Rc<RefCell<SameMusic>>,
|
||||
pub shared_same_invalid_symlinks: Rc<RefCell<InvalidSymlinks>>,
|
||||
pub shared_broken_files_state: Rc<RefCell<BrokenFiles>>,
|
||||
|
@ -142,7 +140,6 @@ impl GuiData {
|
|||
let shared_big_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(BigFile::new()));
|
||||
let shared_similar_images_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SimilarImages::new()));
|
||||
let shared_similar_videos_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SimilarVideos::new()));
|
||||
let shared_zeroed_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(ZeroedFiles::new()));
|
||||
let shared_same_music_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SameMusic::new()));
|
||||
let shared_same_invalid_symlinks: Rc<RefCell<_>> = Rc::new(RefCell::new(InvalidSymlinks::new()));
|
||||
let shared_broken_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(BrokenFiles::new()));
|
||||
|
@ -180,7 +177,6 @@ impl GuiData {
|
|||
shared_big_files_state,
|
||||
shared_similar_images_state,
|
||||
shared_similar_videos_state,
|
||||
shared_zeroed_files_state,
|
||||
shared_same_music_state,
|
||||
shared_same_invalid_symlinks,
|
||||
shared_broken_files_state,
|
||||
|
|
|
@ -12,7 +12,6 @@ pub struct GuiMainNotebook {
|
|||
pub scrolled_window_big_files_finder: gtk::ScrolledWindow,
|
||||
pub scrolled_window_similar_images_finder: gtk::ScrolledWindow,
|
||||
pub scrolled_window_similar_videos_finder: gtk::ScrolledWindow,
|
||||
pub scrolled_window_zeroed_files_finder: gtk::ScrolledWindow,
|
||||
pub scrolled_window_same_music_finder: gtk::ScrolledWindow,
|
||||
pub scrolled_window_invalid_symlinks: gtk::ScrolledWindow,
|
||||
pub scrolled_window_broken_files: gtk::ScrolledWindow,
|
||||
|
@ -24,7 +23,6 @@ pub struct GuiMainNotebook {
|
|||
pub tree_view_big_files_finder: gtk::TreeView,
|
||||
pub tree_view_similar_images_finder: gtk::TreeView,
|
||||
pub tree_view_similar_videos_finder: gtk::TreeView,
|
||||
pub tree_view_zeroed_files_finder: gtk::TreeView,
|
||||
pub tree_view_same_music_finder: gtk::TreeView,
|
||||
pub tree_view_invalid_symlinks: gtk::TreeView,
|
||||
pub tree_view_broken_files: gtk::TreeView,
|
||||
|
@ -92,7 +90,6 @@ impl GuiMainNotebook {
|
|||
let scrolled_window_big_files_finder: gtk::ScrolledWindow = builder.object("scrolled_window_big_files_finder").unwrap();
|
||||
let scrolled_window_similar_images_finder: gtk::ScrolledWindow = builder.object("scrolled_window_similar_images_finder").unwrap();
|
||||
let scrolled_window_similar_videos_finder: gtk::ScrolledWindow = builder.object("scrolled_window_similar_videos_finder").unwrap();
|
||||
let scrolled_window_zeroed_files_finder: gtk::ScrolledWindow = builder.object("scrolled_window_zeroed_files_finder").unwrap();
|
||||
let scrolled_window_same_music_finder: gtk::ScrolledWindow = builder.object("scrolled_window_same_music_finder").unwrap();
|
||||
let scrolled_window_invalid_symlinks: gtk::ScrolledWindow = builder.object("scrolled_window_invalid_symlinks").unwrap();
|
||||
let scrolled_window_broken_files: gtk::ScrolledWindow = builder.object("scrolled_window_broken_files").unwrap();
|
||||
|
@ -104,7 +101,6 @@ impl GuiMainNotebook {
|
|||
let tree_view_big_files_finder: gtk::TreeView = TreeView::new();
|
||||
let tree_view_similar_images_finder: gtk::TreeView = TreeView::new();
|
||||
let tree_view_similar_videos_finder: gtk::TreeView = TreeView::new();
|
||||
let tree_view_zeroed_files_finder: gtk::TreeView = TreeView::new();
|
||||
let tree_view_same_music_finder: gtk::TreeView = TreeView::new();
|
||||
let tree_view_invalid_symlinks: gtk::TreeView = TreeView::new();
|
||||
let tree_view_broken_files: gtk::TreeView = TreeView::new();
|
||||
|
@ -168,7 +164,6 @@ impl GuiMainNotebook {
|
|||
scrolled_window_big_files_finder,
|
||||
scrolled_window_similar_images_finder,
|
||||
scrolled_window_similar_videos_finder,
|
||||
scrolled_window_zeroed_files_finder,
|
||||
scrolled_window_same_music_finder,
|
||||
scrolled_window_invalid_symlinks,
|
||||
scrolled_window_broken_files,
|
||||
|
@ -179,7 +174,6 @@ impl GuiMainNotebook {
|
|||
tree_view_big_files_finder,
|
||||
tree_view_similar_images_finder,
|
||||
tree_view_similar_videos_finder,
|
||||
tree_view_zeroed_files_finder,
|
||||
tree_view_same_music_finder,
|
||||
tree_view_invalid_symlinks,
|
||||
tree_view_broken_files,
|
||||
|
|
|
@ -10,7 +10,6 @@ use czkawka_core::same_music::SameMusic;
|
|||
use czkawka_core::similar_images::SimilarImages;
|
||||
use czkawka_core::similar_videos::SimilarVideos;
|
||||
use czkawka_core::temporary::Temporary;
|
||||
use czkawka_core::zeroed::ZeroedFiles;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{ListStore, TextView};
|
||||
use std::collections::HashMap;
|
||||
|
@ -24,7 +23,6 @@ pub enum Message {
|
|||
Temporary(Temporary),
|
||||
SimilarImages(SimilarImages),
|
||||
SimilarVideos(SimilarVideos),
|
||||
ZeroedFiles(ZeroedFiles),
|
||||
SameMusic(SameMusic),
|
||||
InvalidSymlinks(InvalidSymlinks),
|
||||
BrokenFiles(BrokenFiles),
|
||||
|
@ -100,14 +98,6 @@ pub enum ColumnsSimilarVideos {
|
|||
Color,
|
||||
TextColor,
|
||||
}
|
||||
pub enum ColumnsZeroedFiles {
|
||||
ActiveSelectButton = 0,
|
||||
Size,
|
||||
SizeAsBytes,
|
||||
Name,
|
||||
Path,
|
||||
Modification,
|
||||
}
|
||||
pub enum ColumnsSameMusic {
|
||||
ActivatableSelectButton = 0,
|
||||
ActiveSelectButton,
|
||||
|
|
|
@ -46,7 +46,6 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
|
|||
let scrolled_window_similar_videos_finder = gui_data.main_notebook.scrolled_window_similar_videos_finder.clone();
|
||||
let scrolled_window_same_music_finder = gui_data.main_notebook.scrolled_window_same_music_finder.clone();
|
||||
let scrolled_window_invalid_symlinks = gui_data.main_notebook.scrolled_window_invalid_symlinks.clone();
|
||||
let scrolled_window_zeroed_files_finder = gui_data.main_notebook.scrolled_window_zeroed_files_finder.clone();
|
||||
let scrolled_window_broken_files = gui_data.main_notebook.scrolled_window_broken_files.clone();
|
||||
|
||||
let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone();
|
||||
|
@ -438,42 +437,6 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
|
|||
gtk::Inhibit(false)
|
||||
});
|
||||
}
|
||||
// Zeroed Files
|
||||
{
|
||||
let col_types: [glib::types::Type; 6] = [
|
||||
glib::types::Type::BOOL,
|
||||
glib::types::Type::STRING,
|
||||
glib::types::Type::U64,
|
||||
glib::types::Type::STRING,
|
||||
glib::types::Type::STRING,
|
||||
glib::types::Type::STRING,
|
||||
];
|
||||
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
||||
|
||||
let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
|
||||
|
||||
tree_view.selection().set_mode(SelectionMode::Multiple);
|
||||
|
||||
create_tree_view_zeroed_files(&mut tree_view);
|
||||
|
||||
tree_view.connect_button_press_event(opening_double_click_function_zeroed_files);
|
||||
tree_view.connect_key_press_event(opening_enter_function_zeroed_files);
|
||||
|
||||
gui_data.main_notebook.tree_view_zeroed_files_finder = tree_view.clone();
|
||||
scrolled_window_zeroed_files_finder.add(&tree_view);
|
||||
scrolled_window_zeroed_files_finder.show_all();
|
||||
|
||||
let gui_data = gui_data.clone();
|
||||
tree_view.connect_key_release_event(move |tree_view, e| {
|
||||
if let Some(button_number) = e.keycode() {
|
||||
// Handle delete button
|
||||
if button_number == 119 {
|
||||
basic_remove(tree_view, ColumnsZeroedFiles::Name as i32, ColumnsZeroedFiles::Path as i32, ColumnsZeroedFiles::ActiveSelectButton as i32, &gui_data);
|
||||
}
|
||||
}
|
||||
gtk::Inhibit(false)
|
||||
});
|
||||
}
|
||||
// Same Music
|
||||
{
|
||||
let col_types: [glib::types::Type; 15] = [
|
||||
|
|
|
@ -102,7 +102,6 @@ fn main() {
|
|||
let (futures_sender_similar_videos, futures_receiver_similar_videos): (futures::channel::mpsc::UnboundedSender<similar_videos::ProgressData>, futures::channel::mpsc::UnboundedReceiver<similar_videos::ProgressData>) =
|
||||
futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::UnboundedSender<temporary::ProgressData>, futures::channel::mpsc::UnboundedReceiver<temporary::ProgressData>) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_zeroed, futures_receiver_zeroed): (futures::channel::mpsc::UnboundedSender<zeroed::ProgressData>, futures::channel::mpsc::UnboundedReceiver<zeroed::ProgressData>) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (futures::channel::mpsc::UnboundedSender<invalid_symlinks::ProgressData>, futures::channel::mpsc::UnboundedReceiver<invalid_symlinks::ProgressData>) =
|
||||
futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_broken_files, futures_receiver_broken_files): (futures::channel::mpsc::UnboundedSender<broken_files::ProgressData>, futures::channel::mpsc::UnboundedReceiver<broken_files::ProgressData>) = futures::channel::mpsc::unbounded();
|
||||
|
@ -124,7 +123,6 @@ fn main() {
|
|||
futures_sender_similar_images,
|
||||
futures_sender_similar_videos,
|
||||
futures_sender_temporary,
|
||||
futures_sender_zeroed,
|
||||
futures_sender_invalid_symlinks,
|
||||
futures_sender_broken_files,
|
||||
);
|
||||
|
@ -147,7 +145,6 @@ fn main() {
|
|||
futures_receiver_similar_images,
|
||||
futures_receiver_similar_videos,
|
||||
futures_receiver_temporary,
|
||||
futures_receiver_zeroed,
|
||||
futures_receiver_invalid_symlinks,
|
||||
futures_receiver_broken_files,
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = 11;
|
||||
pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = 10;
|
||||
pub const NUMBER_OF_NOTEBOOK_UPPER_TABS: usize = 4;
|
||||
|
||||
// Needs to be updated when changed order of notebook tabs
|
||||
|
@ -12,7 +12,6 @@ pub enum NotebookMainEnum {
|
|||
SimilarImages,
|
||||
SimilarVideos,
|
||||
SameMusic,
|
||||
Zeroed,
|
||||
Symlinks,
|
||||
BrokenFiles,
|
||||
}
|
||||
|
@ -26,9 +25,8 @@ pub fn to_notebook_main_enum(notebook_number: u32) -> NotebookMainEnum {
|
|||
5 => NotebookMainEnum::SimilarImages,
|
||||
6 => NotebookMainEnum::SimilarVideos,
|
||||
7 => NotebookMainEnum::SameMusic,
|
||||
8 => NotebookMainEnum::Zeroed,
|
||||
9 => NotebookMainEnum::Symlinks,
|
||||
10 => NotebookMainEnum::BrokenFiles,
|
||||
8 => NotebookMainEnum::Symlinks,
|
||||
9 => NotebookMainEnum::BrokenFiles,
|
||||
_ => panic!("Invalid Notebook Tab"),
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +42,6 @@ pub fn get_all_main_tabs() -> [NotebookMainEnum; NUMBER_OF_NOTEBOOK_MAIN_TABS] {
|
|||
to_notebook_main_enum(7),
|
||||
to_notebook_main_enum(8),
|
||||
to_notebook_main_enum(9),
|
||||
to_notebook_main_enum(10),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1926,42 +1926,6 @@ Author: Rafał Mikrut
|
|||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window_zeroed_files_finder">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Zeroed Files</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">8</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window_invalid_symlinks">
|
||||
<property name="visible">True</property>
|
||||
|
@ -1972,7 +1936,7 @@ Author: Rafał Mikrut
|
|||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">9</property>
|
||||
<property name="position">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
|
@ -1982,7 +1946,7 @@ Author: Rafał Mikrut
|
|||
<property name="label" translatable="yes">Invalid Symlinks</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">9</property>
|
||||
<property name="position">8</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -1996,7 +1960,7 @@ Author: Rafał Mikrut
|
|||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">10</property>
|
||||
<property name="position">9</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
|
@ -2006,7 +1970,7 @@ Author: Rafał Mikrut
|
|||
<property name="label" translatable="yes">Broken Files</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">10</property>
|
||||
<property name="position">9</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
|
|
@ -169,14 +169,6 @@ Currently files with these extensions are considered temporary files -
|
|||
|
||||
This only removes the most basic temporary files, for more I suggest to use BleachBit.
|
||||
|
||||
### Zeroed Files
|
||||
Zeroed files very often are results of e.g. incorrect file downloads.
|
||||
|
||||
Their search consists of 3 steps:
|
||||
- Collecting a list of all files with a size greater than 0
|
||||
- At start, 64 bytes of each file are checked to discard the vast majority of non-zero files without major performance losses.
|
||||
- The next step is to check the rest of the file with bigger parts(32KB)
|
||||
|
||||
### Invalid Symlinks
|
||||
To find invalid symlinks we must first find symlnks.
|
||||
|
||||
|
|
Loading…
Reference in New Issue