Hello,
I've run into a little quirk in dealing with Windows file locking -- or to be more precise, an apparent misunderstanding on how to determine when a file is being written to and when it's not.
A call made to determine if a file arriving in an FTP drop-box is free and clear of being written to is apparently failing to indicate that the file under test is indeed still being written to.
I wrote a test script to open a file for write access, then write a byte every second to that file for 5 minutes. The code below was then executed in another process against the test-write file. The results were that the code shown below returned a correct indication that it could not get an exlcusive lock on the file being written to in the other process. (An expected result.)
However, the FLOCK routine fails to indicate that a file is being written to when an FTP process has a file open for writing. Apparently, my subroutine CAN get an exclusive lock on the file.
Additionally, the file is checked for the Read-Only attribute using a Win32::GetFileAttribute call. (And if read-Only, the program attempts to reset the read-only bit.)
What happens next is that the partially completed file is copied to a destination. When the attempt is made to delete the file, only then does the OS return an error:
"The process cannot access the file because it is being used by another process"
Well excuse me, but I thought the FLOCK would have hinted at that fact, but it apparently does not.
So the question is, how do you tell for certain that any given file is NOT being used by another process and can be fully accessed? (i.e. READ/WRITE/MODIFY/DELETE)
=========
Code synopsis:
=========
use Fcntl ':flock';
use IO::File;
...
-->Get a list of files arriving into a directory from FTP process...
-->Send each path+filename string to a validation function that checks we're only handling the right type of file -- ( placed into $pathname variable )
-->Before returning a file type value (1-9) check that we can get an exclusive lock on the file (ensure it's not presently being written to by FTP process.)
...
$Ftype = validate($pathname);
if($Ftype < 9){
...
copy($pathname, $destination);
...
delete($pathname); <--- FAILS here (with message quoted above)
}
########### SUBS ###########
########
sub validate {
if( test_lock($pathname)){ # See if the file is locked for writing
error($ERRLOG,"Locked file ->[ $pathname ]");
$retval = 9; # retval = 9 tells caller to leave the file alone this cycle
}
# end sub validate()
#########
sub test_lock {
my $File = $_[0];
my $mode = ( -e $File ) ? '<' : '>';
my $fh = new IO::File $mode.$File;
my $status = flock($fh, LOCK_NB | LOCK_EX );
if(0 == $status){ # Status will be zero if file is locked
print DBG "\nFound locked File =>".$File if($DEBUG);
return($TRUE); #TRUE = File IS locked
}
flock($fh, LOCK_UN); # Release the lock - we don't need it
return($FALSE); # $FALSE = File is NOT locked
} # end sub test_lock
Start Free Trial