in reply to Unexpected file test (-f) result on Windows

See perlfunc:-X where it says:

This unary operator takes one argument, either a filename or a filehandle, and tests the associated file to see if something is true about it.

In essence, what you are passing is not a filename (or a filehandle). If you remove the '<' and '>>', you'll then get the results you are hoping for.

As it is, you are asking perl to look for a file called '< file' or '>> file', which probably don't exist, so there for they cannot be ordinary files, so the test fails, which is how it should be.

The use of '< file' in the two ar form of open is unique (and only applicable) to that call, where it serves to not only name the file, but also specify the mode of opening the file.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
If I understand your problem, I can solve it! Of course, the same can be said for you.

  • Comment on Re: Unexpected file test (-f) result on Windows

Replies are listed 'Best First'.
Re: Re: Unexpected file test (-f) result on Windows
by DaveH (Monk) on Sep 19, 2003 at 14:56 UTC

    BrowserUk wrote:

    In essence, what you are passing is not a filename (or a filehandle). If you remove the '<' and '>>', you'll then get the results you are hoping for.

    I do understand what you are saying here. However, I'm not trying to have the file test succeed based on open's specical semantics, but rather I'm trying to _detect_ whether somebody else is trying to use open's 2 arg semantics with my module. I fully expect the file test to fail if somebody tries to use, for example, '>>testfile.log' as an argument to my module's 'new()' or 'open()' methods.

    (Does that make sense?! :-) )

    The use of '< file' in the two ar form of open is unique (and only applicable) to that call (open)...

    This was my point! :-) As far as I knew, the only place where one was allowed to use the magic semantics of the first argument to 'open', is in the first argument to open!

    However, for some weird reason, on Windows, a file test on '<testfile.log' (or '<<testfile.log', or even '<<<<<<<<testfile.log') returns true. However, I have just done some more digging, and I think it is a problem with Windows, rather than Perl.

    C:\>perl -e "my $f=qq(<testfile.log); print ref($f); if (-f $f) { prin +t qq(AS thinks this is a file\n); }" AS thinks this is a file C:\>dir "<testfile.log" Volume in drive C has no label. Volume Serial Number is D0C3-B79D Directory of C:\ 19/09/2003 15:03 0 testfile.log 1 File(s) 0 bytes 0 Dir(s) 1,764,376,576 bytes free C:\>dir "<<testfile.log" Volume in drive C has no label. Volume Serial Number is D0C3-B79D Directory of C:\ 19/09/2003 15:03 0 testfile.log 1 File(s) 0 bytes 0 Dir(s) 1,764,376,576 bytes free C:\>dir "<<<<<<<<<testfile.log" Volume in drive C has no label. Volume Serial Number is D0C3-B79D Directory of C:\ 19/09/2003 15:03 0 testfile.log 1 File(s) 0 bytes 0 Dir(s) 1,764,376,576 bytes free

    Looks like this may just be another Microsoft "feature". How helpful of them! ;-)

    Cheers,

    -- Dave :-)


    $q=[split+qr,,,q,~swmi,.$,],+s.$.Em~w^,,.,s,.,$&&$$q[pos],eg,print

      Update: FWIW, this "undocumented feature" is deep within the OS, using '<' in the argument to FindFirstFile/FindNextFile apis also treats it the same way as '*'. It appears that this is the only undocumented character that exhibits this behaviour. Weirdness indeed.

      What can I say? Sorry, but I completely misread the sense of your constanation. Your right! It appears that CMD is treating '<' in the same way as '*'

      P:\test>dir "<.bak" Volume in drive P is Winnt Volume Serial Number is D822-5AE5 Directory of P:\test 27/08/03 00:47 608 286744.pl8.bak 28/08/03 20:20 801 287272.pl8.bak 31/08/03 12:42 729 287900-2.pl8.bak 31/08/03 09:58 1,056 287900.pl8.bak 05/09/03 15:37 2,015 289016-2.pl8.bak 05/09/03 09:56 1,092 289106.pl8.bak 05/09/03 17:26 1,165 289250.pl8.bak 08/09/03 10:49 742 b-sort.pl8.bak ...

      I'm really surprised that I have never encountered this behaviour before...but then, I would never have thought to look for it:)

      It is weird, as far as I am aware, completely undocumented, and very annoying. I cannot even begin to fathom how and why this would have been done!


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
      If I understand your problem, I can solve it! Of course, the same can be said for you.

        BrowserUK wrote:

        Update: FWIW, this "undocumented feature" is deep within the OS, using '<' in the argument to FindFirstFile/FindNextFile apis also treats it the same way as '*'. It appears that this is the only undocumented character that exhibits this behaviour. Weirdness indeed.

        Very strange indeed. As you say, none of the other Windows 'glob' or redirection characters exhibit this peculilar behaviour in this context.

        open FILE, ">testfile.log" or die "Unable to create file: $!"; close FILE; if (! -f "*estfile.log") { print STDERR "Not a file *.\n"; } if (! -f "|testfile.log") { print STDERR "Not a file |.\n"; } if (! -f "?estfile.log") { print STDERR "Not a file ?.\n"; } if (! -f "<testfile.log") { print STDERR "Not a file <.\n"; } if (! -f ">>testfile.log") { print STDERR "Not a file >>.\n"; } exit; __END__ Not a file *. Not a file |. Not a file ?. Not a file >>.

        What I don't understand is why this is effectively performing a directory search in order to test one filename! Does Windows not have the equivalent of the Unix stat() system call? The -f operator should just be calling the perl stat function. Does anyone with a better understanding of Win32 Perl than I understand what is happening here?

        (Should I fall back to matching the filename with a regex?)

        Cheers,

        -- Dave :-)


        $q=[split+qr,,,q,~swmi,.$,],+s.$.Em~w^,,.,s,.,$&&$$q[pos],eg,print
        I see the same results using CMD.exe, but not using 4NT.exe shell. So it's not part of FindFirst/FindNext OS calls, but something in the shell.

        Hmm, maybe 4NT does its own wildcard matching. But, I note that the driver level calls (through filemon) is only getting one call to DIRECTORY when I dir <.exe, even though it passed *.exe to the DIRECTORY call. Yet when doing a dir *.exe, it gets several calls to DIRECTORY before the last returns NO MORE FILES.

        Browser I dont have a wintel box handy right now, can you try this:
        C: cd c:\ dir "<c:\test\.bak"
        my gut fealling tells me that what you are really doing is echoing a list of .bak extention filenames to dir. just like the shorthand for dir *.bak (dir .bak) does in many versions of dos.

        -Waswas
      Why not just untaint the filename you are getting if you consider << >> < > tainted input?

      -Waswas

        Ah, thinking around the problem: that's more like it!

        What would you recommend I use to untaint the data in a portable way? I would expect to miss a lot of cases if I used a regular expression to do the job; that was why I tried to use a file test in the first place. My intention is not to be "too" restrictive in how my module is used (though the specification is not that clearly defined yet i.e. I'm making it up as I go ;-)).

        Cheers,

        -- Dave :-)


        $q=[split+qr,,,q,~swmi,.$,],+s.$.Em~w^,,.,s,.,$&&$$q[pos],eg,print