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

Hello learn-ed monks,

I'm writing some code to try and make some sense out of a mess of some windows file servers I have inherited. It's coming on quite nicely - I'm essentially trying to determine the size of various directories including all their subdirectories and files. To do this, I'm using File::Find::Rule with the following snippet of code:

use strict; use File::Find::Rule; my $dir = "c:/temp/test"; my @results = File::Find::Rule->file->in( $dir ); my $totalsize = 0; foreach my $result ( @results ) { $totalsize += (stat($result))[7]; } my $mbtotalsize = $totalsize /1024 / 1024; print "$dir=$mbtotalsize MB\n";
The problem came when it tried to navigate a very deep directory: Can't cd to [very long path] at C:/Perl/lib/File/Find.pm line 929. The windows path-length at this point is waaaaay over the 255 character limit.

My question (finally!) is this - how can I stop File::Find::(Rule) dying at this point - I just want it to skip over any illegally named files (because of their path length). I could just change the File::Find module to "warn" instead of "die" at that point, but that may have unexpected consquences.

Any advice humbly received!

Replies are listed 'Best First'.
Re: File:Find::Rule on Win32
by davidrw (Prior) on Jul 24, 2005 at 16:02 UTC
    looking at File::Find::Rule, it looks like you can use the exec() method for arbitrary user-defined rules. Something along the lines of:
    my @results = File::Find::Rule->file() ->exec( sub { length($_[1]) < 255 } ) ->in( $dir );
    I would use Data::Dumper; die Dumper \@_; in the sub to verify what's getting passed in; also look at the pod for the exec method.
Re: File:Find::Rule on Win32
by GrandFather (Saint) on Jul 24, 2005 at 20:38 UTC

    The following quote from MSDN in the CreateFile documentation probably doesn't help in this context, but is worth being aware of if you need long file names and paths in Windows:

    "In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming a File.

    Windows Me/98/95: This string must not exceed MAX_PATH characters."

    Perl is Huffman encoded by design.
Re: File:Find::Rule on Win32
by sk (Curate) on Jul 24, 2005 at 16:22 UTC
    Update: Ahhh..did not read your last para prorperly. davidrw's suggestion should do it. If I understand it correctly $_ sets the current short name and not the absolute path so you might want to experiment with that number as the total path limitation could still be an issue...end update

    I am not sure what is your file system but Windows has a limitation with the number of chars on the path.

    I found this link which talks about how the Win32 API call can be made so that the path will be treated as a unicode. I tried to use it in Perl and did not work.

    http://cert.uni-stuttgart.de/archive/bugtraq/2002/01/msg00376.html

    I tried to create a deep path on my Windows XP pro. It did not get ver far

    #!/usr/bin/perl -w my $path = "/monktemp"; chdir($path) or die "Cannot chdir to /monktemp: ($!)"; for (1..300) { mkdir("monk", 0755) or die "Cannot mkdir monk: $!"; chdir("monk") or die "Cannot chdir to monk: ($!)"; $path .= "/monk"; print ("Done Processing $_ levels: Path length so far =", length($ +path),"\n"); }

    Output:

    ...... ...... Done Processing 45 levels: Path length so far =234 Done Processing 46 levels: Path length so far =239 Done Processing 47 levels: Path length so far =244 Cannot mkdir monk No such file or directory at createdir line 7.
    I haven't looked at the Documentation for the exec method yet but not sure whether any non-system method can be made to go deeper than 255 char limitation!

    cheers

    SK

      Thanks to you both for your suggestions - I've done some experimenting and it seems that the $_ value inside the nested subroutine you can use in File::Find::Rule does contain the full path (so, full directory path + filename). Using the line...
      my @results = File::Find::Rule->file->exec( sub { length($_[1]) < 255 +} )->in( $dir );
      ...does indeed exclude any files with an invalid path length. Incidentally, these appear to have come about because directories are shared out half way down the tree and people have then written deep nested directories & files to it. When I come to analyse the directories from the top, the path length is now longer and over the 255 limit.

      Cheers both!