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

#! perl -w use strict; $|++; sub test { my ($dir) = @_; print "test $dir\n"; opendir DIR, $dir or die "can't open"; my @items = readdir DIR; closedir DIR; print " @items\n"; } test "."; # OK, reads the current directory test "/"; # OK, reads the root of the curent drive test "h:/"; # OK, reads h:/ test "c:/"; # OK, reads c:/ test "h:"; # BAD, reads the current directory when script in h:/somed +ir # BUT OK, reads h:/ when script in c:/somedir test "c:"; # BAD, reads the current directory when script in c:/som +edir # BUT OK, reads c:/ when script in h:/somedir __END__
Hi perlmonks of Windows obedience

Above script demonstrates what appears to be a bug in opendir/readdir, and also in packages that rely on it, e.g. File::Find.
In offending cases, opendir "<drive>:" from a script residing in a subdirectory of that drive opens the current directory, not the drive root directory.
This is on Win2k, AS perl 623.
My drives c: and h: happen to be partitions of the same physical disk - this might or might not be relevant.
Can anyone confirm this problem (or tell me if I'm missing something subtle)?
If confirmed, would you agree that this is a bug?

Rudif

Replies are listed 'Best First'.
Re: Problem with opendir/readdir on Win2k
by Corion (Patriarch) on Feb 19, 2001 at 04:40 UTC

    This behaviour is for historic reasons*). Both command.com and cmd.exe keep a current directory for every drive (I guess it's the underlying DOS emulation that does so). But I don't see the problem anyway, just always use drive:/ to remove any ambiguity. If your user specifies stuff like h:, they most likely mean what you will get when you call opendir( "h:" );.

    *) The link is courtesy of the master of links, tilly
      I realize (now that I discovered this behaviour) that the workaround is easy as you say: just always use drive:/, not drive:

      And that I must document it to users of my scripts and modules, and hope they read the doc.

      However, I consider it a bug (ok, counterintutive) because
      - in cmd.com, typing dir c: and typing dir c:\, whatever the current directory is, produces the listing of root directory of drive c (as I would expect).
      - in my tests, the behavior differs depending on the whereabouts of the perl script. Now that's something that I did not expect.

      Rudif
        I can tell you that in the Win95/NT command line "dir c:" gives you the contents of the default directory on the C: drive no matter what your current drive or directory is, and "dir c:\" is the only way to always get the root of C:.

        You can also change the current directory of a drive without "logging" (as they say) to that drive using something like "cd c:\" (this example changes the C: default dir to the root), after which "dir c:" would be equivalent to "dir c:\".

        As to the behaviour changing with the locale of the script, I think that might need a bit more investigation, I've not gone after such a bug but I also haven't notice one in many years of DOS/Win Perling...

        Update ...actually confirmed this behaviour at the NT command line also.

        --
        I'd like to be able to assign to an luser

Re: Problem with opendir/readdir on Win2k
by japhy (Canon) on Feb 19, 2001 at 06:31 UTC
    I find that Windows remembers where you were on the drive you just left. Notice:
    d:\perl> cd c:\windows\temp d:\perl> c: c:\windows\temp> d: d:\perl>
    I also find that when I say dir c:, it returns the contents of c:\windows\temp.

    japhy -- Perl and Regex Hacker
Re: Problem with opendir/readdir on Win2k
by Rudif (Hermit) on Feb 20, 2001 at 03:47 UTC
    Thanks to all monks who responded. It is not a bug after all, and I did miss something subtle.

    Corion pointed out that command.com and cmd.exe keep a current directory for every drive - I knew that from experience.
    japhy added that in Windows (aka command.com and cmd.exe), typing dir c: lists the current directory of drive c: - I never noticed that before.
    Hence my erroneous belief that typing dir c: would list the root directory.

    This being so, it makes sense that Perl's opendir("c:") opens the current directory of drive c:, not the root directory.

    I also looked into Perl sources (AS build 618). In win32\win32.c: win32_opendir() I found the code that performs the mapping "c:" to "c:./":
    /* bare drive name means look in cwd for drive */ if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') { scanname[len++] = '.'; scanname[len++] = '/'; }
    The C comment says what the code does, but not why. japhy explained why.

    Rudif

    PS The conclusion ought to be RTFM, except that I still don't know which FM I should have read.

Re: Problem with opendir/readdir on Win2k
by rrwo (Friar) on Feb 20, 2001 at 01:39 UTC

    You're expecting Perl to use a shortcut available only in the Command Prompt shell. This issue occurs with other languages on Windows systems.

    Try getting around it by expanding the path to an absolute path... this is what I used to do in my Turbo Pascal da(ys|ze). Short of that do a simple regexp that converts a drive letter to a drive letter plus a dot:

    $path =~ s/^([A-Z]\:)$/$1\./i;