Deleting a File

Problem

You want to delete a single file, or a whole directory tree.

Solution

Removing a file is simple, with File.delete:

import 'fileutils' FileUtils.touch "doomed_file" File.exists? "doomed_file" # => true File.delete "doomed_file" File.exists? "doomed_file" # => false

Removing a directory tree is also fairly simple. The most confusing thing about it is the number of different methods Ruby provides to do it. The method you want is probably FileUtils.remove_dir, which recursively deletes the contents of a directory:

Dir.mkdir "doomed_directory" File.exists? "doomed_directory" # => true FileUtils.remove_dir "doomed_directory" File.exists? "doomed_directory" # => false

 

Discussion

Ruby provides several methods for removing directories, but you really only need remove_dir. Dir.delete and FileUtils.rmdir will only work if the directory is already empty. The rm_r and rm_rf defined in FileUtils are similar to remove_dir, but if you're a Unix user you may find their names more mneumonic.

You should also know about the :secure option to rm_rf, because the remove_dir method and all its variants are vulnerable to a race condition when you remove a world-writable directory. The risk is that a process owned by another user might create a symlink in that directory while you're deleting it. This would make you delete the symlinked file along with the files you actually meant to delete.

Passing in the :secure option to rm_rf slows down deletions significantly (it has to change the permissions on the directory before deleting it), but it avoids the race condition. If you're running Ruby 1.8, you'll also need to hack the FileUtils module a little bit to work around a bug (the bug is fixed in Ruby 1.9):?

# A hack to make a method used by rm_rf actually available module FileUtils module_function :fu_world_writable? end Dir.mkdir "/tmp/doomed_directory" FileUtils.rm_rf("/tmp/doomed_directory", :secure=>true) File.exists? "/tmp/doomed_directory" # => false

Why isn't the :secure option the default for rm_rf? Because secure deletion isn't thread-safe: it actually changes the current working directory of the process. You need to choose between thread safety and a possible security hole.

Категории