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

This question is, I suspect, really about Windows 8.1, but I think I'm more likely to get a sensible response here!

Until a few months ago I was still running XP on my desktop machine. One of the perl scripts copied picture files from a camera's SD card to the file system using the date as a directory name. This worked fine, because the multimedia stuff was all on a SATA drive, so the pathname could be hard-coded

When the desktop crashed terminally, and everything had to transferred to the laptop (which runs W8.1), I had to rewrite the code, as the multimedia stuff is now on an external USB drive, and the drive letter won't necessarily stay the same over time. I eventually came up with this code to find the multimedia drive:

sub FindPicDrive { foreach (Win32::DriveInfo::DrivesInUse()) { my $tmp = $_ . ":\\Documents and Settings\\Alan\\My Documents\ +\My Pictures"; # Must also find several directories matching the pattern m[^\ +d{4}_\d{2}_\d{2}$] print "Checking $tmp\n"; if (-d $tmp) { print "Opening $tmp\n"; eval { opendir DH, $tmp or die "This shouldn't happen: $!\n"; }; if ($@) { print "Open fail $! -- shouldn't happen -- ignoring... +\n"; next; } my $count; my @picdirs = grep /^\d{4}_\d{2}_\d{2}$/, readdir DH; #print join(', ',@picdirs), "\n"; closedir DH; if (@picdirs > 5) { print $tmp, ' ', scalar(@picdirs), "\n"; return $tmp; } } } }

which generates this output:

Checking C:\Documents and Settings\Alan\My Documents\My Pictures Opening C:\Documents and Settings\Alan\My Documents\My Pictures Open fail Invalid argument -- shouldn't happen -- ignoring... Checking D:\Documents and Settings\Alan\My Documents\My Pictures Checking E:\Documents and Settings\Alan\My Documents\My Pictures Checking F:\Documents and Settings\Alan\My Documents\My Pictures Checking G:\Documents and Settings\Alan\My Documents\My Pictures Checking H:\Documents and Settings\Alan\My Documents\My Pictures Checking I:\Documents and Settings\Alan\My Documents\My Pictures Opening I:\Documents and Settings\Alan\My Documents\My Pictures I:\Documents and Settings\Alan\My Documents\My Pictures 480 Pic stuff at I:\Documents and Settings\Alan\My Documents\My Pictures

Further investigation showed that, under W8.1, the path 'C:\Documents and Settings\Alan\My Documents\My Pictures' actually maps to 'c:\Users\Alan\Pictures', because several of the path elements are links (.lnk files)

The strange thing is that the -d test seems to work correctly on the former path, but then the same string fails when used as an argument to the opendir function

Shurely shome mishtake?

By the way, output from perl -V is:

Summary of my perl5 (revision 5 version 18 subversion 1) configuration +: Platform: osname=MSWin32, osvers=4.0, archname=MSWin32-x86-multi-thread-64in +t uname='Win32 strawberry-perl 5.18.1.1 #1 Tue Aug 13 19:20:13 2013 +i386' config_args='undef' hint=recommended, useposix=true, d_sigaction=undef useithreads=define, usemultiplicity=define useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=und +ef use64bitint=define, use64bitall=undef, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='gcc', ccflags =' -s -O2 -DWIN32 -DPERL_TEXTMODE_SCRIPTS -DPER +L_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -fno-strict-alias +ing -mms-bitfields', optimize='-s -O2', cppflags='-DWIN32' ccversion='', gccversion='4.7.3', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=1 +2 ivtype='long long', ivsize=8, nvtype='double', nvsize=8, Off_t='lo +ng long', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='g++', ldflags ='-s -L"C:\strawberry\perl\lib\CORE" -L"C:\straw +berry\c\lib"' libpth=C:\strawberry\c\lib C:\strawberry\c\i686-w64-mingw32\lib libs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 +-ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -l +mpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32 perllibs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdl +g32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_3 +2 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32 libc=, so=dll, useshrplib=true, libperl=libperl518.a gnulibc_version='' Dynamic Linking: dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' ' cccdlflags=' ', lddlflags='-mdll -s -L"C:\strawberry\perl\lib\CORE +" -L"C:\strawberry\c\lib"' Characteristics of this binary (from libperl): Compile-time options: HAS_TIMES HAVE_INTERP_INTERN MULTIPLICITY PERLIO_LAYERS PERL_DONT_CREATE_GVSV PERL_HASH_FUNC_ONE_AT_A_TIME_HARD PERL_IMPLICIT_CONTEXT PERL_IMPLICIT_SYS PERL_MALLOC_WRAP PERL_PRESERVE_IVUV PERL_SAWAM +PERSAND USE_64_BIT_INT USE_ITHREADS USE_LARGE_FILES USE_LOCALE USE_LOCALE_COLLATE USE_LOCALE_CTYPE USE_LOCALE_NUMERIC USE_PERLIO USE_PERL_ATOF Built under MSWin32 Compiled at Aug 13 2013 19:29:16 @INC: C:/strawberry/perl/site/lib C:/strawberry/perl/vendor/lib C:/strawberry/perl/lib .

Replies are listed 'Best First'.
Re: links in pathnames under Windows 8
by AppleFritter (Vicar) on Sep 06, 2014 at 20:07 UTC

    First of all, howdy and welcome to the Monastery, meistersinger! (Nice username, BTW.)

    I've just looked into this for a bit on a windows 7 box, using Strawberry 5.20.0, and I've found that links (to directories) appear to only be recognized and handled properly when two conditions are met:

    1. The source and target of the link share the same name.
    2. The target of the link is not a "localized" directory.

    Following a link from e.g. C:\Users\AppleFritter\Desktop\Games to C:\Games works; the former exists (-e), is seen as a directory (-d), and can be opendir'ed. Changing the link's name to e.g. C:\Users\AppleFritter\Desktop\MoreGames causes it to cease working.

    OTOH, following a link from e.g. C:\Users\AppleFritter\Desktop\Users to C:\Users does not work. (I should note that this is a localized version of windows, albeit configured to use English as its system language; maybe an unlocalized English version wouldn't have this problem.)

    All this remains true when running as an Administrator, BTW, so I don't think it's a permissions problem.

    I don't know whether this indicates a bug in perl, windows, or both. My suggestion would be to just work around this; the easiest solution might be to make sure you don't need to follow any links in the first place. Perhaps shuffle the data around on your external drive as necessary, if that's an option.

      Thank you for the welcome! Sorry for the delay -- family problems mostly due to an errant grand-daughter. (The username comes about because I was a musician before I found that computing paid better, and I like the works or Richard Wagner.)

      I finally came back to this problem last week, because the SD card was full, followed your suggestion and continued with the above code. I'll experiment with the other suggestions when I have time.

      Thank you for your help.

Re: links in pathnames under Windows 8
by Anonymous Monk on Sep 06, 2014 at 20:32 UTC
    Try Win32::Unicode with Path::Tiny like
    #!/usr/bin/perl -- BEGIN { if ( eval { require Win32; 1 } ) { require ex::override; require Win32::Unicode::Native; ex::override->import( GLOBAL_stat => sub (;*) { &Win32::Unicode::Native::stat }, GLOBAL_lstat => sub (;*) { &Win32::Unicode::Native::stat } +, map({ my $name = $_; my $prototype = prototype("CORE::$name"); "GLOBAL_$name" => eval "sub($prototype){&Win32::Un +icode::Native::$name}"; } qw/ chdir link mkdir open readlink rename rmdir symlink unlink utime closedir opendir readdir /, ) ); } } use Path::Tiny qw/ path /; for my $drive ( @drives ){ my @picdirs = grep /^\d{4}_\d{2}_\d{2}$/, eval { path( $drive, $dir )->children }; if( @picdirs ){ ...; } }