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

Esteemed Monks,

I have run into a strange problem that I can't seem to get to the bottom of on my own, so I come to the monestary seeking assistance.

I have a script that watches a directory, and modifies some files before moving them to an output directory. Fairly simple, and I have done similar work before without any problems. This time I am getting a bad file descriptor error when creating the output file. I have tried File::Copy, Win32::CopyFile and simply writing the data to the file during processing, and I get the same error each time. The really strange part is that when I use File::Copy or Win32::CopyFile, I get the output file as requested along with the error. When I use the standard print FILE $data, the write fails and I get no file.

Thanks for any assistance/pointers,
digger

open(FILE,"<",$file); binmode(FILE); if (flock(FILE,LOCK_EX|LOCK_NB)) { my $buf = ""; report("Info: Processing $file"); #make sure this is a pcl job file first #if not, move it and log it read(FILE,$buf,9); $printstring = $printstring.$buf; unless($buf =~ m/^\x1B\x25\x2D\x31\x32\x33\x34\x35\x58 +/) { close(FILE); my $errdir = "$dir\\ERR"; report ("Warning: $file is not a valid PCL file - +moving to ERR folder"); unless(-d $errdir){mkdir($errdir);} move($file,$errdir); next; } while(read(FILE,$buf,4096)) { fixtraycalls(\$buf); $printstring= $printstring.$buf; } close FILE;#closing file flushes buffer and releases l +ock if($keepfile) { my $dest; sleep 1; eval{ $dest = $$appconfig{"destination"}."\\$filenam +e"; Win32::CopyFile($file,$dest,1); }; if($!) { report("Error: Unable to move file to destinat +ion - ".$dest."\n $!"); #die; } }

Replies are listed 'Best First'.
Re: Bad File Descriptor Error
by Anno (Deacon) on Mar 19, 2007 at 17:20 UTC
    ... when I use File::Copy or Win32::CopyFile, I get the output file as requested along with the error.

    The error variable $! is only valid immediately after an actual system error, which must be recognized by other means. If $! is nonzero that doesn't indicate an error in the preceding code. The value can come from anywhere. So you are using it wrong in your code below.

    if($keepfile) { my $dest; sleep 1; eval{ $dest = $$appconfig{"destination"}."\\$filename"; Win32::CopyFile($file,$dest,1); }; if($!) { report("Error: Unable to move file to destination - ".$dest."\ +n $!"); #die; } }
    Moreover, why do you run the critical statements under eval()? It will only mask some errors. If the eval() is there for a reason, you ought to inspect $@, not $! after eval finishes to detect possible errors. ($@ is unlike $! in that respect, if it's set after an eval(), there was an error.)

    I believe your program is running just fine, the message in $! is irrelevant. Wy you can't copy the file using print() I don't know.

    Anno

    PS: The behavior of $! is as described in Unix systems. I don't know for sure about Windows.

      Thanks for taking the time to explain my misunderstanding so clearly. I am writing more apps that run in environments outside of my control, so I am trying to make the error handling more robust. My understanding of using eval in this way is that it will trap errors that may be fatal, but allow me to handle them gracefully if possible. After re-reading the perldoc for eval, I see, as you said, that I have to check $@ for error messages.

      If I am misusing eval in this context, I would appreciate any pointers.

      Thanks again
      digger

        Your eval() makes sense if Win32::CopyFile() throws exceptions at run time and you want to deal with that. I don't know if it does. The pure Perl operation
        $dest = $$appconfig{"destination"}."\\$filename";
        does not belong there. If there was a fatal error in that line, it would be a program error and you'd have to correct the line. It doesn't make sense to catch programming errors in eval().

        Anno

        These are just a couple of warnings for you (hopefully, you'll find this advice irrelevant ).

        I've run into problems with $@ on -some- Windows systems. However, you can always use $EVAL_ERROR ( $@ is shorthand for this ). I don't know where this bug comes from, sorry.

        Also, on the Emachine T2862 (and only this model, in my experience), I've had problems with:
        print HANDLE $stuff ; # doesn't seem to work on T2862

        Hopefully, you're not dealing with one of those.

        Good luck.
        Bro. Doug :wq
Re: Bad File Descriptor Error
by samtregar (Abbot) on Mar 19, 2007 at 17:12 UTC
    Are you sure Win32::CopyFile uses $! to report errors? My guess is you're just seeing some left-over junk in there. Most modules use $@, which seems particularly likely given your use of eval{}.

    -sam

Re: Bad File Descriptor Error
by Moron (Curate) on Mar 19, 2007 at 16:53 UTC
    It is a few years ago since I did a bit of Windows programming to season my CV, but as I recall, '\' as a directory separator might be the issue -- the Unix-style '/' is portable* using Perl.

    (* update: i.e. Windows-compatible).

    -M

    Free your mind

Re: Bad File Descriptor Error
by bingos (Vicar) on Mar 20, 2007 at 08:21 UTC

    On MSWin32 you might more milage out of using the Win32 functions:

    use Win32; Win32::FormatMessage( Win32::GetLastError() );

    instead of relying on $!