hardburn has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write a subroutine that opens a file, optionally decompressing (using IO::Zlib) and locking. Current code:

sub open_file { my $file = shift || return; my $lock = 0; my $compress = shift; my $fh; if($compress) { use IO::Zlib; $fh = IO::Zlib->new($file, 'rb') or die "Couldn't open file: $!\n"; } else { open($fh, '<', $file) or die "Couldn't open file: $!\n"; } if($lock) { use Fcntl qw(:DEFAULT :flock); flock($fh, LOCK_SH) or die "Couldn't lock file: $!\n"; } return $fh; }

The above will fail if you want to both lock and decompress the file. This is somewhat obvious, since when $fh is inititlized using IO::Zlib, it doesn't really hold a file descriptor.

I've also tried using the tie interface on IO::Zlib instead of calling IO::Zlib->new():

tie $fh, 'IO::Zlib', $file, "rb";

But this fails with a message Can't use string ("IO::Zlib") as a symbol ref while "strict refs" in use at /usr/local/lib/perl5/site_perl/5.8.0/IO/Zlib.pm line 317. Bug in my code or in IO::Zlib?

Doing it via tie or IO::Zlib->new() or some other clever way is fine by me, as long as you can do both locking and transparent decompression.

----
I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer

Note: All code is untested, unless otherwise stated

Replies are listed 'Best First'.
Re: IO::Zlib and flock
by perlplexer (Hermit) on May 21, 2003 at 17:03 UTC
    From Zlib.pm
    # in new() croak "open() needs a filename" unless defined($filename); $self->{'file'} = gzopen($filename,$mode);
    So, it's passing $filename from new() directly to gzopen() in Compress::Zlib. According to the docs, gzopen() accepts either a file name or an open file handle, in which case it'll call gzdopen(). So, the solution to your problem may be to open() the file first, lock it, and then pass this locked file handle to new().
    I haven't tried it though, so you'll need to test it to make sure it works.

    --perlplexer

      That worked. Thanks.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      Note: All code is untested, unless otherwise stated

Re: IO::Zlib and flock
by halley (Prior) on May 21, 2003 at 17:27 UTC

    Do remember that file locking is not supported on some platforms, is not a protection against applications which don't use the same flavor of file locking, and even when all that is okay, it's still just advisory in nature.

    To perform a stronger locking scheme, just rename the file to something else during your operation. Of course, if your process crashes and never renames the file, it can be a mess to recover.

    --
    [ e d @ h a l l e y . c c ]

      The subroutine above is actually a private method in a class. It's none of my buisness why the application wants the lock, so long as I provide a way to do it.

      That said, I usually do file locking as a CYA measure. Even if it's only advisory locking, I can say "I did my part to keep the file clean. If you didn't do your bit, that's not my problem."

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      Note: All code is untested, unless otherwise stated

      To perform a stronger locking scheme, just rename the file to something else during your operation.

      And exactly how is this stronger? You'll just end up snatching the file from some other application that may be reading/writing from/to it.

      --perlplexer

        File locking doesn't change what another application can or cannot do. Remember the caveats I mentioned. Renaming the file to something else will block another application from subsequently manipulating the file once you've begun your operation.

        Don't think of file locking as "protect myself from the other application's meddling," but rather as "notify other applications of my meddling." If you want to protect your app from others, don't give the other app an opportunity to meddle at all.

        --
        [ e d @ h a l l e y . c c ]