http://qs321.pair.com?node_id=506414

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

I've been looking all over for the answer to this question and it is either so simple that no one else bothers to ask it (and I'm an idiot) or it is very esoteric (and I'm a genius -- or would be if I knew the answer). I've got a module that carries it's own output handle around for doing output. It contains a function that lets the user pass in a new output handle. I want to check that you can actually write to this handle before accepting this as the module's new output channel. I can use fileno() to check if it's open or not, but I can't seem to find a way to tell if it's open for writing or not. The closest thing seems to be to use select() (or IO::Select) to see if it's ready for writing. I'm not sure, though if that is good enough; it seems to me like you could have a filehandle open for writing, but not ready at that moment to be written to.

Anybody got any better ideas how to do this?

--DrWhy

"If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

  • Comment on How do I tell if a handle is open for writing?

Replies are listed 'Best First'.
Re: How do I tell if a handle is open for writing?
by Zaxo (Archbishop) on Nov 07, 2005 at 16:31 UTC

    stat or, more conveniently, the -w file test operator. Both work fine on open handles, though we're mostly used to feeding them file names.

    Update: Oops, got the wrong end of the stick. Here's how to check the open flags to see if the handle is currently writable:

    use Fcntl; sub writable { my $fh = shift; (O_WRONLY | O_RDWR) & fcntl( $fh, F_GETFL, my $slush); } for (qw/ > < >> +< +> /) { open my $fh, $_, 'foo' or warn $! and next; print "$_\t", writable($fh)? 'writable.': 'not writable.', $/; } __END__ > writable. < not writable. >> writable. +< writable. +> writable.

    After Compline,
    Zaxo

      Correct me if I'm wrong here, but doesn't -w myfilehandle tell you whether the file that myfilehandle is pointing to has its writable bits set? That's not what I want to know. I want to know if the filehandle is open for writing. You could open a writable file for reading. Then you couldn't write to it with that handle even though passing that handle to -w would still return true. Or have I been smoking the curtains again?

      --DrWhy

      "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

        Or have I been smoking the curtains again?

        No, the curtains are safe. I've added to my reply a sub that Does What You Want.

        After Compline,
        Zaxo

      That isn't what he is asking for...

      $ touch x; perl -le 'open X,"x"; print -w X; print X "x" or die $!' 1 Bad file descriptor at -e line 1.

      -sauoq
      "My two cents aren't worth a dime.";
      
      I'm trying to extend this to a comparable readable() function.
      sub readable { my $fh = shift; (O_RDONLY | O_RDWR) & fcntl( $fh, F_GETFL, my $slush); } for (qw/ > < >> +< +> /) { open my $fh, $_, 'foo' or warn $! and next; print "$_\t", readable($fh)? 'readable.': 'not readable.', $/; } __END__ > not readable. < not readable. >> not readable. +< readable. +> readable.
      Huh??!

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: How do I tell if a handle is open for writing?
by sgifford (Prior) on Nov 07, 2005 at 17:00 UTC
    Try writing nothing at all to the file, and see if it fails:
    sub is_writable_fh { my($fh)=@_; local $\=''; return print $fh ''; } open(F1,"< $0") or die "Couldn't open '$0' for read: $!\n"; print "F1 is".(is_writable_fh(\*F1)?"":"n't")." writable.\n"; open(F2,">> $0") or die "Couldn't open '$0' for append: $!\n"; print "F2 is".(is_writable_fh(\*F2)?"":"n't")." writable.\n";

    Zaxo's solution will tell you whether you have write permissions to the file, but not whether you have write permissions to the filehandle.

      Excellent! I had thought about just trying to write something to the file but didn't want to modify the file. It didn't occur to me to write *nothing* to the file :)

      I was worried that even this solution might have unintended side effects, e.g., changing the modified time on the file or (less likely in my mind) writing a null character to the file. I tried it on my WinXP system and it doesn't appear to modify the file in any way -- modified date remains unchanged.

      Thanks!

      --DrWhy

      "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

        It should write an EOF at the position (on Win that is, or was it FAT-filesystem only?) and everything after it would be lost. Of course perl could intervene and take it to mean a check for writability, and then use other means to check and get you the result. But I would first seek to EOF.
Re: How do I tell if a handle is open for writing?
by jZed (Prior) on Nov 07, 2005 at 16:40 UTC
    Well I may be a member of the idiots' club along with you, and this certainly isn't pretty, but is there a reason this wouldn't work?:
    eval { my $pos = $fh->tell; $fh->print('1'); $fh->seek($pos); }; my $ready_for_writing = ($@) ? 0 : 1;
    update please ignore this and listen to Zaxo :-)

      You mean other than that it clobbers some content in the file? :-)

      Makeshifts last the longest.

        If this was worth salvaging, I could add in a seek() before the original tell to avoid that problem. But since it's crap anyway, I won't bother :-).
        I did that once. I wouldn't recommend it to anyone -- it tends to make your mother a little crazy...

        --DrWhy

        "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."