The attached patch file_path_pm.gdiff handles a special case of a filename named "." on VMS that is not a directory. If rmtree() is called on a directory with this present, it causes an infinite recursion.

As failed Perl tests on VMS tend to leave a file named "." behind as a result of a file conversion error, a special case is set up to remove it.

It looks like this could be done more efficiently by moving the common code into a subroutine, but this gets the the immediate problem fixed.

The longer patch file file_path_pm_ws.gdiff is one that has the patch and converts the tabs to spaces while retaining the correct indenting, and also fixes a few indenting issues.

-John
[EMAIL PROTECTED]
Personal Opinion Only
--- /rsync_root/perl/lib/File/Path.pm   Thu Jun 28 00:46:16 2007
+++ lib/File/Path.pm    Wed Aug 29 20:12:51 2007
@@ -570,6 +570,57 @@
                closedir $d;
            }
 
+            if ($Is_VMS && ($files[0] eq '.' )) {
+                # If '.' is present on VMS, it means that the file '.;'
+                # is present, not the directory.
+                # This will need to be changed if the VMS C library
+                # in UNIX report mode starts returning '.' for the
+                # current directory.
+
+                # The file '.;' must be handled as a special case as it
+                # can only be accessed in VMS syntax.
+
+                # Force the path to VMS syntax as it could be in UNIX syntax.
+                my $vms_root = VMS::Filespec::vmspath($root);
+
+                # Get rid of '.' from the list
+                shift @files;
+
+                my $vms_file = File::Spec->catfile($vms_root,'.;');
+
+                print "unlink $vms_file\n" if $arg->{verbose};
+                # delete all versions under VMS
+                for (;;) {
+                    if (unlink $vms_file) {
+                        push @{${$arg->{result}}}, $vms_file if $arg->{result};
+                    }
+                    else {
+                        if ($arg->{error}) {
+                            push @{${$arg->{error}}},
+                                 {$vms_file => "unlink: $!"};
+                        }
+                        else {
+                            _carp ("Can't unlink file $vms_file: $!");
+                        }
+                        if ($Force_Writeable) {
+                            if (!chmod $rp, $vms_file) {
+                                my $mask = sprintf("0%o",$rp);
+                                if ($arg->{error}) {
+                                   push @{${$arg->{error}}},
+                                        {$vms_file => "restore chmod: $!"};
+                                }
+                                else {
+                                    _carp
+                                   ("and can't restore permissions to 
$mask\n");
+                                }
+                            }
+                            last;
+                        }
+                        ++$count;
+                        last unless $Is_VMS && lstat $vms_file;
+                    }
+                }
+            }
            # Deleting large numbers of files from VMS Files-11 filesystems
            # is faster if done in reverse ASCIIbetical order 
            @files = reverse @files if $Is_VMS;
--- /rsync_root/perl/lib/File/Path.pm   Thu Jun 28 00:46:16 2007
+++ lib/File/Path.pm    Wed Aug 29 20:12:51 2007
@@ -381,7 +381,7 @@
 # These OSes complain if you want to remove a file that you have no
 # write permission to:
 my $Force_Writeable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' ||
-                      $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc');
+                       $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc');
 
 sub _carp {
     require Carp;
@@ -436,26 +436,26 @@
     my(@created,$path);
     foreach $path (@$paths) {
         next unless length($path);
-       $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT 
-       # Logic wants Unix paths, so go with the flow.
-       if ($Is_VMS) {
-           next if $path eq '/';
-           $path = VMS::Filespec::unixify($path);
-       }
-       next if -d $path;
-       my $parent = File::Basename::dirname($path);
-       unless (-d $parent or $path eq $parent) {
+        $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT 
+        # Logic wants Unix paths, so go with the flow.
+        if ($Is_VMS) {
+            next if $path eq '/';
+            $path = VMS::Filespec::unixify($path);
+        }
+        next if -d $path;
+        my $parent = File::Basename::dirname($path);
+        unless (-d $parent or $path eq $parent) {
             push(@created,_mkpath($arg, [$parent]));
         }
         print "mkdir $path\n" if $arg->{verbose};
         if (mkdir($path,$arg->{mode})) {
             push(@created, $path);
-       }
+        }
         else {
             my $save_bang = $!;
             my ($e, $e1) = ($save_bang, $^E);
-           $e .= "; $e1" if $e ne $e1;
-           # allow for another process to have created it meanwhile
+            $e .= "; $e1" if $e ne $e1;
+            # allow for another process to have created it meanwhile
             if (!-d $path) {
                 $! = $save_bang;
                 if ($arg->{error}) {
@@ -464,8 +464,8 @@
                 else {
                     _croak("mkdir $path: $e");
                 }
-       }
-    }
+            }
+        }
     }
     return @created;
 }
