#!/perl -w
#  *NAME* touch.pl
# AIM:
#------------------------------------------------------------
# touch.pl
# from : http://www.cse.scu.edu/~tschwarz/COEN252_05/Homeworks/hw3.html
#
# This script is proof of concept code, demonstrating the ability
# to arbitrarily modify the creation, last access and last 
# modification dates of files.
#
# The only required module is Win32::API::Prototype, from Dave Roth's
# site: ftp://ftp.roth.net/pub/ntperl/Prototype
# OR
# perl ppm.pl install http://www.roth.net/perl/packages/win32-api-prototype.ppd
# ppm install http://www.roth.net/perl/packages/win32-api-prototype.ppd
#
# Usage: [perl] touch.pl [filename]
# The script has a hard-coded target date; the user can 
# go to that section of code and modify it accordingly. 
#------------------------------------------------------------
use strict;
use Win32::API::Prototype;
use File::stat;

# File to 'touch'
my $deffile = "clds3.jpg";
# my $file = shift || die "You must enter a filename.\n";
my $file = $deffile;
if (@ARGV) {
	$file = pop @ARGV;
}

# First, check current times of the file
#\getTimes($file);
getTimes($file);
print "\n";

print "ERROR: THIS SERVICE FAILS - remove following exit(0) to TRY ;=))\n";
exit(0);

# Set up the necessary API calls
my $OPEN_EXISTING = 3;
my $GENERIC_READ = 0x80000000; 
my $FILE_SHARE_READ = 0x00000001;
my $GENERIC_WRITE = 0x40000000; 

ApiLink('kernel32.dll', 
'HANDLE CreateFile(LPCTSTR pszPath, DWORD dwAccess, DWORD dwShareMode, PVOID SecurityAttributes, DWORD dwCreationDist, DWORD dwFlags, HANDLE hTemplate)') 
|| die "Cannot locate CreateFile()";

ApiLink('kernel32.dll', 'BOOL CloseHandle(HANDLE hFile)') 
|| die "Cannot locate CloseHandle()";

ApiLink('kernel32.dll', 'BOOL SystemTimeToFileTime(SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime)')
|| die "Cannot locate SystemTimeToFileTime()";

ApiLink('kernel32.dll', 'BOOL SetFileTime(HANDLE hfile, FILETIME *lpCreationTime, FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime)')
|| die "Cannot locate SetFileTime()";

ApiLink('kernel32.dll',  'BOOL FileTimeToSystemTime(FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime )' ) 
|| die "Can not locate FileTimeToSystemTime()";

# Create a filehandle to the file
# Must use GENERIC_WRITE in order to modify the object
my $hFile; 
$hFile = CreateFile($file,  $GENERIC_READ|$GENERIC_WRITE, $FILE_SHARE_READ, undef, $OPEN_EXISTING, undef, 0 )
|| die "Can not open the file '$file'\n";

# Create a SYSTEMTIME object
# Use 10:12am, 1 Dec 2001 as a test
# Display as 'Sat 12/1/2001 15:12:30:0'
my $wYear = '2001';
my $wMonth = '12';
my $wDayofWeek = '6';
my $wDay = '1';
my $wHour = '10';
my $wMin = '12';
my $wSec = '30';
my $wMilli = '0';

# Now, pack the object. The SYSTEMTIME object is basically 8 WORDs 
# packed into a structure. 
my $pSystemTime = pack("S8",$wYear,$wMonth,$wDayofWeek,$wDay,$wHour,$wMin, $wSec,$wMilli);
# Convert the SYSTEMTIME to a FILETIME object
#my $pFileTime = pack("L2",0);
my $pFileTime;
if (SystemTimeToFileTime($pSystemTime,$pFileTime)) {
	# Now set the file time(s) 
	# The times, in order, are Creation, Last Access, and Last Write
	# To set only specific ones, change the others to 'undef'...
	# or create separate SYSTEMTIME objects for each one 
	if (SetFileTime($hFile,$pFileTime,$pFileTime,$pFileTime)) {
		# If successful, close the filehandle
		CloseHandle($hFile);
	} else {
		my $error = Win32::FormatMessage Win32::GetLastError;
		$error = Win32::GetLastError if ($error eq "");
		print "Error with SetFileTime: $error\n";
	}
} else {
	my $error = Win32::FormatMessage Win32::GetLastError;
	$error = Win32::GetLastError if ($error eq "");
	print "Error with SystemTimeToFileTime: $error\n";
}

# Check times again
#\getTimes($file);
getTimes($file);

# all done
exit(0);	# not really required, but shows the runtime end of module

#------------------------------------------------------------
# getTimes()
# Retrieves the file times for verification purposes. This 
# subroutine is called both before and after the file times
# are changed (SetFileTime() API call).
#------------------------------------------------------------
sub getTimes {
	my $file = $_[0];
	# this did not work, so changed it ...
	# my ($size,$atime,$mtime,$ctime) = (stat($file))[7..10];
	# also failed
	# my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($file);
	# my $a_time = localtime($atime);
	# my $m_time = localtime($mtime);
	# my $c_time = localtime($ctime);
	# THIS WORKS FINE
	my $sb = stat($file);
	if (defined $sb) {  # check was a VALID, existing file name
		my $a_time = scalar localtime($sb->atime);
		my $m_time = scalar localtime($sb->mtime);
		my $c_time = scalar localtime($sb->ctime);
		print "$file\t".$sb->size." bytes\n";
		print "Creation Time:\t$c_time\n" ;
		print "Last Access :\t$a_time\n" ;
		print "Last Write :\t$m_time\n" ;
	} else {
		die "File [$file] does not appear to exist ... choose a file that does ...\n";
	}
}

# eof - touch.pl
