# see POD documentation at end

=head1 NAME

redate.pl - Change directory dates to reflect latest content.

=head1 SYNOPSIS

perl redate.pl [directory]

=head1 DESCRIPTION

Recursively resets directory times to the time of the latest file or directory inside.

If no directory is given as argument, processes the current directory.

Works only on NT systems (Windows NT/2000/XP), not on Windows 9x.

=cut

BEGIN {
	$^O eq "MSWin32" || die "Sorry, this is only for Windows\n";
}

# Todo: Do we really need to first reset all times to 1980?

my $VERSION = 0.19;

my $show_progress = 10;  # print a dot on STDERR every n file to show progress; Nothing if 0
my $debug = 0;

use File::Find;
use Win32::File qw(GetAttributes SetAttributes READONLY);
use strict;

my $directory = shift || '.';

my $rtime = 315529200;   # 1.1.1980 (1970 not accepted)

my ($dir, %latest, $count);

sub remove_readonly {
	my $file = shift;
	my $attributes;
	if (GetAttributes($file, $attributes)) {
		return SetAttributes($file, $attributes ^ READONLY);
	}
	else {
		return undef;
	}
}

sub set_readonly {
	my $file = shift;
	my $attributes;
	if (GetAttributes($file, $attributes)) {
		return SetAttributes($file, $attributes | READONLY);
	}
	else {
		return undef;
	}
}

sub set_time {
	my ($time, $file) = @_;
	my $ro = 0;
	unless (-w $file) {
		$ro = 1;
		remove_readonly($file) or warn "Cannot make '$file' writable: $!\n";
	}

	if ( utime $time, $time, $file ) {
		if ($debug > 1) { print "OK resetting $file  to ", scalar( localtime $time ), "\n";}
		else {print STDERR "." if ($show_progress && not ++$count % $show_progress);}
	}
	else {warn "\nFAILED to reset $file to ", scalar( localtime $time ), "($!)\n";}

	if ($ro) {
		set_readonly($file) || warn "\nFAILED to make '$file' read-only: $!\n";
	}
}

sub reset_dirs {
	set_time($rtime, $_) if (-d $_);
}

sub check_files {
	print STDERR "." if ($show_progress && not ++$count % $show_progress);
	my $time = (stat $_)[9];
	if (-d $_) {
		$latest{$File::Find::name} = $time if $time > $latest{$File::Find::name};
		$time = $latest{$File::Find::name} if $time < $latest{$File::Find::name}; ## ??!!???
	}
	$latest{$File::Find::dir} = $time if ($time > $latest{$File::Find::dir});
}

############################################## START HERE ##################################################

print STDERR "\n$0 version $VERSION\n\n";
print STDERR "Resetting directory times of $directory\n";

find(\&reset_dirs, $directory);

print STDERR "\n";
print STDERR "Reading dates\n";

finddepth(\&check_files, $directory);

print STDERR "\n";
print STDERR "Changing directory times\n";

foreach $dir (sort keys %latest) {
	set_time($latest{$dir}, $dir);
}

__END__

=head1 SCRIPT CATEGORIES

Win32

=head1 OSNAMES

MSWin32

=head1 AUTHOR

M. Ivkovic email: C<  perl -e "printf '%s@%s', 'mi.perl', 'alma.ch'"  >

=head1 COPYRIGHT

Copyright M. Ivkovic, 2004. Same license as Perl itself.

=cut
