# cprsOldFiles.pl compresses all files under an NTFS directory which have not been accessed for # nDaysToCheck days. It works by calling NT's commandline COMPACT command. # # Original code written 23-sep-1999 by Frank Brown. # # Requirements: # ------------ # 1. Only works on NTFS disks (COMPACT doesn't work on FAT volumes). # 2. If dir is on a network drive, requires a net connection before calling # this script (doesn't parse UNC specs)...for example: # # net use L: \\axpa\users require "ctime.pl"; ### global variables: ### $bDebug = 0; $sAppName = "cprsOldFiles"; $sDefRptFile = $sAppName . ".rpt"; $nDirsRead = 0; $nFilesCompressed = 0; $nFilesRead = 0; $sNow = &ctime(time); chop $sNow; $bRecurse = 0; $sRoot = ""; $sTmpDir = $ENV{'TEMP'}; $sRptFile = ""; $sVersion = "0.1"; ### date calculation vars: $nDaysToCheck = 90; # default to 90 days if no arg passed $nNow = time(); $n1day = 24 * 60 * 60; $nDaysVal = $n1day * $nDaysToCheck; $nEarliestAllowed = $nNow - $nDaysVal; ### let's go: MAIN: unless ($#ARGV + 1) { die "No directory on command line.\n"; } # somebody give me an arg! &ParseCmdArgs(); if ($sRoot eq "") { die "Root folder missing from command line"; } print "$sAppName $sVersion starting on $sNow...\n"; ### removed code to validate $sRoot is on an NTFS volume here! ### print "Will compact files that have not been accessed for at least $nDaysToCheck days.\n"; &ProcessDir($sRoot); $sNow = &ctime(time); print "\n$sAppName $sVersion finished at $sNow"; if ($nFilesCompressed == 0) { print "No files compacted.\n"; goto _noCompresso; } $sMsg = "$sAppName: compacted $nFilesCompressed file"; if ($nFilesCompressed > 1) { $sMsg .= "s"; } print "$sMsg\n"; &ShowFileDates(); if ($sRptFile ne "") { &WriteReport(); } _noCompresso: $sFword = "file"; if ($nFilesRead > 1) { $sFword .= "s"; } $sDirWord = "folder"; if ($nDirsRead > 1) { $sDirWord .= "s"; } print "Processed $nFilesRead $sFword in $nDirsRead $sDirWord.\n"; exit; ######## subroutines start here: ######### sub Help { print "\n$sAppName $sVersion compacts old files on an NTFS volume.\n\n"; print "usage: $sAppName [/s] [/days=n] [/out=reportFile] dir\n\n"; print "/s\trecurse through subdirectories\n"; print "/days\tfile age in days (greater or equal) to compact (default=$nDaysToCheck)\n"; print "/out\twrite report file\n"; } sub IsNumeric { local $nVal = $_[0]; return ($nVal =~ m/^[0-9]+$/); } sub ParseCmdArgs { while (@ARGV) { $_ = shift @ARGV; if ($bDebug) { print "debug: parsing cmdline arg $_\n"; } if (/^[\/\-]/) { # is arg a switch? $arg = substr($_,1,3); $arg =~ tr/A-Z/a-z/; # lowercase arg if ($arg eq "deb") { $bDebug = 1; } if ($bDebug) { print "dbg: arg=$arg\n"; } if ($arg eq "hel" || substr($arg,0,1) eq '?') { &Help(); exit; } if (substr($arg,0,1) eq 's') { $bRecurse = 1; } if ($arg eq "out") { $i = index($_,"="); $i++; $sRptFile = substr($_,$i); if ($sRptFile eq "") { $sRptFile = $sDefRptFile; } } if ($arg eq "day") { $i = index($_,"="); $i++; $nDays = substr($_,$i); if (IsNumeric($nDays)) { $nDaysToCheck = $nDays; } else { print "Error: days $nDays not a number.\n"; exit; } } } else { $sRoot = $_; } } if ($bDebug) { print "dbg: bDebug = $bDebug\n"; print "dbg: sRoot = $sRoot\n"; print "dbg: DaysToCheck = $nDaysToCheck\n"; print "dbg: recurse = $bRecurse\n"; if ($sRptFile ne "") { print "dbg: sRptFile = $sRptFile\n"; } } } sub ProcessDir { local $sDir = $_[0]; if (!length($sDir)) { return; } if ($sDir eq "." || $sDir eq "..") { return; } print "processing dir $sDir...\n"; if (!opendir(FLDR,$sDir)) { print "Can't open folder $sDir\n"; return; } ++$nDirsRead; local @filenames = readdir(FLDR); # get list of files closedir(FLDR); foreach (@filenames) { if ($_ eq "." || $_ eq "..") { next; } $sFile = $sDir; if ($sDir !~ m/\\+$/) { $sFile .= "\\"; } # if no \\ then add one $sFile .= $_; if ( -f $sFile) { &ProcessFile($sFile); } else { if ($bRecurse) { &ProcessDir($sFile); } } } } sub ProcessFile { local $sChkFile = $_[0]; local @dates; local @sortedDates; ++$nFilesRead; push @dates,(stat($sChkFile))[8]; # last access timestamp push @dates,(stat($sChkFile))[9]; # modified timestamp push @dates,(stat($sChkFile))[10]; # creation timestamp @sortedDates = sort numerically @dates; $nMostRecent = pop @sortedDates; if ($nMostRecent < $nEarliestAllowed) { print "Compressing $sChkFile...\n"; $sCmd = sprintf("compact /c /q \"$sChkFile\""); if ($bDebug) { print "dbg: *** $sCmd ***\n"; } else { system($sCmd); } ++$nFilesCompressed; $hOldFiles{$nMostRecent} = $sChkFile; # save in hash } } sub numerically { $a <=> $b; } sub ShowFileDates { @sortedKeys = sort numerically keys(%hOldFiles); $nYoungestKey = pop @sortedKeys; while (@sortedKeys) { $nOldestKey = pop @sortedKeys; } local $sOldDate = &ctime($nOldestKey); chomp($sOldDate); local $sYoungDate = &ctime($nYoungestKey); chomp($sYoungDate); print "oldest: $hOldFiles{$nOldestKey} $sOldDate\n"; print "newest: $hOldFiles{$nYoungestKey} $sYoungDate\n"; } sub WriteReport { local $sLine = ""; local $sFile = ">" . $sRptFile; open(RPT,$sFile) || die "Can't open report file $sRptFile: $!"; @sortedKeys = sort numerically keys(%hOldFiles); local $nTotal = @sortedKeys; $sNow = &ctime(time); print RPT "$sAppName $sVersion compacted file report $sNow\n"; print RPT "Compacted $nTotal files not accessed for $nDaysToCheck days or more:\n\n"; foreach (@sortedKeys) { local $sDate = ctime($_); $sLine = $hOldFiles{$_} . " " . $sDate; print RPT $sLine; } print RPT "\n*** end of report ***\n"; close RPT; print "Created report $sRptFile\n"; }