Skip to content

Commit edd8d3b

Browse files
authored
Merge pull request #99 from mame/dont-swallow-standarderror-in-fileutils-rm_rf
FileUtils.rm_rf should ignore only Errno::ENOENT, not StandardError
2 parents 775c75a + fa65d67 commit edd8d3b

File tree

2 files changed

+60
-9
lines changed

2 files changed

+60
-9
lines changed

lib/fileutils.rb

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
11651165
#
11661166
# Keyword arguments:
11671167
#
1168-
# - <tt>force: true</tt> - ignores raised exceptions of StandardError
1168+
# - <tt>force: true</tt> - ignores raised exceptions of Errno::ENOENT
11691169
# and its descendants.
11701170
# - <tt>noop: true</tt> - does not remove files; returns +nil+.
11711171
# - <tt>verbose: true</tt> - prints an equivalent command:
@@ -1248,7 +1248,7 @@ def rm_f(list, noop: nil, verbose: nil)
12481248
#
12491249
# Keyword arguments:
12501250
#
1251-
# - <tt>force: true</tt> - ignores raised exceptions of StandardError
1251+
# - <tt>force: true</tt> - ignores raised exceptions of Errno::ENOENT
12521252
# and its descendants.
12531253
# - <tt>noop: true</tt> - does not remove entries; returns +nil+.
12541254
# - <tt>secure: true</tt> - removes +src+ securely;
@@ -1315,7 +1315,7 @@ def rm_rf(list, noop: nil, verbose: nil, secure: nil)
13151315
# see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
13161316
#
13171317
# Optional argument +force+ specifies whether to ignore
1318-
# raised exceptions of StandardError and its descendants.
1318+
# raised exceptions of Errno::ENOENT and its descendants.
13191319
#
13201320
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
13211321
#
@@ -1384,10 +1384,12 @@ def remove_entry_secure(path, force = false)
13841384
ent.remove
13851385
rescue
13861386
raise unless force
1387+
raise unless Errno::ENOENT === $!
13871388
end
13881389
end
13891390
rescue
13901391
raise unless force
1392+
raise unless Errno::ENOENT === $!
13911393
end
13921394
module_function :remove_entry_secure
13931395

@@ -1413,7 +1415,7 @@ def fu_stat_identical_entry?(a, b) #:nodoc:
14131415
# should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
14141416
#
14151417
# Optional argument +force+ specifies whether to ignore
1416-
# raised exceptions of StandardError and its descendants.
1418+
# raised exceptions of Errno::ENOENT and its descendants.
14171419
#
14181420
# Related: FileUtils.remove_entry_secure.
14191421
#
@@ -1423,10 +1425,12 @@ def remove_entry(path, force = false)
14231425
ent.remove
14241426
rescue
14251427
raise unless force
1428+
raise unless Errno::ENOENT === $!
14261429
end
14271430
end
14281431
rescue
14291432
raise unless force
1433+
raise unless Errno::ENOENT === $!
14301434
end
14311435
module_function :remove_entry
14321436

@@ -1437,14 +1441,15 @@ def remove_entry(path, force = false)
14371441
# should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
14381442
#
14391443
# Optional argument +force+ specifies whether to ignore
1440-
# raised exceptions of StandardError and its descendants.
1444+
# raised exceptions of Errno::ENOENT and its descendants.
14411445
#
14421446
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
14431447
#
14441448
def remove_file(path, force = false)
14451449
Entry_.new(path).remove_file
14461450
rescue
14471451
raise unless force
1452+
raise unless Errno::ENOENT === $!
14481453
end
14491454
module_function :remove_file
14501455

@@ -1456,7 +1461,7 @@ def remove_file(path, force = false)
14561461
# should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
14571462
#
14581463
# Optional argument +force+ specifies whether to ignore
1459-
# raised exceptions of StandardError and its descendants.
1464+
# raised exceptions of Errno::ENOENT and its descendants.
14601465
#
14611466
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
14621467
#
@@ -2328,13 +2333,21 @@ def preorder_traverse
23282333

23292334
def postorder_traverse
23302335
if directory?
2331-
entries().each do |ent|
2336+
begin
2337+
children = entries()
2338+
rescue Errno::EACCES
2339+
# Failed to get the list of children.
2340+
# Assuming there is no children, try to process the parent directory.
2341+
yield self
2342+
return
2343+
end
2344+
2345+
children.each do |ent|
23322346
ent.postorder_traverse do |e|
23332347
yield e
23342348
end
23352349
end
23362350
end
2337-
ensure
23382351
yield self
23392352
end
23402353

test/fileutils/test_fileutils.rb

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,24 @@ def test_rm_r_pathname
750750
assert_file_not_exist 'tmp/tmpdir3'
751751
end
752752

753+
def test_rm_r_no_permissions
754+
check_singleton :rm_rf
755+
756+
return if /mswin|mingw/ =~ RUBY_PLATFORM
757+
758+
mkdir 'tmpdatadir'
759+
touch 'tmpdatadir/tmpdata'
760+
chmod "-x", 'tmpdatadir'
761+
762+
begin
763+
assert_raise Errno::EACCES do
764+
rm_r 'tmpdatadir'
765+
end
766+
ensure
767+
chmod "+x", 'tmpdatadir'
768+
end
769+
end
770+
753771
def test_remove_entry_cjk_path
754772
dir = "tmpdir\u3042"
755773
my_rm_rf dir
@@ -1798,12 +1816,32 @@ def test_rm_rf
17981816
return if /mswin|mingw/ =~ RUBY_PLATFORM
17991817

18001818
mkdir 'tmpdatadir'
1801-
chmod 0o700, 'tmpdatadir'
1819+
chmod 0o000, 'tmpdatadir'
18021820
rm_rf 'tmpdatadir'
18031821

18041822
assert_file_not_exist 'tmpdatadir'
18051823
end
18061824

1825+
def test_rm_rf_no_permissions
1826+
check_singleton :rm_rf
1827+
1828+
return if /mswin|mingw/ =~ RUBY_PLATFORM
1829+
1830+
mkdir 'tmpdatadir'
1831+
touch 'tmpdatadir/tmpdata'
1832+
chmod "-x", 'tmpdatadir'
1833+
1834+
begin
1835+
assert_raise Errno::EACCES do
1836+
rm_rf 'tmpdatadir'
1837+
end
1838+
1839+
assert_file_exist 'tmpdatadir'
1840+
ensure
1841+
chmod "+x", 'tmpdatadir'
1842+
end
1843+
end
1844+
18071845
def test_rmdir
18081846
check_singleton :rmdir
18091847

0 commit comments

Comments
 (0)