Project

General

Profile

Actions

Bug #3556

closed

FileUtils.mkdir_p fails trying to create C: under Windows

Added by luislavena (Luis Lavena) over 14 years ago. Updated over 13 years ago.

Status:
Closed
Assignee:
-
Target version:
ruby -v:
1.8 and 1.9, including trunk
Backport:
[ruby-core:31177]

Description

=begin
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</\z>, '')

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]
#<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=0, blksize=nil, blocks=nil, atime=2010-07-10 17:12:25 -0300, mtime=2010-07-10 17:12:25 -0300, ctime=2010-02-28 11:29:05 -0300>
-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

#<File::Stat dev=3, ino=0, mode=16768, nlink=1, uid=0, gid=0, rdev=3, size=0, blksize=nil, blocks=nil, atime=Sat Jul 10
17:12:25 -0300 2010, mtime=Sat Jul 10 17:12:25 -0300 2010, ctime=Sun Feb 28 11:29:05 -0300 2010
#<File::Stat dev=3, ino=0, mode=16768, nlink=1, uid=0, gid=0, rdev=3, size=0, blksize=nil, blocks=nil, atime=Sat Jul 10
16:48:38 -0300 2010, mtime=Sat Jul 10 16:48:38 -0300 2010, ctime=Mon Jul 13 23:38:56 -0300 2009

jruby 1.4.1 (ruby 1.8.7 patchlevel 174) (2010-04-26 ea6db6a) (Java HotSpot(TM) Client VM 1.6.0_18) [x86-java]

#<File::Stat dev=0x2, ino=0, mode=040777, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=0, blocks=0, atime=Tue Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>
#<File::Stat dev=0x2, ino=0, mode=040777, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=0, blocks=0, atime=Tue Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>

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]

#<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=512, blocks=0, atime=Tue
Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>
#<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=512, blocks=0, atime=Tue
Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>
=end


Files

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0