about summary refs log tree commit
diff options
context:
space:
mode:
authorChris Lindee <chris.lindee@cpanel.net>2014-12-03 13:02:38 -0600
committerChris Lindee <chris.lindee@cpanel.net>2014-12-03 15:43:06 -0600
commitb99b8b4b6b733f94f5cbe0c8ad87b04bc7e64913 (patch)
treeb2ed824d8d51662134d40b457a3209d6a3196126
parentbeeea5ae701fe425397f4452562747d25bc40528 (diff)
downloadperl-libnet-b99b8b4b6b733f94f5cbe0c8ad87b04bc7e64913.tar.gz
Make rmdir() more robust against faulty FTP servers
[RT #100694] Some FTP servers simply don't process NLST properly. Use the
RFC standardized MLSD command first, then fallback onto NLST if no data is
provided.

Caveat: MLSD will return 501 if given a file instead of a directory.  We
ignore this error and try NLST anyway.  That command should subsequently
fail and then we return the empty list.
-rw-r--r--lib/Net/FTP.pm12
1 files changed, 8 insertions, 4 deletions
diff --git a/lib/Net/FTP.pm b/lib/Net/FTP.pm
index ea0d7ae..f34636b 100644
--- a/lib/Net/FTP.pm
+++ b/lib/Net/FTP.pm
@@ -661,8 +661,12 @@ sub rmdir {
     or !$recurse;
 
   # Try to delete the contents
-  # Get a list of all the files in the directory
-  my @filelist = grep { !/^\.{1,2}$/ } $ftp->ls($dir);
+  # Get a list of all the files in the directory, excluding the current and parent directories
+  my @filelist = map { /^(?:\S+;)+ (.+)$/ ? ($1) : () } grep { !/^(?:\S+;)*type=[cp]dir;/ } $ftp->_list_cmd("MLSD", $dir);
+
+  # Fallback to using the less well-defined NLST command if MLSD fails
+  @filelist = grep { !/^\.{1,2}$/ } $ftp->ls($dir)
+    unless @filelist;
 
   return
     unless @filelist;    # failed, it is probably not a directory
@@ -1141,7 +1145,7 @@ sub _data_cmd {
     my $data = $ftp->_dataconn();
     if (CMD_INFO == $ftp->response()) {
       $data->reading
-        if $data && $cmd =~ /RETR|LIST|NLST/;
+        if $data && $cmd =~ /RETR|LIST|NLST|MLSD/;
       return $data;
     }
     $data->_close if $data;
@@ -1180,7 +1184,7 @@ sub _data_cmd {
     my $data = $ftp->_dataconn();
 
     $data->reading
-      if $data && $cmd =~ /RETR|LIST|NLST/;
+      if $data && $cmd =~ /RETR|LIST|NLST|MLSD/;
 
     return $data;
   }