@@ -518,20 +518,20 @@
     my($count) = 0;
     my (@files, $root);
     foreach $root (@$paths) {
-       if ($Is_MacOS) {
-           $root = ":$root" if $root !~ /:/;
+        if ($Is_MacOS) {
+            $root = ":$root" if $root !~ /:/;
             $root =~ s/([^:])\z/$1:/;
         }
         else {
-           $root =~ s#/\z##;
-       }
+            $root =~ s#/\z##;
+       }
         my $rp = (lstat $root)[2] or next;
-       $rp &= 07777;   # don't forget setuid, setgid, sticky bits
-       if ( -d _ ) {
-           # notabene: 0700 is for making readable in the first place,
-           # it's also intended to change it to writable in case we have
-           # to recurse in which case we are better than rm -rf for 
-           # subtrees with strange permissions
+        $rp &= 07777;       # don't forget setuid, setgid, sticky bits
+        if ( -d _ ) {
+            # notabene: 0700 is for making readable in the first place,
+            # it's also intended to change it to writable in case we have
+            # to recurse in which case we are better than rm -rf for 
+            # subtrees with strange permissions
             if (!chmod($rp | 0700,
                 ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
             ) {
@@ -558,25 +558,76 @@
                 @files = ();
             }
             else {
-               no strict 'refs';
-               if (!defined ${"\cTAINT"} or ${"\cTAINT"}) {
+                no strict 'refs';
+                if (!defined ${"\cTAINT"} or ${"\cTAINT"}) {
                     # Blindly untaint dir names if taint mode is
                     # active, or any perl < 5.006
                     @files = map { /\A(.*)\z/s; $1 } readdir $d;
                 }
                 else {
-                   @files = readdir $d;
-               }
-               closedir $d;
-           }
-
-           # Deleting large numbers of files from VMS Files-11 filesystems
-           # is faster if done in reverse ASCIIbetical order 
-           @files = reverse @files if $Is_VMS;
-           ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS;
-           if ($Is_MacOS) {
-               @files = map("$root$_", @files);
-           }
+                    @files = readdir $d;
+                }
+                closedir $d;
+            }
+
+            if ($Is_VMS && ($files[0] eq '.' )) {
+                # If '.' is present on VMS, it means that the file '.;'
+                # is present, not the directory.
+                # This will need to be changed if the VMS C library
+                # in UNIX report mode starts returning '.' for the
+                # current directory.
+
+                # The file '.;' must be handled as a special case as it
+                # can only be accessed in VMS syntax.
+
+                # Force the path to VMS syntax as it could be in UNIX syntax.
+                my $vms_root = VMS::Filespec::vmspath($root);
+
+                # Get rid of '.' from the list
+                shift @files;
+
+                my $vms_file = File::Spec->catfile($vms_root,'.;');
+
+                print "unlink $vms_file\n" if $arg->{verbose};
+                # delete all versions under VMS
+                for (;;) {
+                    if (unlink $vms_file) {
+                        push @{${$arg->{result}}}, $vms_file if $arg->{result};
+                    }
+                    else {
+                        if ($arg->{error}) {
+                            push @{${$arg->{error}}},
+                                 {$vms_file => "unlink: $!"};
+                        }
+                        else {
+                            _carp ("Can't unlink file $vms_file: $!");
+                        }
+                        if ($Force_Writeable) {
+                            if (!chmod $rp, $vms_file) {
+                                my $mask = sprintf("0%o",$rp);
+                                if ($arg->{error}) {
+                                   push @{${$arg->{error}}},
+                                        {$vms_file => "restore chmod: $!"};
+                                }
+                                else {
+                                    _carp
+                                   ("and can't restore permissions to 
$mask\n");
+                                }
+                            }
+                            last;
+                        }
+                        ++$count;
+                        last unless $Is_VMS && lstat $vms_file;
+                    }
+                }
+            }
+            # Deleting large numbers of files from VMS Files-11 filesystems
+            # is faster if done in reverse ASCIIbetical order 
+            @files = reverse @files if $Is_VMS;
+            ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS;
+            if ($Is_MacOS) {
+                @files = map("$root$_", @files);
+            }
             else {
                 my $updir  = File::Spec->updir();
                 my $curdir = File::Spec->curdir();
@@ -590,10 +641,10 @@
             $arg->{depth}--;
             if ($arg->{depth} or !$arg->{keep_root}) {
                 if ($arg->{safe} &&
-               ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
+                ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
                     print "skipped $root\n" if $arg->{verbose};
-               next;
-           }
+                next;
+            }
                 if (!chmod $rp | 0700, $root) {
                     if ($Force_Writeable) {
                         if ($arg->{error}) {
@@ -606,25 +657,25 @@
                     }
                 }
                 print "rmdir $root\n" if $arg->{verbose};
-           if (rmdir $root) {
+            if (rmdir $root) {
                     push @{${$arg->{result}}}, $root if $arg->{result};
-               ++$count;
-           }
-           else {
+                ++$count;
+            }
+            else {
                     if ($arg->{error}) {
                         push @{${$arg->{error}}}, {$root => "rmdir: $!"};
                     }
                     else {
                         _carp ("Can't remove directory $root: $!");
-           }
+            }
                     if (!chmod($rp,
                         ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
                     ) {
                         my $mask = sprintf("0%o",$rp);
                         if ($arg->{error}) {
                             push @{${$arg->{error}}}, {$root => "restore 
chmod: $!"};
-       }
-       else { 
+                        }
+                        else { 
                             _carp("and can't restore permissions to $mask\n");
                         }
                     }
@@ -633,12 +684,12 @@
         }
         else {
             if ($arg->{safe} &&
-               ($Is_VMS ? !&VMS::Filespec::candelete($root)
-                        : !(-l $root || -w $root)))
-           {
+                ($Is_VMS ? !&VMS::Filespec::candelete($root)
+                         : !(-l $root || -w $root)))
+            {
                 print "skipped $root\n" if $arg->{verbose};
-               next;
-           }
+                next;
+            }
             if (!chmod $rp | 0600, $root) {
                 if ($Force_Writeable) {
                     if ($arg->{error}) {
@@ -651,8 +702,8 @@
                 }
             }
             print "unlink $root\n" if $arg->{verbose};
-           # delete all versions under VMS
-           for (;;) {
+            # delete all versions under VMS
+            for (;;) {
                 if (unlink $root) {
                     push @{${$arg->{result}}}, $root if $arg->{result};
                 }
@@ -674,13 +725,13 @@
                                 _carp("and can't restore permissions to 
$mask\n");
                             }
                         }
-                   }
-                   last;
-               }
-               ++$count;
-               last unless $Is_VMS && lstat $root;
-           }
-       }
+                    }
+                    last;
+                }
+                ++$count;
+                last unless $Is_VMS && lstat $root;
+            }
+        }
     }
 
     return $count;

Reply via email to