Hello,

I have a CGI script that reads from and writes to a text file on the web server. Before reading or writing, the script uses flock to lock another file. The script is distributed with a program I sell and has been working on many different Unix, Linux and MS Windows web servers for years.

However, one customer discovered that on his Linux web server, the text file is consistently getting corrupted. I sent him a modified version of the script that tests the flock call and it seems flock always returns TRUE right away, even when the file it is trying to lock should still be locked by another user.

Below are two subroutines: LockFile and UnlockFile. LockFile creates a temporary file when it is asked to lock the file exclusively. UnlockFile deletes the temporary file.

For the purposes of this discussion, I simplified the functions a little. The script with the modified LockFile and UnlockFile subroutines has been tested on Linux and MS Windows web servers. On the customer's Linux web server, the LockFile subroutine consistently dies with the message "Acquired an exclusive lock for $flockPath but cannot create $fexistPath." It does not do this on any other web server that I have tested.

I thought there may be a problem with sysopen on the customers' web server. So, I added an alternative method to flock that used sysopen instead and it worked.

Even if the CGI script is run using the same process for each website visitor on the customer's web server, shouldn't flock wait until the lock is released before returning TRUE?

sub LockFile { local $path = $_[0] ; local $mode = $_[1] ; local $flockPath = $path . '.lck' ; local $flockFH = $flockPath ; open ($flockFH, ">$flockPath") or die ("Failed to open $flockPath") +; if (flock ($flockFH, $mode)) { use Fcntl ; local $fexistPath = $path . '.lck.tmp' ; if ($mode & LOCK_EX) { local $fexistFH = $fexistPath ; sysopen ($fexistFH, $fexistPath, O_WRONLY | O_CREAT | O_EXCL) or die ("Acquired an exclusive lock for $flockPath but cannot +create $fexistPath.") ; close $fexistFH ; } elsif (-e $fexistPath) { die ("Acquired a shared lock for $flockPath but found that $fexi +stPath exists.") ; } } else { die ("System Busy") ; } return ($flockFH, $path, $mode) ; } sub UnlockFile { use Fcntl ; local $fh = $_[0] ; local $path = $_[1] ; local $mode = $_[2] ; if ($mode & LOCK_EX) { local $fexistPath = $path . '.lck.tmp' ; unlink ($fexistPath) > 0 or die ("Failed to delete the lock file $ +fexistPath.") ; } close ($fh) ; }

For example, the subroutines would be called like:

local ($lockFH, $lockPath, $lockMode) = LockFile ("test.txt", 2); # Wait 10 seconds before calling UnlockFile UnlockFile ($lockFH, $lockPath, $lockMode);

Thank you in advance for your help.


In reply to In a CGI script can flock return TRUE right away even if the file has already been locked? by rzward

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.