Merge with 70bfb0d (ThomasCX/defragfs)
This commit is contained in:
parent
4e68d4c222
commit
cf20e82b54
109
defragfs
109
defragfs
|
@ -7,11 +7,17 @@
|
||||||
# Using: $ sudo ./defragfs / -af
|
# Using: $ sudo ./defragfs / -af
|
||||||
# Help: $ ./defragfs / -h
|
# 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");
|
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:
|
Using defragfs:
|
||||||
|
|
||||||
|
@ -66,37 +72,49 @@ if (!(-e $DIR) || !(-d $DIR)) { die "You must specify a correct directory name!
|
||||||
my $AUTO = 0;
|
my $AUTO = 0;
|
||||||
my $FORCE = 0;
|
my $FORCE = 0;
|
||||||
|
|
||||||
if($ARG =~ m/a/) { $AUTO = 1; }
|
if($ARG =~ m/(^|\s)-\S*a/) { $AUTO = 1; }
|
||||||
if($ARG =~ m/f/) { $FORCE = 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:
|
start:
|
||||||
print ("Analysis in progress...\n\n");
|
print ("Analysis in progress...\n");
|
||||||
|
|
||||||
my $files = 0; # number of files
|
my $files = 0; # number of files
|
||||||
my $fragments = 0; # number of fragment before defrag
|
my $fragments = 0; # number of fragment before defrag
|
||||||
my $fragfiles = 0; # number of fragmented files before defrag
|
my $fragfiles = 0; # number of fragmented files before defrag
|
||||||
my $TMP_filefrag_1 = "/tmp/frags-result-tmp";
|
my @hash_chars = ("0".."9", "A".."Z", "a".."z");
|
||||||
my $TMP_filefrag_2 = "/tmp/frags-result";
|
my $random_chars = randomChars(4);
|
||||||
my $TMP_defrag_filelist_1 = "/tmp/defrag-filelist-tmp";
|
my $TMP_filefrag_1 = "/tmp/frags-result-tmp$random_chars";
|
||||||
my $TMP_defrag_filelist_2 = "/tmp/defrag-filelist";
|
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_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 $max_avgfrags = 1.1; # max "Avg File Fragments" used to determine whether worth defrag.
|
||||||
my $default_defrag_ratio; # default defragmentation ratio in percentage
|
my $default_defrag_ratio; # default defragmentation ratio in percentage
|
||||||
my $max_display_num = 10; # display how much files in report
|
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 $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.
|
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");
|
unlink($TMP_filefrag_1, $TMP_filefrag_2, $TMP_defrag_filelist_1, $TMP_defrag_filelist_2);
|
||||||
system("rm -f $TMP_filefrag_2");
|
|
||||||
system("rm -f $TMP_defrag_filelist_1");
|
# cleanup on aborts
|
||||||
system("rm -f $TMP_defrag_filelist_2");
|
$SIG{'INT'} = $SIG{'QUIT'} = $SIG{'ABRT'} = $SIG{'TERM'} = \&abort;
|
||||||
|
|
||||||
my $progress = 0;
|
my $progress = 0;
|
||||||
|
my $starttime = time();
|
||||||
|
my $lasttime = $starttime;
|
||||||
open (FILES, "find \"" . $DIR . "\" -xdev -type f |");
|
open (FILES, "find \"" . $DIR . "\" -xdev -type f |");
|
||||||
while (defined (my $file = <FILES>)) {
|
while (defined (my $file = <FILES>)) {
|
||||||
|
chomp($file);
|
||||||
$file =~ s/!/\\!/g;
|
$file =~ s/!/\\!/g;
|
||||||
$file =~ s/#/\\#/g;
|
$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;
|
$file =~ s/\|/\\\|/g;
|
||||||
$file =~ s/'/\\'/g;
|
$file =~ s/'/\\'/g;
|
||||||
|
$file =~ s/"/\\"/g;
|
||||||
$file =~ s/ /\\ /g;
|
$file =~ s/ /\\ /g;
|
||||||
open (FRAG, "filefrag $file |");
|
open (FRAG, "filefrag $file |");
|
||||||
my $res = <FRAG>;
|
my $res = <FRAG>;
|
||||||
if ($res =~ m/.*:\s+(\d+) extents? found/) {
|
if ($res =~ m/.*:\s+(\d+) extents? found/) {
|
||||||
my $fragment = $1;
|
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;
|
$fragments+=$fragment;
|
||||||
if ($fragment > 1) {
|
if ($fragment > 1) {
|
||||||
system("echo -n \"$res\" >> $TMP_filefrag_1");
|
system("echo -n \"$res\" >> $TMP_filefrag_1");
|
||||||
$fragfiles++;
|
$fragfiles++;
|
||||||
}
|
}
|
||||||
$files++;
|
$files++;
|
||||||
|
} else {
|
||||||
|
printf("\rFailed to parse fragmentation for: $file\n");
|
||||||
}
|
}
|
||||||
close (FRAG);
|
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);
|
close (FILES);
|
||||||
|
|
||||||
if ($files eq 0) {
|
if ($files == 0) {
|
||||||
print ("The selected directory contains no file!\n");
|
print ("The selected directory contains no file!\n");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
@ -148,10 +183,10 @@ if ($fragfiles > 0) {
|
||||||
exit;
|
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)) {
|
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 {
|
} else {
|
||||||
print ("\nYou do not need a defragmentation!\n");
|
print ("\nYou do not need a defragmentation!\n");
|
||||||
exit;
|
exit;
|
||||||
|
@ -183,14 +218,16 @@ while (<TMPFRAGLIST>) {
|
||||||
my $filename = $1;
|
my $filename = $1;
|
||||||
system("echo \"$1\" >> $TMP_defrag_filelist_2");
|
system("echo \"$1\" >> $TMP_defrag_filelist_2");
|
||||||
}
|
}
|
||||||
|
close TMPFRAGLIST;
|
||||||
|
|
||||||
open (GETSIZE, "$TMP_defrag_filelist_2");
|
open (GETSIZE, "$TMP_defrag_filelist_2");
|
||||||
my $max = 0;
|
my $max = 0;
|
||||||
while (<GETSIZE>) {
|
while (<GETSIZE>) {
|
||||||
s/(.*)\n/$1/;
|
s/(.*)\n/$1/;
|
||||||
$size = -s "$_";
|
my $size = -s "$_";
|
||||||
if ($size > $max) { $max = $size; }
|
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] ");
|
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 = "" }
|
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 ("\nOK, please drink a cup of tea and wait...\n");
|
||||||
print ("\nFile Number - File Name (Size Mb) [actual extents] - extents after defrag attempt\n");
|
print ("\nFile Number - File Name (Size Mb) [actual extents] - extents after defrag attempt\n");
|
||||||
my $actual_file = $total_defrag_files;
|
my $actual_file = $total_defrag_files;
|
||||||
|
my $total_fragments_eliminated = 0;
|
||||||
open (DEFRAG, "$TMP_defrag_filelist_2");
|
open (DEFRAG, "$TMP_defrag_filelist_2");
|
||||||
|
|
||||||
while (<DEFRAG>) {
|
while (<DEFRAG>) {
|
||||||
s/(.*)\n/$1/;
|
s/(.*)\n/$1/;
|
||||||
$from = $_;
|
my $from = $_;
|
||||||
s/(.*)/$1.ft/;
|
my $to = $1 . ".defrag_tmp$random_chars";
|
||||||
$to = $_;
|
while (-e $to) {
|
||||||
|
$to .= randomChars(1);
|
||||||
|
}
|
||||||
|
|
||||||
my $i_file = $actual_file;
|
my $i_file = $actual_file;
|
||||||
my $i_tries = 0;
|
my $i_tries = 0;
|
||||||
|
@ -218,6 +258,7 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
|
||||||
|
|
||||||
open (FRAG, "-|", "filefrag", $from);
|
open (FRAG, "-|", "filefrag", $from);
|
||||||
$res = <FRAG>;
|
$res = <FRAG>;
|
||||||
|
close FRAG;
|
||||||
if ($res =~ m/.*:\s+(\d+) extents? found/) { $fragment_from = $1; }
|
if ($res =~ m/.*:\s+(\d+) extents? found/) { $fragment_from = $1; }
|
||||||
|
|
||||||
if ($i_file eq $actual_file) {
|
if ($i_file eq $actual_file) {
|
||||||
|
@ -239,11 +280,13 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
|
||||||
} else {
|
} else {
|
||||||
open (FRAG, "-|", "filefrag", $to);
|
open (FRAG, "-|", "filefrag", $to);
|
||||||
$res = <FRAG>;
|
$res = <FRAG>;
|
||||||
|
close FRAG;
|
||||||
if ($res =~ m/.*:\s+(\d+) extents? found/) { $fragment_to = $1; }
|
if ($res =~ m/.*:\s+(\d+) extents? found/) { $fragment_to = $1; }
|
||||||
|
|
||||||
if ($fragment_to <= $fragment_from) { # <= not just <
|
if ($fragment_to <= $fragment_from) { # <= not just <
|
||||||
system("mv -f \"$to\" \"$from\" 2>/dev/null");
|
system("mv -f \"$to\" \"$from\" 2>/dev/null");
|
||||||
print "$fragment_to ";
|
print "$fragment_to ";
|
||||||
|
$total_fragments_eliminated += ($fragment_from - $fragment_to);
|
||||||
if ($fragment_to eq 1) { last; }
|
if ($fragment_to eq 1) { last; }
|
||||||
if ($fragment_to eq $fragment_from) { $i_tries++; }
|
if ($fragment_to eq $fragment_from) { $i_tries++; }
|
||||||
if ($fragment_to < $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");
|
system("sync");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
close DEFRAG;
|
||||||
|
|
||||||
|
unlink($TMP_filefrag_1, $TMP_filefrag_2, $TMP_defrag_filelist_1, $TMP_defrag_filelist_2);
|
||||||
|
|
||||||
system("sync");
|
system("sync");
|
||||||
print ("\n\nDone!\n\n");
|
print ("\n\nDone - Eliminated $total_fragments_eliminated excess fragments this pass.\n\n");
|
||||||
|
|
||||||
if ($AUTO) { exit; }
|
if ($AUTO) { exit; }
|
||||||
else { goto start; }
|
else { goto start; }
|
||||||
|
@ -265,3 +311,18 @@ if (($confirm eq "y") || ($confirm eq "Y") || ($confirm eq "")) {
|
||||||
exit;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user