Search code examples
rubysymlink

Ruby FileUtils.rm_r fails on Windows when there are symlinks to directories: alternatives?


I support a cross-platform ruby 2 script that works for OS X and Linux, but fails on Windows when it tries to remove a tree containing directory symlinks. Here's what I see in the simplest possible example, running from irb. The directory "parent" contains a symlink named "symlink" that points at a target directory. The target exists.

irb(main):001:0> require 'fileutils'
=> true
irb(main):003:0> FileUtils.rm_r 'parent'
Errno::ENOENT: No such file or directory - parent/symlink
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1349:in `open'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1349:in `entries'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1349:in `entries'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1536:in `postorder_traverse'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1537:in `block in postorder_traverse'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1536:in `each'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:1536:in `postorder_traverse'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:837:in `remove_entry'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:695:in `block in rm_r'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:691:in `each'
    from c:/engapps/Ruby/lib/ruby/2.0.0/fileutils.rb:691:in `rm_r'

Outside of solutions like system('rmdir /s/q parent'), are there any other options here? I know that FileUtils.symlink() is unsupported on Windows, but a hardcore failure of FileUtils.rm_r() is something else entirely. This has been a problem since Win 7 came out, maybe even back to Vista, and I haven't found a good solution that doesn't involve shelling out to CMD.EXE.

NOTE: FileUtils.rm_rf() doesn't improve things.


Solution

  • 2023 update: This is no longer true. At some point since 2015, Ruby has been fixed so that this limitation is gone.

    My previous answer, for posterity:

    I've read the source code for fileutils.rb in ruby 2.0, as well as code it depends on. It's abundantly clear from this source that Windows symlinks are not considered, although there is code that behaves differently for Win32 than for non-Windows all over this module. There don't seem to be any open tickets for Ruby regarding Windows symlinks, so the answer is, Ruby doesn't handle it and it doesn't look like it will anytime soon. So the system('rmdir /s/q parent') workaround is the way to remove a Windows directory tree containing symlinks.