Skip to content

Commit fa65d67

Browse files
FileUtils.rm* methods swallows only Errno::ENOENT when force is true
... instead of any StandardError. To behave like the standard `rm` command, it should only ignore exceptions about not existing files, not every exception. This should make debugging some errors easier, because the expectation is that `rm -rf` will succeed if and only if, all given files (previously existent or not) are removed. However, due to this exception swallowing, this is not always the case. From the `rm` man page > COMPATIBILITY > > The rm utility differs from historical implementations in that the -f > option only masks attempts to remove non-existent files instead of > masking a large variety of errors. Co-Authored-By: David Rodríguez <[email protected]>
1 parent ec5d3b8 commit fa65d67

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

lib/fileutils.rb

Lines changed: 11 additions & 6 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
#

test/fileutils/test_fileutils.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,26 @@ def test_rm_rf
18141814
assert_file_not_exist 'tmpdatadir'
18151815
end
18161816

1817+
def test_rm_rf_no_permissions
1818+
check_singleton :rm_rf
1819+
1820+
return if /mswin|mingw/ =~ RUBY_PLATFORM
1821+
1822+
mkdir 'tmpdatadir'
1823+
touch 'tmpdatadir/tmpdata'
1824+
chmod "-x", 'tmpdatadir'
1825+
1826+
begin
1827+
assert_raise Errno::EACCES do
1828+
rm_rf 'tmpdatadir'
1829+
end
1830+
1831+
assert_file_exist 'tmpdatadir'
1832+
ensure
1833+
chmod "+x", 'tmpdatadir'
1834+
end
1835+
end
1836+
18171837
def test_rmdir
18181838
check_singleton :rmdir
18191839

0 commit comments

Comments
 (0)