in reply to Testing for read() failures on different platforms

What on earth would generate a read failure? You mention reading a directory. Yet, directories are just regular files that have special magic associated with them at the OS level. Linux does a little more work for you than Solaris does. This fact doesn't surprise me at all. Personally, I think Solaris is an OS that hasn't been intelligently supported in years and am actively trying to convert my company from Solaris 2.9 to RH ES 3.

That said, I'm still wondering what other situations would generate a read failure. If you can successfully open a file, you should always be able to read from it. Of course, I suppose you could create the file, open it successfully, then delete it and try to read from it. That might generate a read error. Then again, a simplistic test on Cygwin(WinXP) didn't. I suffered from input buffering. *shrugs*

Good luck?

------
We are the carpenters and bricklayers of the Information Age.

Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

I shouldn't have to say this, but any code, unless otherwise stated, is untested

  • Comment on Re: Testing for read() failures on different platforms

Replies are listed 'Best First'.
Re^2: Testing for read() failures on different platforms
by BrowserUk (Patriarch) on Jul 27, 2004 at 03:23 UTC

    I can think of two ways a read from a successfully opened file could fail:

    Opening a file for write access and then trying to read from it. Perl catches this.

    Opening a file on removeable media, and then the media is removed before the read attempt.

    Under win32 (native), this results in an "Abort, retry, continue" popup. Retry is loop unless it is reinserted. The other two result in the read completing as if the file where empty. Ie. a successful read of zero bytes. I'm not sure what *nix would do under these circumstances.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
      You forgot about corrupted media. The cheapest media to corrupt is CD-Roms. Take 1, burn a giant file to take up all the space, then scratch it, then try reading from it.

      MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
      I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
      ** The third rule of perl club is a statement of fact: pod is sexy.

      I'm thinking more along the lines of an NFS or Samba mount that goes bye-bye

      +++++++++++++++++
      #!/usr/bin/perl
      use warnings;use strict;use brain;

Re^2: Testing for read() failures on different platforms
by leriksen (Curate) on Jul 27, 2004 at 02:47 UTC
    That said, I'm still wondering what other situations would generate a read failure.

    Very true, we've been discussing that here - more like, well, if it 'very rarely' happens, should we try to catch a failure.

    But seeing as we have code that tries to deal intelligently with this scenario, we really should try and test it, just to confirm the code really does what we think it does.

    So yes one solution is to not cater for read failures on successfully opened files - then you dont need a test case !-)

    But we are (currently) catering for it, and we want to test that accomodation on different platforms - but with the above mentioned difficulty.

    FWIW, we are getting a consistent (as in, the same error message) on Linux and Solaris if we replace the dummy directory handle (made with IO::File) with one created by IO::Dir - we get

    'usage: $dh->seek(POS) at ...'
    on both platforms - so that would work for now, but come the day we go to another platform I dont hold much hope that will be robust enough

    +++++++++++++++++
    #!/usr/bin/perl
    use warnings;use strict;use brain;

Re^2: Testing for read() failures on different platforms
by calin (Deacon) on Jul 27, 2004 at 09:01 UTC
    I suppose you could create the file, open it successfully, then delete it and try to read from it. That might generate a read error.

    Not on UNIX. It is perfectly possible to open a file, unlink it from the file system, and still be able to read from or write to it. The file is actually deleted when the last open filehandle to it is closed. This is a common way to create a temporary file that no other process can open.

    #!/usr/bin/perl my $tf = 'tmpfile'; open FH, ">$tf" or die $!; print FH "Test data\n"; close FH; open FH, "<$tf" or die $!; unlink $tf; print "File deleted!\n" unless -e $tf; print 'File contents: ', <FH>;
      In a similar way, removing read permissions on a file won't prevent reading of the contents through an already open file handle. That may seem insecure, but the property can be used to enhance security. If a process needs to read from or write to a protected resource, it can start life as root, open the resource appropriately and then drop privileges. The now unprivileged process still has privileged access through the open file handle.

      "Even if you are on the right track, you'll get run over if you just sit there." - Will Rogers
Re^2: Testing for read() failures on different platforms
by adrianh (Chancellor) on Jul 27, 2004 at 22:54 UTC
    What on earth would generate a read failure?

    Networked file systems, corrupt media, broken pipe, etc. Not checking for read errors can lead to evil bugs :-)

    As to the OPs question:

    ... can anyone advise me on a better way for testing cross platform read failures?

    I find redefining read is the simplest solution. At its most basic just adding

    BEGIN { *CORE::GLOBAL::read = sub (*\$$;$) { return undef }; };

    to your test file will always cause read to fail.

      Yep, of course.
      And nicely extensible to other functions in the CORE package I imagine, like testing failing write()'s, etc.

      That is the solution I will use.

      Thank you

      +++++++++++++++++
      #!/usr/bin/perl
      use warnings;use strict;use brain;

      Bugger, that doesn't work, and it behaves funny too.

      Here's the code in the File.t file

      ... $file = File->new('t/file7.test'); eval { # declare as local so default is restored on block exit local *CORE::GLOBAL::read = sub (*\$$;$) { return undef }; $file->header(); }; ...

      And File::header() looks like this

      ... sub header { my ( $self ) = @_; my $seek_rc = $self->{FH}->seek($self->{Header}->{OFFSET}, SEEK_SE +T ); if ($seek_rc == 0) { croak( 'Cannot seek to absolute file position on opened file handl +e - ', $! ); } my $length = $self->{FH}->read(my $header, $self->{Header}->{Lengt +h}); # check if read() had an error croak( "Error in reading file header - $!") # pathological test unless defined $length; croak( 'Error in reading file header - Mismatch between expected l +ength (', $self->{Header}->{Length}, ") and returned length ($length +) byte count") unless $length == $self->{Header}->{_Length}; $header =~ s/(?:\015+)?\012.*$/\n/; # remove any garbage at end +of header and replace with \n return $header; } ...

      So if the read() returns undef, I expect the croak() message to appear with the $! reason for failure.

      Instead, I don't get my croak() message , all I get is $! populated with 'Bad file descriptor'. $@ is empty (that us , $@ eq '').

      Whatsmore, this happens on Linux. Both $@ and $! are still an empty string on Solaris.

      So why aren't I croak()'ing ?

      use brain;