http://www.perlmonks.org?node_id=997802


in reply to [Win32] Verify filename (case sensitively)

Just yesterday, I investigated that in relation to generating a warning on Windows when a module is loaded with the "wrong" case, like use Strict;. I found this (C++) post, which seems to be fairly OK. It does not do an extra stat() call per file, but a call to SHGetFileInfoW. I don't know if that's horribly slow or not.

The linked subroutine tries to verify all parts of the path, while at least Perl would only be interested in the last part(s) of the name.

Replies are listed 'Best First'.
Re^2: [Win32] Verify filename (case sensitively)
by syphilis (Archbishop) on Oct 08, 2012 at 12:53 UTC
    Hi Corion,
    Prompted by the link you gave, I switched to my C:/_32 directory which contains a file named 'switches.txt'. I tried:
    C:\_32>perl -MWin32 -e "print Win32::GetFullPathName('SwitcHes.txt') C:\_32\SwitcHes.txt
    Not much joy with that .. it just reproduces what I gave it.
    However:
    C:\_32>perl -MWin32 -e "print Win32::GetLongPathName('SwitcHes.txt') switches.txt
    That looks more promising !!
    I should be able to make use of that in my script without going to too much trouble at all.

    Incidentally, I did see that post of yours ... but didn't get around to actually reading the thread :-(

    Cheers,
    Rob
Re^2: [Win32] Verify filename (case sensitively)
by Anonymous Monk on Oct 08, 2012 at 15:51 UTC
    Win32::StrictFileNames does that
    $ perl -Mcgi -e 1 $ perl -Mwin32::strictfileNames -e 1 $ perl -Mwin32::strictfileNames -Mcgi -e 1 Can't locate cgi.pm in @INC (@INC contains:... $ perl -Mwin32::strictfileNames -Mcgi -e 1 Can't locate cgi.pm in @INC (@INC contains:...
      Win32::StrictFileNames does that

      That seems to make use of GetLongPathName(), too.
      It won't build successfully for me using mingw - all tests die with the following diagnostic:

      t/7-rmdir.t ... Can't load 'C:\sisyphusion\Win32-StrictFileNames-0.01\blib\arch/ auto/Win32/StrictFileNames/StrictFileNames.dll' for module Win32::StrictFileNames: load_file:Invalid access to memory location at C:/MinGW/perl512/lib/DynaLoader.pm line 200.
      at t/7-rmdir.t line 8

      Update: And similar errors when building using an MS compiler (MSVC++-7.0) instead of gcc.

      Also, I notice that the author provides, on his own ppm repo, packages for this module only for perls 5.6 and 5.8. (I don't know if that's because they pose a problem with later versions of perl.)

      Does use Win32::StrictFileNames; catch *all* instances of case-mismatch (eg with '-e', 'open') ?

      Looks like an interesting module to re-visit if I get the time (before I forget all about it :-).
      For the moment, the Win32::GetLongPathName() function will suffice.

      And interesting that, going by your example, the module itself works irrespective of the case that's used when loading it.

      Cheers,
      Rob
        Compiler fine. No compiler warnings.
        Test Summary Report ------------------- t/2-exist.t (Wstat: 2304 Tests: 15 Failed: 9) Failed tests: 4-6, 8-11, 14-15 Non-zero exit status: 9 t/3-stat.t (Wstat: 2304 Tests: 15 Failed: 9) Failed tests: 4-6, 8-11, 14-15 Non-zero exit status: 9 t/4-dir.t (Wstat: 1792 Tests: 13 Failed: 7) Failed tests: 4-5, 7-9, 12-13 Non-zero exit status: 7 t/7-rmdir.t (Wstat: 2048 Tests: 14 Failed: 8) Failed tests: 2, 5, 7, 9-10, 12-14 Non-zero exit status: 8 Files=9, Tests=114, 2 wallclock secs ( 0.13 usr + 0.05 sys = 0.17 C +PU) Result: FAIL Failed 4/9 test programs. 33/114 subtests failed. NMAKE : fatal error U1077: 'C:\perl512\bin\perl.exe' : return code '0x +ff' Stop. C:\Documents and Settings\Owner\Desktop\cpan libs\Win32-StrictFileName +s-0.01>
        Can't load 'C:\sisyphusion\Win32-StrictFileNames-0.01\blib\arch/ auto/ +Win32/StrictFileNames/StrictFileNames.dll' for module Win32::StrictFi +leNames: load_file:Invalid access to memory location at C:/MinGW/perl +512/lib/DynaLoader.pm line 200.
        means something in DllMain did an access vio.

        1 minute later of research.

        // ========== Initialisation //-------------------------------------------------------------------- +--------- // DllMain() // Function called by the system when processes and threads are initia +lized // and terminated. //-------------------------------------------------------------------- +--------- BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpRese +rved) { BOOL bResult = TRUE; int i; char szMsvcrt[3][16] = { "MSVCRT.dll", "MSVCRT70.dll", "MSVCRT71.dll" }; switch( dwReason ) { case DLL_PROCESS_ATTACH: hDllInstance = hInstance; // save Dll instance handle DEBUGSTR("hDllInstance = 0x%.8x", hDllInstance); bResult &= HookAPIAllMod("KERNEL32.dll", "CreateFileA", (PROC)My +_CreateFileA); DEBUGSTR("CreateFileA = %d", bResult); bResult &= HookAPIAllMod("KERNEL32.dll", "GetFileAttributesA", ( +PROC)My_GetFileAttributesA); DEBUGSTR("GetFileAttributesA = %d", bResult); for (i=0; i<3; i++) { if ( GetModuleHandle(szMsvcrt[i]) ) { bResult &= HookAPIAllMod(szMsvcrt[i], "_stati64", (PROC)My_s +tati64); bResult &= HookAPIAllMod(szMsvcrt[i], "_stat", (PROC)My_stat +); bResult &= HookAPIAllMod(szMsvcrt[i], "_rmdir", (PROC)My_rmd +ir); bResult &= HookAPIAllMod(szMsvcrt[i], "_chdir", (PROC)My_chd +ir); DEBUGSTR("%s functions = %d", szMsvcrt[i], bResult); } } case DLL_PROCESS_DETACH: break; } return (bResult); }
        WHAT???!!!! I see a familiar friend, I guess I am not the first to do IAT patching with Perl in XS. I'm guessing bitrot/compiler/crt versions or x64 broke this module.
        Well, it compiles for me with mingw32 gcc version 4.7.0 (GCC)