diff --git a/lib/fileutils.rb b/lib/fileutils.rb index 7eb66dd..c14e1dc 100644 --- a/lib/fileutils.rb +++ b/lib/fileutils.rb @@ -1165,7 +1165,7 @@ def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) # # Keyword arguments: # - # - force: true - ignores raised exceptions of StandardError + # - force: true - ignores raised exceptions of Errno::ENOENT # and its descendants. # - noop: true - does not remove files; returns +nil+. # - verbose: true - prints an equivalent command: @@ -1248,7 +1248,7 @@ def rm_f(list, noop: nil, verbose: nil) # # Keyword arguments: # - # - force: true - ignores raised exceptions of StandardError + # - force: true - ignores raised exceptions of Errno::ENOENT # and its descendants. # - noop: true - does not remove entries; returns +nil+. # - secure: true - removes +src+ securely; @@ -1315,7 +1315,7 @@ def rm_rf(list, noop: nil, verbose: nil, secure: nil) # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability]. # # Optional argument +force+ specifies whether to ignore - # raised exceptions of StandardError and its descendants. + # raised exceptions of Errno::ENOENT and its descendants. # # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. # @@ -1384,10 +1384,12 @@ def remove_entry_secure(path, force = false) ent.remove rescue raise unless force + raise unless Errno::ENOENT === $! end end rescue raise unless force + raise unless Errno::ENOENT === $! end module_function :remove_entry_secure @@ -1413,7 +1415,7 @@ def fu_stat_identical_entry?(a, b) #:nodoc: # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments]. # # Optional argument +force+ specifies whether to ignore - # raised exceptions of StandardError and its descendants. + # raised exceptions of Errno::ENOENT and its descendants. # # Related: FileUtils.remove_entry_secure. # @@ -1423,10 +1425,12 @@ def remove_entry(path, force = false) ent.remove rescue raise unless force + raise unless Errno::ENOENT === $! end end rescue raise unless force + raise unless Errno::ENOENT === $! end module_function :remove_entry @@ -1437,7 +1441,7 @@ def remove_entry(path, force = false) # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments]. # # Optional argument +force+ specifies whether to ignore - # raised exceptions of StandardError and its descendants. + # raised exceptions of Errno::ENOENT and its descendants. # # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. # @@ -1445,6 +1449,7 @@ def remove_file(path, force = false) Entry_.new(path).remove_file rescue raise unless force + raise unless Errno::ENOENT === $! end module_function :remove_file @@ -1456,7 +1461,7 @@ def remove_file(path, force = false) # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments]. # # Optional argument +force+ specifies whether to ignore - # raised exceptions of StandardError and its descendants. + # raised exceptions of Errno::ENOENT and its descendants. # # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. # @@ -2328,13 +2333,21 @@ def preorder_traverse def postorder_traverse if directory? - entries().each do |ent| + begin + children = entries() + rescue Errno::EACCES + # Failed to get the list of children. + # Assuming there is no children, try to process the parent directory. + yield self + return + end + + children.each do |ent| ent.postorder_traverse do |e| yield e end end end - ensure yield self end diff --git a/test/fileutils/test_fileutils.rb b/test/fileutils/test_fileutils.rb index e1e2a82..993f820 100644 --- a/test/fileutils/test_fileutils.rb +++ b/test/fileutils/test_fileutils.rb @@ -750,6 +750,24 @@ def test_rm_r_pathname assert_file_not_exist 'tmp/tmpdir3' end + def test_rm_r_no_permissions + check_singleton :rm_rf + + return if /mswin|mingw/ =~ RUBY_PLATFORM + + mkdir 'tmpdatadir' + touch 'tmpdatadir/tmpdata' + chmod "-x", 'tmpdatadir' + + begin + assert_raise Errno::EACCES do + rm_r 'tmpdatadir' + end + ensure + chmod "+x", 'tmpdatadir' + end + end + def test_remove_entry_cjk_path dir = "tmpdir\u3042" my_rm_rf dir @@ -1790,12 +1808,32 @@ def test_rm_rf return if /mswin|mingw/ =~ RUBY_PLATFORM mkdir 'tmpdatadir' - chmod 0o700, 'tmpdatadir' + chmod 0o000, 'tmpdatadir' rm_rf 'tmpdatadir' assert_file_not_exist 'tmpdatadir' end + def test_rm_rf_no_permissions + check_singleton :rm_rf + + return if /mswin|mingw/ =~ RUBY_PLATFORM + + mkdir 'tmpdatadir' + touch 'tmpdatadir/tmpdata' + chmod "-x", 'tmpdatadir' + + begin + assert_raise Errno::EACCES do + rm_rf 'tmpdatadir' + end + + assert_file_exist 'tmpdatadir' + ensure + chmod "+x", 'tmpdatadir' + end + end + def test_rmdir check_singleton :rmdir