Merge with 70bfb0d (ThomasCX/defragfs)

This commit is contained in:
q3aql 2021-03-22 12:31:05 +01:00
parent 4e68d4c222
commit cf20e82b54

109
defragfs
View File

@ -7,11 +7,17 @@
# Using: $ sudo ./defragfs / -af
# Help: $ ./defragfs / -h
use strict;
use warnings;
print ("defragfs 1.1.1, Released under GPLv3 by John Robson <john.robson\@usp.br>, March 2011 (help: \$ defragfs / -h)\n\n");
($DIR, $ARG) = @ARGV;
my $NEEDHELP = 0;
my ($DIR, $ARG);
$DIR = shift(@ARGV);
$ARG = join(" ", @ARGV);
if($ARG =~ m/h/) { die("GNU/Linux file systems rarely fragmented files. The file system always allocates more space to write a file, but sometimes the file size grows so that space becomes insufficient and the file is fragmented, but even so the file system fragments the file efficiently.
if($ARG =~ m/(^|\s)-\S*h/) { die("GNU/Linux file systems rarely fragment files. The file system always allocates more space to write a file, but sometimes the file size grows so that space becomes insufficient and the file is fragmented, but even so the file system fragments the file efficiently.
Using defragfs:
@ -66,37 +72,49 @@ if (!(-e $DIR) || !(-d $DIR)) { die "You must specify a correct directory name!
my $AUTO = 0;
my $FORCE = 0;
if($ARG =~ m/a/) { $AUTO = 1; }
if($ARG =~ m/f/) { $FORCE = 1; }
if($ARG =~ m/(^|\s)-\S*a/) { $AUTO = 1; }
if($ARG =~ m/(^|\s)-\S*f/) { $FORCE = 1; }
if($ARG =~ m/-\S*([^afh ])\S*/) {
print "FATAL: unknown flag '$1' was used.\n";
$NEEDHELP = 1;
}
if (($DIR eq "") || ($DIR =~ m/-/)) { die "Usage: defragfs.pl DIRECTORY [-af], -af means force automatic defragmentation
if (($DIR eq "") || ($DIR =~ m/^-/) || $NEEDHELP) { die "Usage: defragfs.pl DIRECTORY [-af], -af means force automatic defragmentation
"; }
start:
print ("Analysis in progress...\n\n");
print ("Analysis in progress...\n");
my $files = 0; # number of files
my $fragments = 0; # number of fragment before defrag
my $fragfiles = 0; # number of fragmented files before defrag
my $TMP_filefrag_1 = "/tmp/frags-result-tmp";
my $TMP_filefrag_2 = "/tmp/frags-result";
my $TMP_defrag_filelist_1 = "/tmp/defrag-filelist-tmp";
my $TMP_defrag_filelist_2 = "/tmp/defrag-filelist";
my @hash_chars = ("0".."9", "A".."Z", "a".."z");
my $random_chars = randomChars(4);
my $TMP_filefrag_1 = "/tmp/frags-result-tmp$random_chars";
my $TMP_filefrag_2 = "/tmp/frags-result$random_chars";
my $TMP_defrag_filelist_1 = "/tmp/defrag-filelist-tmp$random_chars";
my $TMP_defrag_filelist_2 = "/tmp/defrag-filelist$random_chars";
my $max_fragrate = 1; # max "File Fragmentation Rate" used to determine whether worth defrag.
my $max_avgfrags = 1.1; # max "Avg File Fragments" used to determine whether worth defrag.
my $default_defrag_ratio; # default defragmentation ratio in percentage
my $max_display_num = 10; # display how much files in report
my $total_defrag_files = 0; # which files to be defrag, determined after user input the ratio
my $max_tries = 1; # max "Max Tries" used to determine max attempts to defrag a file after first attempt.
# variables used during defrag process
my $defrag_ratio;
my $confirm;
system("rm -f $TMP_filefrag_1");
system("rm -f $TMP_filefrag_2");
system("rm -f $TMP_defrag_filelist_1");
system("rm -f $TMP_defrag_filelist_2");
unlink($TMP_filefrag_1, $TMP_filefrag_2, $TMP_defrag_filelist_1, $TMP_defrag_filelist_2);
# cleanup on aborts
$SIG{'INT'} = $SIG{'QUIT'} = $SIG{'ABRT'} = $SIG{'TERM'} = \&abort;
my $progress = 0;
my $starttime = time();
my $lasttime = $starttime;
open (FILES, "find \"" . $DIR . "\" -xdev -type f |");
while (defined (my $file = <FILES>)) {
chomp($file);
$file =~ s/!/\\!/g;
$file =~ s/#/\\#/g;
$file =~ s/&/\\&/g;
@ -105,27 +123,44 @@ while (defined (my $file = <FILES>)) {
$file =~ s/\$/\\\$/g;
$file =~ s/\(/\\\(/g;
$file =~ s/\)/\\\)/g;
$file =~ s/\;/\\\;/g;
$file =~ s/\|/\\\|/g;
$file =~ s/'/\\'/g;
$file =~ s/"/\\"/g;
$file =~ s/ /\\ /g;
open (FRAG, "filefrag $file |");
my $res = <FRAG>;
if ($res =~ m/.*:\s+(\d+) extents? found/) {
my $fragment = $1;
if ($fragment eq 0) { $fragment = 1; }
if ($fragment eq 0) {
my $size = (stat($file))[7];
if ($size > 0) {
printf("\rSystem reports zero fragments for '$file' with size $size bytes. Perhaps file is locked, in use, or missing permissions?\n");
}
$fragment = 1;
}
$fragments+=$fragment;
if ($fragment > 1) {
system("echo -n \"$res\" >> $TMP_filefrag_1");
$fragfiles++;
}
$files++;
} else {
printf("\rFailed to parse fragmentation for: $file\n");
}
close (FRAG);
if (($progress++ % 1000) eq 0) { print "."; }
my $now = time();
if ($now != $lasttime) {
my $et = $now - $starttime;
my $rate = int($progress / $et);
print "\r $progress files analyzed in $et seconds @ $rate files/sec";
$lasttime = $now;
}
if (($progress++ % 100) == 0) { print ". \b"; }
}
close (FILES);
if ($files eq 0) {
if ($files == 0) {
print ("The selected directory contains no file!\n");
exit;
}
@ -148,10 +183,10 @@ if ($fragfiles > 0) {
exit;
}
$default_defrag_ratio = ($files eq 1) ? 100 : ($fragfiles / $files) * 100;
$default_defrag_ratio = ($files == 1) ? 100 : ($fragfiles / $files) * 100;
if (((($fragfiles / $files) * 100) > $max_fragrate) || (($fragments / $files) > $max_avgfrags) || ($FORCE)) {
print ("\nYou need a defragmentation or Your are using -f parameter!\n");
print ("\nYou need a defragmentation or you are using -f parameter!\n");
} else {
print ("\nYou do not need a defragmentation!\n");
exit;
@ -183,14 +218,16 @@ while (<TMPFRAGLIST>) {
my $filename = $1;
system("echo \"$1\" >> $TMP_defrag_filelist_2");
}
close TMPFRAGLIST;
open (GETSIZE, "$TMP_defrag_filelist_2");
my $max = 0;
while (<GETSIZE>) {
s/(.*)\n/$1/;
$size = -s "$_";
my $size = -s "$_";
if ($size > $max) { $max = $size; }
}
close GETSIZE;
print ("You need AT LEAST " . sprintf("%.3f", $max / 1048576) . " Megabytes temporarily used for defragmentation (at the directory where you specified), continue (Y/N)? [Y] ");
if ($AUTO) { $confirm = "" }
@ -201,13 +238,16 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
print ("\nOK, please drink a cup of tea and wait...\n");
print ("\nFile Number - File Name (Size Mb) [actual extents] - extents after defrag attempt\n");
my $actual_file = $total_defrag_files;
my $total_fragments_eliminated = 0;
open (DEFRAG, "$TMP_defrag_filelist_2");
while (<DEFRAG>) {
s/(.*)\n/$1/;
$from = $_;
s/(.*)/$1.ft/;
$to = $_;
my $from = $_;
my $to = $1 . ".defrag_tmp$random_chars";
while (-e $to) {
$to .= randomChars(1);
}
my $i_file = $actual_file;
my $i_tries = 0;
@ -218,6 +258,7 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
open (FRAG, "-|", "filefrag", $from);
$res = <FRAG>;
close FRAG;
if ($res =~ m/.*:\s+(\d+) extents? found/) { $fragment_from = $1; }
if ($i_file eq $actual_file) {
@ -239,11 +280,13 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
} else {
open (FRAG, "-|", "filefrag", $to);
$res = <FRAG>;
close FRAG;
if ($res =~ m/.*:\s+(\d+) extents? found/) { $fragment_to = $1; }
if ($fragment_to <= $fragment_from) { # <= not just <
system("mv -f \"$to\" \"$from\" 2>/dev/null");
print "$fragment_to ";
$total_fragments_eliminated += ($fragment_from - $fragment_to);
if ($fragment_to eq 1) { last; }
if ($fragment_to eq $fragment_from) { $i_tries++; }
if ($fragment_to < $fragment_from) { $i_tries--; }
@ -255,9 +298,12 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
system("sync");
}
}
close DEFRAG;
unlink($TMP_filefrag_1, $TMP_filefrag_2, $TMP_defrag_filelist_1, $TMP_defrag_filelist_2);
system("sync");
print ("\n\nDone!\n\n");
print ("\n\nDone - Eliminated $total_fragments_eliminated excess fragments this pass.\n\n");
if ($AUTO) { exit; }
else { goto start; }
@ -265,3 +311,18 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
exit;
}
sub randomChars {
my $cnt = shift;
my $str = "";
for(;$cnt>0;$cnt--) {
$str .= $hash_chars[rand @hash_chars];
}
return $str;
}
sub abort {
print "interrupt signaled, cleaning up...\n";
unlink($TMP_filefrag_1, $TMP_filefrag_2, $TMP_defrag_filelist_1, $TMP_defrag_filelist_2);
exit(1);
}