Comments: Authenticated sender is From: "Robert Pepper" To: perl-win32-web@activeware.com Date: Tue, 19 Aug 1997 09:17:06 +0100 Subject: Re: CGI: How I "lock" files under WinNT, please comment. CC: brainsik@cats.ucsc.edu > Oops, didn't realize this group had already started: Neither, it seems, do many other people. That was the problem with no renaming Users to Misc. > I have a set of intraweb pages with CGI scripts that allow authorized > persons to modify the HTML. Keep in mind, these scripts are used relatively > infrequently, (many times an hour as opposed to many times a second). The > time it takes to modify any of the web pages is about one second. I have > tried to take into account the problem of the user hitting 'stop' in the > middle of a file write. > > Any comments about this method would be greatly appreciated. I have one or two... > Here is how my file locking code works: > > sub file_lock { > > # Get the name of the file to be modified > # > my $file2mod = shift; > > my $old_input_separator = $/; > my $html; > > # To signal that a file is locked, I create a new file whose name is > # of the form "file_to_modify.lock". > # Here, I check to see if this file already exists. > # > if (-e "$file2mod.lock") { > > # If it does exist, I want to make sure that the file is really locked, > # that this locked file indicator is not just some remnant from > # a user hitting their 'stop' button while attempting to modify > # the web page. I believe you can trap the stop button with alarms. > my $mod_time = (stat "$file2mod.lock")[9]; > my $cur_time = time; You might also consider the -M test. > # I have allowed a lockfile to be up to eight seconds old, which > # I feel is MORE than enough leeway to allow for the types of > # file writes that will be occurring. > # > if (($cur_time - $mod_time) > 8) { > > # If the lockfile is older than 8 seconds then I will assume that > # the lockfile should NOT exist. Which means, that there could have > # been error when I was writing the HTML file. > # So, I want to read in the backup copy of the HTML file (which is > # actually saved as the lockfile), and copy it over the original > # filename. > # > $/ = ""; > open LOCKFILE, "$file2mod.lock"; > $html = ; What about : open LOCKFILE, "$file2mod.lock"; @html = ; print @html; which does the name thing, but you don't need to worry about as an input deliminator. Remember, the HTML specs don't actually mention as a valid tag, and it makes no difference to browsers if it is there or not. Secondly, I don't think it would accept as it is case sensistive (I guess). You are also not checking error codes on file opens. I'm not suggesting a die, but maybe : open LOCKFILE, "$file2mod.lock" or &death; sub death { print '

Error running program. Please call systems administration and complain

'; die $!; } or whatever, maybe an email to you, dump to an errorlog. > close LOCKFILE; > open HTML_FILE, "$file2mod"; > print HTML_FILE $html; > close HTML_FILE; > } > else { > > # If the lockfile exists and is less than 8 seconds old, then there > # might be legitimate file modifications occurring, so send the user > # a message telling them that the file is in use, and exit the script. > # > &fail(4); > } > } > # Otherwise, read in the HTML file to be modified > # and copy it as the lockfile. > # > $/ = ""; > open HTML_FILE, "$file2mod"; > $html = ; > close HTML_FILE; > open LOCKFILE, ">$file2mod.lock"; > print LOCKFILE $html; > close LOCKFILE; > $/ = $old_input_separator; > } Why not just copy the file with a system command or File::Copy ? The code above doesn't modify the file at all. If it *did* modify the file, you should think about $^I, the inplace edit variable. Very, very useful. Nice example in the Camel book, if you haven't got it let me know, I have some sample code lying around somewhere. Also check out Win32::Semaphore. This could be useful, although I've never used it so I can't comment. If you do use it, please send me your working code ! There is also the flock() function. It is possible that, (espeically with caching and lazy writes) your locking procedure may not work. The already small probability could be further reduced by sleeping for a second in between creation of the semaphore file and writing, then creating another lock file...but you're better of using Semaphore or flock(). Incidentally, if you 'local' global variables then you can change them to different values between blocks, so you don't need the my and $/ changes. BTW, this is one of the easiest to read posts I've seen on these lists. Very clear, code supplied and all the information needed. hth -- Robert Pepper # robert@netcat.co.uk # http://www.netcat.co.uk/rob/ "This site is best viewed with browsers that support tables, chairs and sofa beds. Best experienced with an Open Mind."