From: Luis Lavena Date: 2010-07-11T05:20:01+09:00 Subject: [ruby-core:31177] [Bug #3556] FileUtils.mkdir_p fails trying to create C: under Windows Bug #3556: FileUtils.mkdir_p fails trying to create C: under Windows http://redmine.ruby-lang.org/issues/show/3556 Author: Luis Lavena Status: Open, Priority: Normal Target version: 1.9.x ruby -v: 1.8 and 1.9, including trunk Hello, I've been experiencing weird problems with FileUtils.mkdir_p in RubyGems, as tried to document in [ruby-talk:365540] http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/365540 The root of this investigation is a report about gem installation under Windows: http://groups.google.com/group/rubyinstaller/browse_thread/thread/df7b7c217ad7d882 We have been trying to reproduce this without avail. Now, I was able to recreate a scenario: ruby -v -rfileutils -e "system('rd C:\\Foo /s/q'); puts FileUtils.mkdir_p('C:/Foo/Bar')" C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:243:in `mkdir': File exists - C: (Errno::EEXIST) from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:243:in `fu_mkdir' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:217:in `mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:215:in `reverse_each' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:215:in `mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:201:in `each' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:201:in `mkdir_p' from -e:1 C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in `mkdir': File exists - C: (Errno::EEXIST) from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in `fu_mkdir' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:217:in `block (2 levels) in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in `reverse_each' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in `block in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in `each' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in `mkdir_p' from -e:1:in `
' C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in `mkdir': File exists - C: (Errno::EEXIST) from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in `fu_mkdir' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:217:in `block (2 levels) in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in `reverse_each' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in `block in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in `each' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in `mkdir_p' from -e:1:in `
' And same happens with trunk. After digging a little bit on test_fileutils.rb found that even running the tests fails: 1) Error: test_mkdir_p(TestFileUtils): Errno::EEXIST: File exists - C: test/fileutils/test_fileutils.rb:767:in `block in test_mkdir_p' test/fileutils/test_fileutils.rb:766:in `each' test/fileutils/test_fileutils.rb:766:in `test_mkdir_p' 53 tests, 278 assertions, 0 failures, 1 errors, 0 skips Further investigation pointed that the rescue of SystemCallError in mkdir_p is evaluating for File.directory? of dir, when dir has actually been altered inside fu_mkdir: path = path.sub(%r, '') But this change, been made in a local variable, is not seen by mkdir_p. So: 1) mkdir_p sends "C:/" to fu_mkdir 2) fu_mkdir trims it to "C:" 3) fu_mkdir invokes Dir.mkdir "C:" and Errno::EEXIST is raised 4) mkdir_p catches it but evaluates File.directory? for "C:/" instead of "C:" 5) mkdir_p re-raises the exception since File.directory?("C:/") == false If I'm not missing something, that is wrong. Attached is a simple patch that correct the issue, however, I think the real problem is File.stat that fails: C:\Users\Luis>ruby -v -e "puts File.stat('C:').inspect; puts File.stat('C:/').inspect" ruby 1.9.2dev (2010-07-02) [i386-mingw32] # -e:1:in `stat': Permission denied - C:/ (Errno::EACCES) from -e:1:in `
' You receive Errno::EACCES for C:/, but that doesn't happen on JRuby or IronRuby: IronRuby 1.0.0.0 on .NET 4.0.30319.1 # # jruby 1.5.1 (ruby 1.8.7 patchlevel 249) (2010-06-06 f3a3480) (Java HotSpot(TM) Client VM 1.6.0_18) [x86-java] # # ---------------------------------------- http://redmine.ruby-lang.org