# fopen: opens a file. Allows for file locking and better error-handling. sub fopen ($$;$) { my ($pack, $file, $line) = caller; $file_open++; my ($filehandle, $filename, $usetmp) = @_; ## make life easier - spot a file that's not closed! if (($debug == 1 or ($debug == 2 && $iamadmin))) { $openfiles .= qq~$filehandle -> $filename ~; } my ($flockCorrected, $cmdResult, $openMode, $openSig); $serveros = "$^O"; if ($serveros =~ m/Win/ && substr($filename, 1, 1) eq ":") { $filename =~ s~\\~\\\\~g; # Translate windows-style \ slashes to windows-style \\ escaped slashes. $filename =~ s~/~\\\\~g; # Translate unix-style / slashes to windows-style \\ escaped slashes. } else { $filename =~ tr~\\~/~; # Translate windows-style \ slashes to unix-style / slashes. } $LOCK_EX = 2; # You can probably keep this as it is set now. $LOCK_UN = 8; # You can probably keep this as it is set now. $LOCK_SH = 1; # You can probably keep this as it is set now. $usetempfile = 0; # Write to a temporary file when updating large files. # Check whether we want write, append, or read. $filename =~ m~\A([<>+]*)(.+)~; $openSig = $1 || ''; $filename = $2 || $filename; $openMode = $yyOpenMode{$openSig} || 0; $filename =~ s~[^/\\0-9A-Za-z#%+\,\-\ \.\:@^_]~~g; # Remove all inappropriate characters. if ($filename =~ m~/\.\./~) { &fatal_error("cannot_open","$filename. $maintxt{'609'}"); } # If the file doesn't exist, but a backup does, rename the backup to the filename if (!-e $filename && -e "$filename.bak") { rename("$filename.bak", "$filename"); } if (-z $filename && -e "$filename.bak") { rename("$filename.bak", "$filename"); } $testfile = $filename; if ($use_flock == 2 && $openMode) { my $count; while ($count < 15) { if (-e $filehandle) { sleep 2; } else { last; } ++$count; } unlink($filehandle) if ($count == 15); local *LFH; CORE::open(LFH, ">$filehandle"); $yyLckFile{$filehandle} = *LFH; } if ($use_flock && $openMode == 1 && $usetmp && $usetempfile && -e $filename) { $yyTmpFile{$filehandle} = $filename; $filename .= '.tmp'; } if ($openMode > 2) { if ($openMode == 5) { $cmdResult = CORE::open($filehandle, "+>>$filename"); } elsif ($use_flock == 1) { if ($openMode == 4) { if (-e $filename) { # We are opening for output and file locking is enabled... # read-open() the file rather than write-open()ing it. # This is to prevent open() from clobbering the file before # checking if it is locked. $flockCorrected = 1; $cmdResult = CORE::open($filehandle, "+<$filename"); } else { $cmdResult = CORE::open($filehandle, "+>$filename"); } } else { $cmdResult = CORE::open($filehandle, "+<$filename"); } } elsif ($openMode == 4) { $cmdResult = CORE::open($filehandle, "+>$filename"); } else { $cmdResult = CORE::open($filehandle, "+<$filename"); } } elsif ($openMode == 1 && $use_flock == 1) { if (-e $filename) { # We are opening for output and file locking is enabled... # read-open() the file rather than write-open()ing it. # This is to prevent open() from clobbering the file before # checking if it is locked. $flockCorrected = 1; $cmdResult = CORE::open($filehandle, "+<$filename"); } else { $cmdResult = CORE::open($filehandle, ">$filename"); } } elsif ($openMode == 1) { $cmdResult = CORE::open($filehandle, ">$filename"); # Open the file for writing } elsif ($openMode == 2) { $cmdResult = CORE::open($filehandle, ">>$filename"); # Open the file for append } elsif ($openMode == 0) { $cmdResult = CORE::open($filehandle, $filename); # Open the file for input } unless ($cmdResult) { return 0; } if ($flockCorrected) { # The file was read-open()ed earlier, and we have now verified an exclusive lock. # We shall now clobber it. flock($filehandle, $LOCK_EX); if ($faketruncation) { CORE::open(OFH, ">$filename"); unless ($cmdResult) { return 0; } print OFH ''; CORE::close(OFH); } else { truncate(*$filehandle, 0) || &fatal_error("truncation_error","$filename"); } seek($filehandle, 0, 0); } elsif ($use_flock == 1) { if ($openMode) { flock($filehandle, $LOCK_EX); } else { flock($filehandle, $LOCK_SH); } } return 1; }