views:

89

answers:

1

Are file descriptors supported on windows? Why do things "seem to work" in Perl with fds?

Things like "fileno", "dup" and "dup2" were working but then randomly inside some other environment, stopped working. It's hard to give details, mostly what I'm looking for is answers from experienced Windows programmers and how file descriptors work/don't work on Windows.

I would guess that it's the PerlIO layer playing games and making it seem as though file descriptors work, but that's only a guess.

Example of what is happening:

open($saveout, ">&STDOUT") or die();
...
open(STDOUT, ">&=".fileno($saveout)) or die();

The second line die()s but only in certain situations (which I have yet to nail down).

A: 

Windows uses file descriptors natively. See Low-Level I/O on MSDN. They all report errors through the C variable errno, which means they show up in Perl's $!.

Note that you can save yourself a bit of typing:

open(STDOUT, ">&=", $saveout) or ...;

This works because the documentation for open in perlfunc provides:

If you use the 3-arg form then you can pass either a number, the name of a filehandle or the normal “reference to a glob.”

Finally, always include meaningful diagnostics when you call die! The program below identifies itself ($0), tells what it was trying to do (open), and why it failed ($!). Also, because the message doesn't end with a newline, die adds the name of the file and line number where it was called.

my $fakefd = 12345;
open(STDOUT, ">&=", $fakefd) or die("$0: open: $!");

This produces

prog.pl: open: Bad file descriptor at foo.pl line 2.

According to the documentation for _fdopen (because you used >&= and not >&), it has two failure modes:

If execution is allowed to continue, errno is set either to EBADF, indicating a bad file descriptor, or EINVAL, indicating that mode was a null pointer.

The second would be a bug in perl and highly unlikely because I don't see anywhere in perlio.c that involves a computed mode: they're all static strings.

Something appears to have gone wrong with $saveout. Could $saveout have been closed before you try to restore it? From your example, it's unclear whether you enabled the strict pragma. If it's not lexical (declared with my), are you calling a function that also monkeys with $saveout?

Greg Bacon