Skip Menu |

This queue is for tickets about the libnet CPAN distribution.

Report information
The Basics
Id: 120202
Status: new
Priority: 0/
Queue: libnet

People
Owner: Nobody in particular
Requestors: ToddAndMargo [...] zoho.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 3.10
Fixed in: (no value)



Subject: Net::FTP:rmdir RECURSE does not check for files starting with a dot
Client: Windows 7 Pro x32, fully updated strawberry-perl-5.24.0.1-32bit.msi Net::FTP 3.10 FTP Server: Fedora Core 25, x64 vsftpd-3.0.3-3.fc25.x86_64 Problem: Net::FTP::rmdir's RECURSE function does not check for files that start with a dot ("."). This causes the RECURSE delete to fail. This is because it uses the Net::FTP::ls function to find files to recurse on and "ls" will not give you files that start with a dot, unless you specifically ask for them. From: http://search.cpan.org/CPAN/authors/id/S/SH/SHAY/libnet-3.10.tar.gz /libnet-3.10/lib/Net/FTP.PM I do believe the error occurs on these lines 671 # Try to delete the contents 672 # Get a list of all the files in the directory, excluding the current and parent directories 673 my @filelist = map { /^(?:\S+;)+ (.+)$/ ? ($1) : () } grep { !/^(?:\S+;)*type=[cp]dir;/ } $ftp->_list_cmd("MLSD", $dir); 674 675 # Fallback to using the less well-defined NLST command if MLSD fails 676 @filelist = grep { !/^\.{1,2}$/ } $ftp->ls($dir) 677 unless @filelist; I do not understand the code very well, but I will suggest a solution: insert after line 676 push ( @filelist, grep { !/^\.{1,2}$/ } $ftp->ls($dir/.*) unless @filelist; Note that I have added "/.*" to the $dir. This will only give you back files that start with a dot. The "push" will add them the the previous pile. I have not a clue how to make line 673 include files that begin in a dot Please let me know if I can assist with this. Many thanks, -T In my own code, this is how I get a "ls -a" full directory: sub lsa ( $$ ) { # do a full directory (ls -a) and return a reference pointer to a results array # print if $Print > 0 my $DirPath = $_[0]; my $Print = $_[1]; my @Dir; @Dir = @{$ftp->ls ( "$DirPath/.*" )}; push ( @Dir, @{$ftp->ls ( "$DirPath" )}); if ( $Print > 0 ) { print "Directory Listing of $DirPath\n"; for my $Line ( @Dir ) { print" $Line\n"; } print "\n"; } return \@Dir; }
From: ToddAndMargo [...] zoho.com
The following is the test code I wrote. It should be useful in testing. It is not "short". It is written top down so you can comment out a one liner at the bottom to remove a ton of testing associated with that one liner. It is also "self contained", so you don't have to open a shell on the server and set up test files and directories And I have commented out all the stuff that works. <code> # RotatorForCobianBackupFTP.pl # configure the following three to your location my $Username = "xxxx"; my $Password = "yyyy"; my $FtpServer = "aaa.bbb.ccc.ddd"; my $BkRoot = ".metadata"; my $DotFile = ".lock"; my $DotDir = ".precomp"; my $SomeFile = "eraseme"; use strict; use warnings; use diagnostics; # Reference for Net::FTP # http://search.cpan.org/~shay/libnet-3.10/lib/Net/FTP.pm use Net::FTP; my $ftp; sub lsa ( $$ ) { # do a full directory (ls -a) and return a reference pointer to a results array # print if $Print > 0 my $DirPath = $_[0]; my $Print = $_[1]; my @Dir; @Dir = @{$ftp->ls ( "$DirPath/.*" )}; push ( @Dir, @{$ftp->ls ( "$DirPath" )}); if ( $Print > 0 ) { print "Directory Listing of $DirPath\n"; for my $Line ( @Dir ) { print" $Line\n"; } print "\n"; } return \@Dir; } sub Exists ( $$$ ) { # Test an FTP directory path for the existance of a file/directory my $DirPath = $_[0]; my $HuntFor = $_[1]; # This must be the last thing in the string my $Print = $_[2]; # print if > 0 my @DirArray; # print STDERR "Exsits Path = <$DirPath> HuntFor = <$HuntFor>\n"; @DirArray = @{lsa ( "$DirPath", 0 ) }; # for my $Line ( @DirArray) { print" Exists Line = <$Line>\n"; } for my $Line ( @DirArray ) { # print " Exists Line = <$Line>\n"; if ( $Line =~ /${HuntFor}$/ ) { if ( $Print > 0) { print " Exists: $HuntFor was found in $DirPath\n\n"; } return 1; } } if ( $Print > 0 ) { print " $HuntFor was not found in $DirPath\n\n"; } return 0; } sub RecreateTestFiles () { # create what was forgotten # if $BkRoot does not exist, create it my $FileHandle; if ( not Exists ( "/", $BkRoot, 0 ) ) { print "Recreating $BkRoot directory\n"; $ftp->mkdir ( $BkRoot ); } if ( not Exists ( "/", $DotDir, 0 ) ) { print "Recreating $DotDir directory\n"; $ftp->mkdir ( $DotDir ); } if ( not Exists ( "/$BkRoot", "$DotFile", 0 ) ) { print "Recreating $BkRoot/$DotFile file\n"; if ( not -f "$DotFile" ) { print "Recreating local $DotFile file\n"; open $FileHandle, ">>", "$DotFile"; close $FileHandle; } $ftp->put ( "$DotFile", "/$BkRoot/$DotFile" ); } if ( not Exists ( "/$BkRoot", "$SomeFile", 0 ) ) { print "Recreating $BkRoot/eraseme file\n"; if ( not -f "eraseme" ) { print "Recreating local $SomeFile file\n"; open $FileHandle, ">>", "$SomeFile"; close $FileHandle; } $ftp->put ( "eraseme", "/$BkRoot/$SomeFile" ); } lsa ( "/", 1); lsa ( "/$BkRoot", 1); print "\n"; } sub RecurseRmDir ( $ ) { my $Target = $_[0]; # Stone age subs print "Attempting to recursively delete direcory $Target\n"; if ( $ftp->rmdir ( "$Target", 1 ) ) { print "Directory $Target was recursively removed\n"; } else { print "Recursive removal of $Target failed\n"; } lsa ( "/$BkRoot", 1); print "\n"; } sub DelFile ( $ ) { my $Target = $_[0]; # Stone age subs print "Attempting to delete file $Target\n"; if ( $ftp->delete ( "$Target" ) ) { print "File $Target was deleted by ftp->delete\n"; } else { print "File $Target failed to delete with ftp->delete\n"; } lsa ( "/$BkRoot", 1); print "\n"; } sub RenameFile ( $ ) { my $Target = $_[0]; # Stone age subs print "Attempting to rename file $Target\n"; if ( $ftp->rename ( "$Target", "$BkRoot/dotfile" ) ) { print "File $Target was renamed to $BkRoot/dotfile\n"; } else { print "File $Target failed rename to $BkRoot/dotfile\n"; } lsa ( "/$BkRoot", 1); print "\n"; } sub RmDotDir () { print "Attempting to remove empty dot directory <$DotDir>\n"; $ftp->rmdir ( "$DotDir" ); lsa ( "/", 1 ); } print "My version of Net::FTP is " . $Net::FTP::VERSION . "\n\n"; # Open a new FTP connnector $ftp = Net::FTP->new("$FtpServer", Passive=>1 ) or die "Cannot connect to $FtpServer: $@"; # Log on to the FTP site $ftp->login("$Username", "$Password") or die "Cannot login ", $ftp->message; RecreateTestFiles; # DelFile ( "/$BkRoot/$DotFile" ); # RecreateTestFiles; # RenameFile ( "/$BkRoot/$DotFile" ); # RecreateTestFiles; RecurseRmDir ( "/$BkRoot" ); # RecreateTestFiles; # RmDotDir; $ftp->quit; # With this, I will say no more __END__ </code> C:\NtUtil>perl Net.FTP.Delete.Test.pl My version of Net::FTP is 3.10 Recreating .precomp directory Directory Listing of / /. /.. /.metadata /.precomp /IAmMatt /MyDocsBackup Directory Listing of /.metadata /.metadata/. /.metadata/.. /.metadata/.lock /.metadata/eraseme Attempting to recursively delete direcory /.metadata Recursive removal of /.metadata failed Directory Listing of /.metadata /.metadata/. /.metadata/.. /.metadata/.lock