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

Hi there! I have a little problem.
First of all i made a script to create a long path on windows:
my $count = 0; for ($count = 0;$count < 100; $count++) { mkdir "folder_" . $count; chdir "folder_" . $count; }
as you can see, it produced 100 nested folders.
Ok. Now i need to remove it (Windows cannot handle this also with setting path in form "\\.\C:\....").
I have made a new script to do the job:
sub recursive_remove { my($dir) = @_; opendir(DIR, $dir) || die "Error: $dir $!\n"; foreach my $file (readdir(DIR)) { next if $file =~ /^\.{1,2}/; rmdir($dir) || recursive_remove($dir . "/" . $file); } } recursive_remove('C:/temp/' . $ARGV[0]);
this on dies on folder_20 with "No such file or directory" Any suggestions how to do it?

Replies are listed 'Best First'.
Re: Removing long pathes on windows xp
by BrowserUk (Patriarch) on Dec 19, 2007 at 15:39 UTC

    There are several ways to do this, but by far the simplest is:

    system "rd /S /Q Folder_01";

    assuming that you want to remove everything below the root.

    However, if you really have to work with paths longer than 260 characters then you'll have to construct the paths in the full domain name form, and then convert them to UTF16LE.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks everybody! but no success until now.
      By the way i have not tried last suggestion:
      then you'll have to construct the paths in the full domain name form, and then convert them to UTF16LE

      Let's say i have a folder c:\temp\folder_0\folder_1\... (100 times) running on a pc called "myhost".
      How should the full domain path look like in such case?
        Thanks everybody! but no success until now.

        Does that mean that rd /s/q /the/rootdir didn't work?

        By the way i have not tried last suggestion:

        then you'll have to construct the paths in the full domain name form, and then convert them to UTF16LE

        Let's say i have a folder c:\temp\folder_0\folder_1\... (100 times) running on a pc called "myhost". How should the full domain path look like in such case?

        Well first off, you'll not easily be able to create that path using perl, because all the standard apis you might try to use to do so, are subject to the same 260 char restriction. With the 10 chars of \folder_nn at each element the furthest you are going to get is folder_24 or 25 depending.

        But say for example you decided to go ahead with this anyway and use Win32API::File or Win32::API to achieve your goal, then you would need to construct these ludicrous pathnames in full unicode UNC form (per this document (under Maximum Path Length) which bits of your OP hinted at your being aware of).

        To do that, you might use code something like:

        use Encode qw[ from_to ]; my $path = join '\\', 'c:', 'test', map qq[folder_$_], '00'..'99'; $path = "\\\\?\\" . $path; Encode::from_to( $path, 'utf8', 'utf16le' ); print $path;

        Which results in paths that display something along the lines of:

        \ \ ? \ c : \ t e s t \ f o l d e r _ 0 0 \ f o l d e r _ 0 1 \ f o l +d e r _ 0 2 \ f o l d e r _ 0 3 \ f o l d e r _ 0 4 \ f o l d e r _ 0 + 5 \ f o l d e r _ 0 6 \ f o l d e r _ 0 7 \ f o l d e r _ 0 8 \ f o +l d e r _ 0 9 \ f o l d e r _ 1 0 \ f o l d e r _ 1 1 \ f o l d e r _ + 1 2 \ f o l d e r _ 1 3 \ f o l d e r _ 1 4 \ f o l d e r _ 1 5 \ f +o l d e r _ 1 6 \ f o l d e r _ 1 7 \ f o l d e r _ 1 8 \ f o l d e r + _ 1 9 \ f o l d e r _ 2 0 \ f o l d e r _ 2 1 \ f o l d e r _ 2 2 \ +f o l d e r _ 2 3 \ f o l d e r _ 2 4 \ f o l d e r _ 2 5 \ f o l d e + r _ 2 6 \ f o l d e r _ 2 7 \ f o l d e r _ 2 8 \ f o l d e r _ 2 9 +\ f o l d e r _ 3 0 \ f o l d e r _ 3 1 \ f o l d e r _ 3 2 \ f o l d + e r _ 3 3 \ f o l d e r _ 3 4 \ f o l d e r _ 3 5 \ f o l d e r _ 3 +6 \ f o l d e r _ 3 7 \ f o l d e r _ 3 8 \ f o l d e r _ 3 9 \ f o l + d e r _ 4 0 \ f o l d e r _ 4 1 \ f o l d e r _ 4 2 \ f o l d e r _ +4 3 \ f o l d e r _ 4 4 \ f o l d e r _ 4 5 \ f o l d e r _ 4 6 \ f o + l d e r _ 4 7 \ f o l d e r _ 48 \ f o l d e r _ 4 9 \ f o l d e r _ + 5 0 \ f o l d e r _ 5 1 \ f o l d e r _ 5 2 \ f o l d e r _ 5 3 \ f +o l d e r _ 5 4 \ f o l d e r _ 5 5 \ f o l d e r _ 5 6 \ f o l d e r + _ 5 7 \ f o l d e r _ 5 8 \ f o l d e r _ 5 9 \ f o l d e r _ 6 0 \ +f o l d e r _ 6 1 \ f o l d e r _ 6 2 \ f o l d e r _ 6 3 \ f o l d e + r _ 6 4 \ f o l d e r _ 6 5 \ f o l d e r _ 6 6 \ f o l d e r _ 6 7 +\ f o l d e r _ 6 8 \ f o l d e r _ 6 9 \ f o l d e r _ 7 0 \ f o l d + e r _ 7 1 \ f o l d e r _ 7 2 \ f o l d e r _ 7 3 \ f o l d e r _ 7 +4 \ f o l d e r _ 7 5 \ f o l d e r _ 7 6 \ f o l d e r _ 7 7 \ f o l + d e r _ 7 8 \ f o l d e r _ 7 9 \ f o l d e r _ 8 0 \ f o l d e r _ +8 1 \ f o l d e r _ 8 2 \ f o l d e r _ 8 3 \ f o l d e r _ 8 4 \ f o + l d e r _ 8 5 \ f o l d e r _ 8 6 \ f o l d e r _ 8 7 \ f o l d e r +_ 8 8 \ f o l d e r _ 8 9 \ f o l d e r _ 9 0 \ f o l d e r _ 9 1 \ f + o l d e r _ 9 2 \ f o l d e r _ 9 3 \ f o l d e r _ 9 4 \ f o l d e +r _ 9 5 \ f o l d e r _ 9 6 \ f o l d e r _ 9 7 \ f o l d e r _ 98 \ +f o l d e r _ 9 9

        And if that hasn't put you off the idea, then know that none of the standard tools--perl, shell, explorer, etc.--will allow you to type, view or manipulate such behemoths. But, at least in theory, the wide (suffixW) system apis will allow you to manipulate that 1000+char (2000+byte) baby, and much, much longer; upto 32K apparently. I've no idea whether that is 32k bytes or 32k chars, but then, does it matter?

        Bottom line: if you can really come up with a good reason for doing this, and are prepared to put the effort into to doing so, then the system has apis that will allow you to do it; and Perl will give you access to those APIs. All you have to do is put in the reading and the work.

        Good luck :)


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Removing long pathes on windows xp
by moritz (Cardinal) on Dec 19, 2007 at 14:47 UTC
      crashes on .../folder_13 (out of 100)
Re: Removing long pathes on windows xp
by pc88mxer (Vicar) on Dec 19, 2007 at 15:31 UTC
    One initial comment... you should local-ize the DIR filehandle like this:
    sub recursive_remove { my($dir) = @_; local(*DIR); opendir(DIR, $dir) || die "Error: $dir $!\n"; ...
    otherwise you are reusing the same file handle as you recursively call yourself. Don't know yet if this is causing your problem or not.
      or better yet, lexical-ize the filehandle:

      sub recursive_remove { my ($dirname) = @_; opendir my $dirhandle, $dirname or die "opening $dirname: $!"; foreach my $file (readdir $dirhandle) { ... } }

      i don't think the non-local or non-lexical nature of the directory handle is causing the problem because the names of the files in the directory are immediately read and the directory handle is never referred to again.
      the problem is more likely due to the length limit mentioned below.

      btw: the regex  /^\.{1,2}/ fails for files with names like  .initrc
      try using an end-anchor assertion:  m{ \A \.{1,2} \z }xms