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

A text file is created on a Unix system. Some time later, my Perl program accesses this text file. The Perl program runs on a Windows system, the access to the Unix share is done using CIFS, and the file is specified using UNC path syntax. "Accessing the file" in this case means that the file is opened, read, closed, and deleted. Deletion does not work if the file was read using ':unix' layer. The problem is reproducible with Perl 5.8.8 and 5.10.0. Here is the example program:

use strict; use warnings; use IO::File; my $filepath='\\\\mucsdn21\\fischron\\tmp\\created_on_unix.txt'; if(-f $filepath) { my $fh=IO::File->new(); $fh->open($filepath) || die "$!"; binmode($fh,':unix'); my @result=<$fh>; $fh->close || die "$!"; print(@result." lines read\n"); $!=0; # Documentation does not say whether or not unlink sets $! o +n error if(!unlink($filepath)) { print("*************** Could not delete $filepath ($!)\n"); } } else { print("$filepath does not exist"); }
Running this program results in the output
2 lines read *************** Could not delete \\mucsdn21\fischron\tmp\aftermath_res +ult.txt (Permission denied)
and the file still exists afterwards. If I comment out the binmode statement and run the program, the file is deleted properly.

Further analysis with a slightly modified test program, and using Process Explorer, reveals that at the time the unlink function is executed, the process still has an open handle to the file to be deleted. I conclude that the close statement doesn't properly close the file.

The reason why I use binmode(...,':unix') is that the file was created on Unix using Unix line separators, but I want to read it on Windows. I found that this is not strictly necessary: I can read the file equally well using the default layer. Still, I wonder why my original solution did not work.

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: Closing a filehandle in ":unix" layer doesn't work on Win32
by ikegami (Patriarch) on Mar 28, 2011 at 16:23 UTC

    Adding a unix layer makes no sense. I suspect both the existing unix layer and the one you add are trying to close the handle. Of course, only one will succeed. Do you have the problem if you use the following without binmode?

    $fh->open("<:unix $filepath")

    I would never use that, though. The following is the same, but provides buffering:

    $fh->open("<:perlio $filepath")

    The best solution is probably the following, though.

    $fh->open("< $filepath"); binmode($fh);

    Although I'd write it as

    open(my $fh, '<', $filepath); binmode($fh);
      Adding a unix layer makes no sense.
      I guess I was misusing the "layer" feature. Maybe you can enlighten me here:

      My reasoning about using the :unix layer was the following: By default (on a Windows host), Perl translates CRLF to \n when reading a file. In my case, however, the text file was created on a Unix platform with LF line endings. Hence, I thought that using the :unix layer, would have the effect of "recognizing" the proper endings. In particular, if the file to be read would contain by chance a CR right in front of a LF, this CR should also be returned to my application (i.e. CR should be treated just like any other character, but LF should be recognized as line delimiter).

      I suspect both the existing unix layer and the one you add are trying to close the handle. Of course, only one will succeed.

      This would not explain my problem, because if at least one of the 'close' would succeed, the handle would be closed afterwards. However, in my case the problem was the (Windows-)Handle was still *open* afterwards. Maybe it works the other way around: When switching to :unix layer, an additional (Windows-)handle was created, and the close operation closed only one, leaving the other open?

      The best solution is probably the following, though....

      If I understand right, using just binmode without argument is equivalent to specifying the :raw layer. This works indeed, and I think this is the solution I am going to use.

      -- 
      Ronald Fischer <ynnor@mm.st>

        Hence, I thought that using the :unix layer, would have the effect of "recognizing" the proper endings

        The key word was "adding". You were causing your handle to have layers :unix:crlf:unix.

        Furthermore, :unix does not refer to file formats. See PerlIO for definitions of the layers.

        If I understand right, using just binmode without argument is equivalent to specifying the :raw layer.

        binmode without argument is not currently equivalent to specifying :raw, because :raw doesn't currently behave as documented. You want the documented behaviour, so you want binmode without arguments.

        see perlio/binmode,
        :unix Lowest level layer which provides basic PerlIO operations in terms of UNIX/POSIX numeric file descriptor calls (open(), read(), write(), lseek(), close()).
        Also see this program, the results are for a win32 machine, and yes, those are unix perlio layers you see
Re: Closing a filehandle in ":unix" layer doesn't work on Win32
by JavaFan (Canon) on Mar 28, 2011 at 13:34 UTC
    The problem is reproducible with Perl 5.8.8 and 5.10.0.
    Is it reproducible with 5.12.x? With blead?
      I had a chance to try it with Perl 5.12.1 (ActiveState distribution) - same result.

      -- 
      Ronald Fischer <ynnor@mm.st>
Re: Closing a filehandle in ":unix" layer doesn't work on Win32
by BrowserUk (Patriarch) on Mar 28, 2011 at 13:19 UTC

    A couple of suggestions:

    1. Throw some $^E around in your error messages.
    2. Try ditching IO::File.

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      $^E just says that I try to delete a file which is still open. Replacing IO::File by the standard functions doesn't change anything, which is not really surprising, as IO::File is just an OO wrapper around the file functions.

      -- 
      Ronald Fischer <ynnor@mm.st>
Re: Closing a filehandle in ":unix" layer doesn't work on Win32
by MidLifeXis (Monsignor) on Mar 28, 2011 at 13:11 UTC

    Update: "If I comment out the binmode statement and run the program, the file is deleted properly." missed on the first go round. First, I would check to see if you have permissions to delete the file.

    If that is fine, then I would test to see if the behavior changes if you isolate the block that uses $fh (my $fh ... $fh->close) with a block or a sub. How about if you do a $fh = undef; after the close?

    --MidLifeXis

      Nice ideas, but no change in effect. Actually, if my explicit closing of the file handle doesn't help, I would not expect that going out of scope would do any difference.....

      -- 
      Ronald Fischer <ynnor@mm.st>