Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Including as stripped-down version of Rake and a batch file to run a …

…standard build
  • Loading branch information...
commit ecba4e613738cb9be761c7e1698f4ccdaef0b561 1 parent 13cd39c
Alexander Groß authored November 19, 2009

Showing 80 changed files with 12,304 additions and 3 deletions. Show diff stats Hide diff stats

  1. 1,591  Tools/Rake/lib/ruby/1.8/fileutils.rb
  2. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/Win32API.so
  3. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/bigdecimal.so
  4. 92  Tools/Rake/lib/ruby/1.8/i386-mswin32/config.h
  5. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/curses.so
  6. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/dbm.so
  7. 262  Tools/Rake/lib/ruby/1.8/i386-mswin32/defines.h
  8. 32  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest.h
  9. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest.so
  10. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest/bubblebabble.so
  11. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest/md5.so
  12. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest/rmd160.so
  13. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest/sha1.so
  14. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/digest/sha2.so
  15. 313  Tools/Rake/lib/ruby/1.8/i386-mswin32/dl.h
  16. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/dl.so
  17. 16  Tools/Rake/lib/ruby/1.8/i386-mswin32/dlconfig.h
  18. 40  Tools/Rake/lib/ruby/1.8/i386-mswin32/dln.h
  19. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/enumerator.so
  20. 60  Tools/Rake/lib/ruby/1.8/i386-mswin32/env.h
  21. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/etc.so
  22. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/fcntl.so
  23. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/gdbm.so
  24. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/iconv.so
  25. 508  Tools/Rake/lib/ruby/1.8/i386-mswin32/intern.h
  26. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/io/wait.so
  27. 142  Tools/Rake/lib/ruby/1.8/i386-mswin32/missing.h
  28. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/nkf.so
  29. 474  Tools/Rake/lib/ruby/1.8/i386-mswin32/node.h
  30. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/openssl.so
  31. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/racc/cparse.so
  32. 154  Tools/Rake/lib/ruby/1.8/i386-mswin32/rbconfig.rb
  33. 42  Tools/Rake/lib/ruby/1.8/i386-mswin32/re.h
  34. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/readline.so
  35. 221  Tools/Rake/lib/ruby/1.8/i386-mswin32/regex.h
  36. 759  Tools/Rake/lib/ruby/1.8/i386-mswin32/ruby.h
  37. 88  Tools/Rake/lib/ruby/1.8/i386-mswin32/rubyio.h
  38. 105  Tools/Rake/lib/ruby/1.8/i386-mswin32/rubysig.h
  39. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/sdbm.so
  40. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/socket.so
  41. 72  Tools/Rake/lib/ruby/1.8/i386-mswin32/st.h
  42. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/stringio.so
  43. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/strscan.so
  44. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/syck.so
  45. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/tcltklib.so
  46. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/thread.so
  47. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/tkutil.so
  48. 67  Tools/Rake/lib/ruby/1.8/i386-mswin32/util.h
  49. 19  Tools/Rake/lib/ruby/1.8/i386-mswin32/version.h
  50. 559  Tools/Rake/lib/ruby/1.8/i386-mswin32/win32/win32.h
  51. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/win32ole.so
  52. BIN  Tools/Rake/lib/ruby/1.8/i386-mswin32/zlib.so
  53. 352  Tools/Rake/lib/ruby/1.8/monitor.rb
  54. 1,788  Tools/Rake/lib/ruby/1.8/optparse.rb
  55. 146  Tools/Rake/lib/ruby/1.8/ostruct.rb
  56. 360  Tools/Rake/lib/ruby/1.8/singleton.rb
  57. 2,506  Tools/Rake/lib/ruby/site_ruby/1.8/rake.rb
  58. 108  Tools/Rake/lib/ruby/site_ruby/1.8/rake/alt_system.rb
  59. 8  Tools/Rake/lib/ruby/site_ruby/1.8/rake/classic_namespace.rb
  60. 33  Tools/Rake/lib/ruby/site_ruby/1.8/rake/clean.rb
  61. 24  Tools/Rake/lib/ruby/site_ruby/1.8/rake/contrib/compositepublisher.rb
  62. 153  Tools/Rake/lib/ruby/site_ruby/1.8/rake/contrib/ftptools.rb
  63. 75  Tools/Rake/lib/ruby/site_ruby/1.8/rake/contrib/publisher.rb
  64. 18  Tools/Rake/lib/ruby/site_ruby/1.8/rake/contrib/rubyforgepublisher.rb
  65. 47  Tools/Rake/lib/ruby/site_ruby/1.8/rake/contrib/sshpublisher.rb
  66. 209  Tools/Rake/lib/ruby/site_ruby/1.8/rake/contrib/sys.rb
  67. 97  Tools/Rake/lib/ruby/site_ruby/1.8/rake/gempackagetask.rb
  68. 42  Tools/Rake/lib/ruby/site_ruby/1.8/rake/loaders/makefile.rb
  69. 184  Tools/Rake/lib/ruby/site_ruby/1.8/rake/packagetask.rb
  70. 5  Tools/Rake/lib/ruby/site_ruby/1.8/rake/rake_test_loader.rb
  71. 209  Tools/Rake/lib/ruby/site_ruby/1.8/rake/rdoctask.rb
  72. 23  Tools/Rake/lib/ruby/site_ruby/1.8/rake/ruby182_test_unit_fix.rb
  73. 23  Tools/Rake/lib/ruby/site_ruby/1.8/rake/runtest.rb
  74. 23  Tools/Rake/lib/ruby/site_ruby/1.8/rake/tasklib.rb
  75. 161  Tools/Rake/lib/ruby/site_ruby/1.8/rake/testtask.rb
  76. 55  Tools/Rake/lib/ruby/site_ruby/1.8/rake/win32.rb
  77. 10  Tools/Rake/lib/ruby/site_ruby/1.8/rubygems.rb
  78. 10  Tools/Rake/lib/ruby/site_ruby/1.8/ubygems.rb
  79. 19  build.cmd
  80. 3  rakefile
1,591  Tools/Rake/lib/ruby/1.8/fileutils.rb
... ...
@@ -0,0 +1,1591 @@
  1
+# 
  2
+# = fileutils.rb
  3
+# 
  4
+# Copyright (c) 2000-2006 Minero Aoki
  5
+# 
  6
+# This program is free software.
  7
+# You can distribute/modify this program under the same terms of ruby.
  8
+# 
  9
+# == module FileUtils
  10
+# 
  11
+# Namespace for several file utility methods for copying, moving, removing, etc.
  12
+# 
  13
+# === Module Functions
  14
+# 
  15
+#   cd(dir, options)
  16
+#   cd(dir, options) {|dir| .... }
  17
+#   pwd()
  18
+#   mkdir(dir, options)
  19
+#   mkdir(list, options)
  20
+#   mkdir_p(dir, options)
  21
+#   mkdir_p(list, options)
  22
+#   rmdir(dir, options)
  23
+#   rmdir(list, options)
  24
+#   ln(old, new, options)
  25
+#   ln(list, destdir, options)
  26
+#   ln_s(old, new, options)
  27
+#   ln_s(list, destdir, options)
  28
+#   ln_sf(src, dest, options)
  29
+#   cp(src, dest, options)
  30
+#   cp(list, dir, options)
  31
+#   cp_r(src, dest, options)
  32
+#   cp_r(list, dir, options)
  33
+#   mv(src, dest, options)
  34
+#   mv(list, dir, options)
  35
+#   rm(list, options)
  36
+#   rm_r(list, options)
  37
+#   rm_rf(list, options)
  38
+#   install(src, dest, mode = <src's>, options)
  39
+#   chmod(mode, list, options)
  40
+#   chmod_R(mode, list, options)
  41
+#   chown(user, group, list, options)
  42
+#   chown_R(user, group, list, options)
  43
+#   touch(list, options)
  44
+#
  45
+# The <tt>options</tt> parameter is a hash of options, taken from the list
  46
+# <tt>:force</tt>, <tt>:noop</tt>, <tt>:preserve</tt>, and <tt>:verbose</tt>.
  47
+# <tt>:noop</tt> means that no changes are made.  The other two are obvious.
  48
+# Each method documents the options that it honours.
  49
+#
  50
+# All methods that have the concept of a "source" file or directory can take
  51
+# either one file or a list of files in that argument.  See the method
  52
+# documentation for examples.
  53
+#
  54
+# There are some `low level' methods, which do not accept any option:
  55
+#
  56
+#   copy_entry(src, dest, preserve = false, dereference = false)
  57
+#   copy_file(src, dest, preserve = false, dereference = true)
  58
+#   copy_stream(srcstream, deststream)
  59
+#   remove_entry(path, force = false)
  60
+#   remove_entry_secure(path, force = false)
  61
+#   remove_file(path, force = false)
  62
+#   compare_file(path_a, path_b)
  63
+#   compare_stream(stream_a, stream_b)
  64
+#   uptodate?(file, cmp_list)
  65
+#
  66
+# == module FileUtils::Verbose
  67
+# 
  68
+# This module has all methods of FileUtils module, but it outputs messages
  69
+# before acting.  This equates to passing the <tt>:verbose</tt> flag to methods
  70
+# in FileUtils.
  71
+# 
  72
+# == module FileUtils::NoWrite
  73
+# 
  74
+# This module has all methods of FileUtils module, but never changes
  75
+# files/directories.  This equates to passing the <tt>:noop</tt> flag to methods
  76
+# in FileUtils.
  77
+# 
  78
+# == module FileUtils::DryRun
  79
+# 
  80
+# This module has all methods of FileUtils module, but never changes
  81
+# files/directories.  This equates to passing the <tt>:noop</tt> and
  82
+# <tt>:verbose</tt> flags to methods in FileUtils.
  83
+# 
  84
+
  85
+module FileUtils
  86
+
  87
+  def self.private_module_function(name)   #:nodoc:
  88
+    module_function name
  89
+    private_class_method name
  90
+  end
  91
+
  92
+  # This hash table holds command options.
  93
+  OPT_TABLE = {}   #:nodoc: internal use only
  94
+
  95
+  #
  96
+  # Options: (none)
  97
+  #
  98
+  # Returns the name of the current directory.
  99
+  #
  100
+  def pwd
  101
+    Dir.pwd
  102
+  end
  103
+  module_function :pwd
  104
+
  105
+  alias getwd pwd
  106
+  module_function :getwd
  107
+
  108
+  #
  109
+  # Options: verbose
  110
+  # 
  111
+  # Changes the current directory to the directory +dir+.
  112
+  # 
  113
+  # If this method is called with block, resumes to the old
  114
+  # working directory after the block execution finished.
  115
+  # 
  116
+  #   FileUtils.cd('/', :verbose => true)   # chdir and report it
  117
+  # 
  118
+  def cd(dir, options = {}, &block) # :yield: dir
  119
+    fu_check_options options, OPT_TABLE['cd']
  120
+    fu_output_message "cd #{dir}" if options[:verbose]
  121
+    Dir.chdir(dir, &block)
  122
+    fu_output_message 'cd -' if options[:verbose] and block
  123
+  end
  124
+  module_function :cd
  125
+
  126
+  alias chdir cd
  127
+  module_function :chdir
  128
+
  129
+  OPT_TABLE['cd']    =
  130
+  OPT_TABLE['chdir'] = [:verbose]
  131
+
  132
+  #
  133
+  # Options: (none)
  134
+  # 
  135
+  # Returns true if +newer+ is newer than all +old_list+.
  136
+  # Non-existent files are older than any file.
  137
+  # 
  138
+  #   FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
  139
+  #       system 'make hello.o'
  140
+  # 
  141
+  def uptodate?(new, old_list, options = nil)
  142
+    raise ArgumentError, 'uptodate? does not accept any option' if options
  143
+
  144
+    return false unless File.exist?(new)
  145
+    new_time = File.mtime(new)
  146
+    old_list.each do |old|
  147
+      if File.exist?(old)
  148
+        return false unless new_time > File.mtime(old)
  149
+      end
  150
+    end
  151
+    true
  152
+  end
  153
+  module_function :uptodate?
  154
+
  155
+  #
  156
+  # Options: mode noop verbose
  157
+  # 
  158
+  # Creates one or more directories.
  159
+  # 
  160
+  #   FileUtils.mkdir 'test'
  161
+  #   FileUtils.mkdir %w( tmp data )
  162
+  #   FileUtils.mkdir 'notexist', :noop => true  # Does not really create.
  163
+  #   FileUtils.mkdir 'tmp', :mode => 0700
  164
+  # 
  165
+  def mkdir(list, options = {})
  166
+    fu_check_options options, OPT_TABLE['mkdir']
  167
+    list = fu_list(list)
  168
+    fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
  169
+    return if options[:noop]
  170
+
  171
+    list.each do |dir|
  172
+      fu_mkdir dir, options[:mode]
  173
+    end
  174
+  end
  175
+  module_function :mkdir
  176
+
  177
+  OPT_TABLE['mkdir'] = [:mode, :noop, :verbose]
  178
+
  179
+  #
  180
+  # Options: mode noop verbose
  181
+  # 
  182
+  # Creates a directory and all its parent directories.
  183
+  # For example,
  184
+  # 
  185
+  #   FileUtils.mkdir_p '/usr/local/lib/ruby'
  186
+  # 
  187
+  # causes to make following directories, if it does not exist.
  188
+  #     * /usr
  189
+  #     * /usr/local
  190
+  #     * /usr/local/lib
  191
+  #     * /usr/local/lib/ruby
  192
+  #
  193
+  # You can pass several directories at a time in a list.
  194
+  # 
  195
+  def mkdir_p(list, options = {})
  196
+    fu_check_options options, OPT_TABLE['mkdir_p']
  197
+    list = fu_list(list)
  198
+    fu_output_message "mkdir -p #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
  199
+    return *list if options[:noop]
  200
+
  201
+    list.map {|path| path.sub(%r</\z>, '') }.each do |path|
  202
+      # optimize for the most common case
  203
+      begin
  204
+        fu_mkdir path, options[:mode]
  205
+        next
  206
+      rescue SystemCallError
  207
+        next if File.directory?(path)
  208
+      end
  209
+
  210
+      stack = []
  211
+      until path == stack.last   # dirname("/")=="/", dirname("C:/")=="C:/"
  212
+        stack.push path
  213
+        path = File.dirname(path)
  214
+      end
  215
+      stack.reverse_each do |path|
  216
+        begin
  217
+          fu_mkdir path, options[:mode]
  218
+        rescue SystemCallError => err
  219
+          raise unless File.directory?(path)
  220
+        end
  221
+      end
  222
+    end
  223
+
  224
+    return *list
  225
+  end
  226
+  module_function :mkdir_p
  227
+
  228
+  alias mkpath    mkdir_p
  229
+  alias makedirs  mkdir_p
  230
+  module_function :mkpath
  231
+  module_function :makedirs
  232
+
  233
+  OPT_TABLE['mkdir_p']  =
  234
+  OPT_TABLE['mkpath']   =
  235
+  OPT_TABLE['makedirs'] = [:mode, :noop, :verbose]
  236
+
  237
+  def fu_mkdir(path, mode)   #:nodoc:
  238
+    path = path.sub(%r</\z>, '')
  239
+    if mode
  240
+      Dir.mkdir path, mode
  241
+      File.chmod mode, path
  242
+    else
  243
+      Dir.mkdir path
  244
+    end
  245
+  end
  246
+  private_module_function :fu_mkdir
  247
+
  248
+  #
  249
+  # Options: noop, verbose
  250
+  # 
  251
+  # Removes one or more directories.
  252
+  # 
  253
+  #   FileUtils.rmdir 'somedir'
  254
+  #   FileUtils.rmdir %w(somedir anydir otherdir)
  255
+  #   # Does not really remove directory; outputs message.
  256
+  #   FileUtils.rmdir 'somedir', :verbose => true, :noop => true
  257
+  # 
  258
+  def rmdir(list, options = {})
  259
+    fu_check_options options, OPT_TABLE['rmdir']
  260
+    list = fu_list(list)
  261
+    fu_output_message "rmdir #{list.join ' '}" if options[:verbose]
  262
+    return if options[:noop]
  263
+    list.each do |dir|
  264
+      Dir.rmdir dir.sub(%r</\z>, '')
  265
+    end
  266
+  end
  267
+  module_function :rmdir
  268
+
  269
+  OPT_TABLE['rmdir'] = [:noop, :verbose]
  270
+
  271
+  #
  272
+  # Options: force noop verbose
  273
+  #
  274
+  # <b><tt>ln(old, new, options = {})</tt></b>
  275
+  #
  276
+  # Creates a hard link +new+ which points to +old+.
  277
+  # If +new+ already exists and it is a directory, creates a link +new/old+.
  278
+  # If +new+ already exists and it is not a directory, raises Errno::EEXIST.
  279
+  # But if :force option is set, overwrite +new+.
  280
+  # 
  281
+  #   FileUtils.ln 'gcc', 'cc', :verbose => true
  282
+  #   FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
  283
+  # 
  284
+  # <b><tt>ln(list, destdir, options = {})</tt></b>
  285
+  # 
  286
+  # Creates several hard links in a directory, with each one pointing to the
  287
+  # item in +list+.  If +destdir+ is not a directory, raises Errno::ENOTDIR.
  288
+  # 
  289
+  #   include FileUtils
  290
+  #   cd '/sbin'
  291
+  #   FileUtils.ln %w(cp mv mkdir), '/bin'   # Now /sbin/cp and /bin/cp are linked.
  292
+  # 
  293
+  def ln(src, dest, options = {})
  294
+    fu_check_options options, OPT_TABLE['ln']
  295
+    fu_output_message "ln#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
  296
+    return if options[:noop]
  297
+    fu_each_src_dest0(src, dest) do |s,d|
  298
+      remove_file d, true if options[:force]
  299
+      File.link s, d
  300
+    end
  301
+  end
  302
+  module_function :ln
  303
+
  304
+  alias link ln
  305
+  module_function :link
  306
+
  307
+  OPT_TABLE['ln']   =
  308
+  OPT_TABLE['link'] = [:force, :noop, :verbose]
  309
+
  310
+  #
  311
+  # Options: force noop verbose
  312
+  #
  313
+  # <b><tt>ln_s(old, new, options = {})</tt></b>
  314
+  # 
  315
+  # Creates a symbolic link +new+ which points to +old+.  If +new+ already
  316
+  # exists and it is a directory, creates a symbolic link +new/old+.  If +new+
  317
+  # already exists and it is not a directory, raises Errno::EEXIST.  But if
  318
+  # :force option is set, overwrite +new+.
  319
+  # 
  320
+  #   FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
  321
+  #   FileUtils.ln_s 'verylongsourcefilename.c', 'c', :force => true
  322
+  # 
  323
+  # <b><tt>ln_s(list, destdir, options = {})</tt></b>
  324
+  # 
  325
+  # Creates several symbolic links in a directory, with each one pointing to the
  326
+  # item in +list+.  If +destdir+ is not a directory, raises Errno::ENOTDIR.
  327
+  #
  328
+  # If +destdir+ is not a directory, raises Errno::ENOTDIR.
  329
+  # 
  330
+  #   FileUtils.ln_s Dir.glob('bin/*.rb'), '/home/aamine/bin'
  331
+  # 
  332
+  def ln_s(src, dest, options = {})
  333
+    fu_check_options options, OPT_TABLE['ln_s']
  334
+    fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
  335
+    return if options[:noop]
  336
+    fu_each_src_dest0(src, dest) do |s,d|
  337
+      remove_file d, true if options[:force]
  338
+      File.symlink s, d
  339
+    end
  340
+  end
  341
+  module_function :ln_s
  342
+
  343
+  alias symlink ln_s
  344
+  module_function :symlink
  345
+
  346
+  OPT_TABLE['ln_s']    =
  347
+  OPT_TABLE['symlink'] = [:force, :noop, :verbose]
  348
+
  349
+  #
  350
+  # Options: noop verbose
  351
+  # 
  352
+  # Same as
  353
+  #   #ln_s(src, dest, :force)
  354
+  # 
  355
+  def ln_sf(src, dest, options = {})
  356
+    fu_check_options options, OPT_TABLE['ln_sf']
  357
+    options = options.dup
  358
+    options[:force] = true
  359
+    ln_s src, dest, options
  360
+  end
  361
+  module_function :ln_sf
  362
+
  363
+  OPT_TABLE['ln_sf'] = [:noop, :verbose]
  364
+
  365
+  #
  366
+  # Options: preserve noop verbose
  367
+  #
  368
+  # Copies a file content +src+ to +dest+.  If +dest+ is a directory,
  369
+  # copies +src+ to +dest/src+.
  370
+  #
  371
+  # If +src+ is a list of files, then +dest+ must be a directory.
  372
+  #
  373
+  #   FileUtils.cp 'eval.c', 'eval.c.org'
  374
+  #   FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
  375
+  #   FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true
  376
+  #   FileUtils.cp 'symlink', 'dest'   # copy content, "dest" is not a symlink
  377
+  # 
  378
+  def cp(src, dest, options = {})
  379
+    fu_check_options options, OPT_TABLE['cp']
  380
+    fu_output_message "cp#{options[:preserve] ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
  381
+    return if options[:noop]
  382
+    fu_each_src_dest(src, dest) do |s, d|
  383
+      copy_file s, d, options[:preserve]
  384
+    end
  385
+  end
  386
+  module_function :cp
  387
+
  388
+  alias copy cp
  389
+  module_function :copy
  390
+
  391
+  OPT_TABLE['cp']   =
  392
+  OPT_TABLE['copy'] = [:preserve, :noop, :verbose]
  393
+
  394
+  #
  395
+  # Options: preserve noop verbose dereference_root remove_destination
  396
+  # 
  397
+  # Copies +src+ to +dest+. If +src+ is a directory, this method copies
  398
+  # all its contents recursively. If +dest+ is a directory, copies
  399
+  # +src+ to +dest/src+.
  400
+  #
  401
+  # +src+ can be a list of files.
  402
+  # 
  403
+  #   # Installing ruby library "mylib" under the site_ruby
  404
+  #   FileUtils.rm_r site_ruby + '/mylib', :force
  405
+  #   FileUtils.cp_r 'lib/', site_ruby + '/mylib'
  406
+  # 
  407
+  #   # Examples of copying several files to target directory.
  408
+  #   FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
  409
+  #   FileUtils.cp_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
  410
+  #
  411
+  #   # If you want to copy all contents of a directory instead of the
  412
+  #   # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
  413
+  #   # use following code.
  414
+  #   FileUtils.cp_r 'src/.', 'dest'     # cp_r('src', 'dest') makes src/dest,
  415
+  #                                      # but this doesn't.
  416
+  # 
  417
+  def cp_r(src, dest, options = {})
  418
+    fu_check_options options, OPT_TABLE['cp_r']
  419
+    fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
  420
+    return if options[:noop]
  421
+    options[:dereference_root] = true unless options.key?(:dereference_root)
  422
+    fu_each_src_dest(src, dest) do |s, d|
  423
+      copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination]
  424
+    end
  425
+  end
  426
+  module_function :cp_r
  427
+
  428
+  OPT_TABLE['cp_r'] = [:preserve, :noop, :verbose,
  429
+                       :dereference_root, :remove_destination]
  430
+
  431
+  #
  432
+  # Copies a file system entry +src+ to +dest+.
  433
+  # If +src+ is a directory, this method copies its contents recursively.
  434
+  # This method preserves file types, c.f. symlink, directory...
  435
+  # (FIFO, device files and etc. are not supported yet)
  436
+  #
  437
+  # Both of +src+ and +dest+ must be a path name.
  438
+  # +src+ must exist, +dest+ must not exist.
  439
+  #
  440
+  # If +preserve+ is true, this method preserves owner, group, permissions
  441
+  # and modified time.
  442
+  #
  443
+  # If +dereference_root+ is true, this method dereference tree root.
  444
+  #
  445
+  # If +remove_destination+ is true, this method removes each destination file before copy.
  446
+  #
  447
+  def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
  448
+    Entry_.new(src, nil, dereference_root).traverse do |ent|
  449
+      destent = Entry_.new(dest, ent.rel, false)
  450
+      File.unlink destent.path if remove_destination && File.file?(destent.path)
  451
+      ent.copy destent.path
  452
+      ent.copy_metadata destent.path if preserve
  453
+    end
  454
+  end
  455
+  module_function :copy_entry
  456
+
  457
+  #
  458
+  # Copies file contents of +src+ to +dest+.
  459
+  # Both of +src+ and +dest+ must be a path name.
  460
+  #
  461
+  def copy_file(src, dest, preserve = false, dereference = true)
  462
+    ent = Entry_.new(src, nil, dereference)
  463
+    ent.copy_file dest
  464
+    ent.copy_metadata dest if preserve
  465
+  end
  466
+  module_function :copy_file
  467
+
  468
+  #
  469
+  # Copies stream +src+ to +dest+.
  470
+  # +src+ must respond to #read(n) and
  471
+  # +dest+ must respond to #write(str).
  472
+  #
  473
+  def copy_stream(src, dest)
  474
+    fu_copy_stream0 src, dest, fu_stream_blksize(src, dest)
  475
+  end
  476
+  module_function :copy_stream
  477
+
  478
+  #
  479
+  # Options: force noop verbose
  480
+  # 
  481
+  # Moves file(s) +src+ to +dest+.  If +file+ and +dest+ exist on the different
  482
+  # disk partition, the file is copied instead.
  483
+  # 
  484
+  #   FileUtils.mv 'badname.rb', 'goodname.rb'
  485
+  #   FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', :force => true  # no error
  486
+  # 
  487
+  #   FileUtils.mv %w(junk.txt dust.txt), '/home/aamine/.trash/'
  488
+  #   FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
  489
+  # 
  490
+  def mv(src, dest, options = {})
  491
+    fu_check_options options, OPT_TABLE['mv']
  492
+    fu_output_message "mv#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
  493
+    return if options[:noop]
  494
+    fu_each_src_dest(src, dest) do |s, d|
  495
+      destent = Entry_.new(d, nil, true)
  496
+      begin
  497
+        if destent.exist?
  498
+          if destent.directory?
  499
+            raise Errno::EEXIST, dest
  500
+          else
  501
+            destent.remove_file if rename_cannot_overwrite_file?
  502
+          end
  503
+        end
  504
+        begin
  505
+          File.rename s, d
  506
+        rescue Errno::EXDEV
  507
+          copy_entry s, d, true
  508
+          if options[:secure]
  509
+            remove_entry_secure s, options[:force]
  510
+          else
  511
+            remove_entry s, options[:force]
  512
+          end
  513
+        end
  514
+      rescue SystemCallError
  515
+        raise unless options[:force]
  516
+      end
  517
+    end
  518
+  end
  519
+  module_function :mv
  520
+
  521
+  alias move mv
  522
+  module_function :move
  523
+
  524
+  OPT_TABLE['mv']   =
  525
+  OPT_TABLE['move'] = [:force, :noop, :verbose, :secure]
  526
+
  527
+  def rename_cannot_overwrite_file?   #:nodoc:
  528
+    /djgpp|cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
  529
+  end
  530
+  private_module_function :rename_cannot_overwrite_file?
  531
+
  532
+  #
  533
+  # Options: force noop verbose
  534
+  # 
  535
+  # Remove file(s) specified in +list+.  This method cannot remove directories.
  536
+  # All StandardErrors are ignored when the :force option is set.
  537
+  # 
  538
+  #   FileUtils.rm %w( junk.txt dust.txt )
  539
+  #   FileUtils.rm Dir.glob('*.so')
  540
+  #   FileUtils.rm 'NotExistFile', :force => true   # never raises exception
  541
+  # 
  542
+  def rm(list, options = {})
  543
+    fu_check_options options, OPT_TABLE['rm']
  544
+    list = fu_list(list)
  545
+    fu_output_message "rm#{options[:force] ? ' -f' : ''} #{list.join ' '}" if options[:verbose]
  546
+    return if options[:noop]
  547
+
  548
+    list.each do |path|
  549
+      remove_file path, options[:force]
  550
+    end
  551
+  end
  552
+  module_function :rm
  553
+
  554
+  alias remove rm
  555
+  module_function :remove
  556
+
  557
+  OPT_TABLE['rm']     =
  558
+  OPT_TABLE['remove'] = [:force, :noop, :verbose]
  559
+
  560
+  #
  561
+  # Options: noop verbose
  562
+  # 
  563
+  # Equivalent to
  564
+  #
  565
+  #   #rm(list, :force => true)
  566
+  #
  567
+  def rm_f(list, options = {})
  568
+    fu_check_options options, OPT_TABLE['rm_f']
  569
+    options = options.dup
  570
+    options[:force] = true
  571
+    rm list, options
  572
+  end
  573
+  module_function :rm_f
  574
+
  575
+  alias safe_unlink rm_f
  576
+  module_function :safe_unlink
  577
+
  578
+  OPT_TABLE['rm_f']        =
  579
+  OPT_TABLE['safe_unlink'] = [:noop, :verbose]
  580
+
  581
+  #
  582
+  # Options: force noop verbose secure
  583
+  # 
  584
+  # remove files +list+[0] +list+[1]... If +list+[n] is a directory,
  585
+  # removes its all contents recursively. This method ignores
  586
+  # StandardError when :force option is set.
  587
+  # 
  588
+  #   FileUtils.rm_r Dir.glob('/tmp/*')
  589
+  #   FileUtils.rm_r '/', :force => true          #  :-)
  590
+  #
  591
+  # WARNING: This method causes local vulnerability
  592
+  # if one of parent directories or removing directory tree are world
  593
+  # writable (including /tmp, whose permission is 1777), and the current
  594
+  # process has strong privilege such as Unix super user (root), and the
  595
+  # system has symbolic link.  For secure removing, read the documentation
  596
+  # of #remove_entry_secure carefully, and set :secure option to true.
  597
+  # Default is :secure=>false.
  598
+  #
  599
+  # NOTE: This method calls #remove_entry_secure if :secure option is set.
  600
+  # See also #remove_entry_secure.
  601
+  # 
  602
+  def rm_r(list, options = {})
  603
+    fu_check_options options, OPT_TABLE['rm_r']
  604
+    # options[:secure] = true unless options.key?(:secure)
  605
+    list = fu_list(list)
  606
+    fu_output_message "rm -r#{options[:force] ? 'f' : ''} #{list.join ' '}" if options[:verbose]
  607
+    return if options[:noop]
  608
+    list.each do |path|
  609
+      if options[:secure]
  610
+        remove_entry_secure path, options[:force]
  611
+      else
  612
+        remove_entry path, options[:force]
  613
+      end
  614
+    end
  615
+  end
  616
+  module_function :rm_r
  617
+
  618
+  OPT_TABLE['rm_r'] = [:force, :noop, :verbose, :secure]
  619
+
  620
+  #
  621
+  # Options: noop verbose secure
  622
+  # 
  623
+  # Equivalent to
  624
+  #
  625
+  #   #rm_r(list, :force => true)
  626
+  #
  627
+  # WARNING: This method causes local vulnerability.
  628
+  # Read the documentation of #rm_r first.
  629
+  # 
  630
+  def rm_rf(list, options = {})
  631
+    fu_check_options options, OPT_TABLE['rm_rf']
  632
+    options = options.dup
  633
+    options[:force] = true
  634
+    rm_r list, options
  635
+  end
  636
+  module_function :rm_rf
  637
+
  638
+  alias rmtree rm_rf
  639
+  module_function :rmtree
  640
+
  641
+  OPT_TABLE['rm_rf']  =
  642
+  OPT_TABLE['rmtree'] = [:noop, :verbose, :secure]
  643
+
  644
+  #
  645
+  # This method removes a file system entry +path+.  +path+ shall be a
  646
+  # regular file, a directory, or something.  If +path+ is a directory,
  647
+  # remove it recursively.  This method is required to avoid TOCTTOU
  648
+  # (time-of-check-to-time-of-use) local security vulnerability of #rm_r.
  649
+  # #rm_r causes security hole when:
  650
+  #
  651
+  #   * Parent directory is world writable (including /tmp).
  652
+  #   * Removing directory tree includes world writable directory.
  653
+  #   * The system has symbolic link.
  654
+  #
  655
+  # To avoid this security hole, this method applies special preprocess.
  656
+  # If +path+ is a directory, this method chown(2) and chmod(2) all
  657
+  # removing directories.  This requires the current process is the
  658
+  # owner of the removing whole directory tree, or is the super user (root).
  659
+  #
  660
+  # WARNING: You must ensure that *ALL* parent directories are not
  661
+  # world writable.  Otherwise this method does not work.
  662
+  # Only exception is temporary directory like /tmp and /var/tmp,
  663
+  # whose permission is 1777.
  664
+  #
  665
+  # WARNING: Only the owner of the removing directory tree, or Unix super
  666
+  # user (root) should invoke this method.  Otherwise this method does not
  667
+  # work.
  668
+  #
  669
+  # For details of this security vulnerability, see Perl's case:
  670
+  #
  671
+  #   http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448
  672
+  #   http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452
  673
+  #
  674
+  # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100].
  675
+  #
  676
+  def remove_entry_secure(path, force = false)
  677
+    unless fu_have_symlink?
  678
+      remove_entry path, force
  679
+      return
  680
+    end
  681
+    fullpath = File.expand_path(path)
  682
+    st = File.lstat(fullpath)
  683
+    unless st.directory?
  684
+      File.unlink fullpath
  685
+      return
  686
+    end
  687
+    # is a directory.
  688
+    parent_st = File.stat(File.dirname(fullpath))
  689
+    unless fu_world_writable?(parent_st)
  690
+      remove_entry path, force
  691
+      return
  692
+    end
  693
+    unless parent_st.sticky?
  694
+      raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
  695
+    end
  696
+    # freeze tree root
  697
+    euid = Process.euid
  698
+    File.open(fullpath + '/.') {|f|
  699
+      unless fu_stat_identical_entry?(st, f.stat)
  700
+        # symlink (TOC-to-TOU attack?)
  701
+        File.unlink fullpath
  702
+        return
  703
+      end
  704
+      f.chown euid, -1
  705
+      f.chmod 0700
  706
+    }
  707
+    # ---- tree root is frozen ----
  708
+    root = Entry_.new(path)
  709
+    root.preorder_traverse do |ent|
  710
+      if ent.directory?
  711
+        ent.chown euid, -1
  712
+        ent.chmod 0700
  713
+      end
  714
+    end
  715
+    root.postorder_traverse do |ent|
  716
+      begin
  717
+        ent.remove
  718
+      rescue
  719
+        raise unless force
  720
+      end
  721
+    end
  722
+  rescue
  723
+    raise unless force
  724
+  end
  725
+  module_function :remove_entry_secure
  726
+
  727
+  def fu_world_writable?(st)
  728
+    (st.mode & 0002) != 0
  729
+  end
  730
+  private_module_function :fu_world_writable?
  731
+
  732
+  def fu_have_symlink?   #:nodoc
  733
+    File.symlink nil, nil
  734
+  rescue NotImplementedError
  735
+    return false
  736
+  rescue
  737
+    return true
  738
+  end
  739
+  private_module_function :fu_have_symlink?
  740
+
  741
+  def fu_stat_identical_entry?(a, b)   #:nodoc:
  742
+    a.dev == b.dev and a.ino == b.ino
  743
+  end
  744
+  private_module_function :fu_stat_identical_entry?
  745
+
  746
+  #
  747
+  # This method removes a file system entry +path+.
  748
+  # +path+ might be a regular file, a directory, or something.
  749
+  # If +path+ is a directory, remove it recursively.
  750
+  #
  751
+  # See also #remove_entry_secure.
  752
+  #
  753
+  def remove_entry(path, force = false)
  754
+    Entry_.new(path).postorder_traverse do |ent|
  755
+      begin
  756
+        ent.remove
  757
+      rescue
  758
+        raise unless force
  759
+      end
  760
+    end
  761
+  rescue
  762
+    raise unless force
  763
+  end
  764
+  module_function :remove_entry
  765
+
  766
+  #
  767
+  # Removes a file +path+.
  768
+  # This method ignores StandardError if +force+ is true.
  769
+  #
  770
+  def remove_file(path, force = false)
  771
+    Entry_.new(path).remove_file
  772
+  rescue
  773
+    raise unless force
  774
+  end
  775
+  module_function :remove_file
  776
+
  777
+  #
  778
+  # Removes a directory +dir+ and its contents recursively.
  779
+  # This method ignores StandardError if +force+ is true.
  780
+  #
  781
+  def remove_dir(path, force = false)
  782
+    remove_entry path, force   # FIXME?? check if it is a directory
  783
+  end
  784
+  module_function :remove_dir
  785
+
  786
+  #
  787
+  # Returns true if the contents of a file A and a file B are identical.
  788
+  # 
  789
+  #   FileUtils.compare_file('somefile', 'somefile')  #=> true
  790
+  #   FileUtils.compare_file('/bin/cp', '/bin/mv')    #=> maybe false
  791
+  #
  792
+  def compare_file(a, b)
  793
+    return false unless File.size(a) == File.size(b)
  794
+    File.open(a, 'rb') {|fa|
  795
+      File.open(b, 'rb') {|fb|
  796
+        return compare_stream(fa, fb)
  797
+      }
  798
+    }
  799
+  end
  800
+  module_function :compare_file
  801
+
  802
+  alias identical? compare_file
  803
+  alias cmp compare_file
  804
+  module_function :identical?
  805
+  module_function :cmp
  806
+
  807
+  #
  808
+  # Returns true if the contents of a stream +a+ and +b+ are identical.
  809
+  #
  810
+  def compare_stream(a, b)
  811
+    bsize = fu_stream_blksize(a, b)
  812
+    sa = sb = nil
  813
+    while sa == sb
  814
+      sa = a.read(bsize)
  815
+      sb = b.read(bsize)
  816
+      unless sa and sb
  817
+        if sa.nil? and sb.nil?
  818
+          return true
  819
+        end
  820
+      end
  821
+    end
  822
+    false
  823
+  end
  824
+  module_function :compare_stream
  825
+
  826
+  #
  827
+  # Options: mode preserve noop verbose
  828
+  # 
  829
+  # If +src+ is not same as +dest+, copies it and changes the permission
  830
+  # mode to +mode+.  If +dest+ is a directory, destination is +dest+/+src+.
  831
+  # This method removes destination before copy.
  832
+  # 
  833
+  #   FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true
  834
+  #   FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true
  835
+  # 
  836
+  def install(src, dest, options = {})
  837
+    fu_check_options options, OPT_TABLE['install']
  838
+    fu_output_message "install -c#{options[:preserve] && ' -p'}#{options[:mode] ? (' -m 0%o' % options[:mode]) : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
  839
+    return if options[:noop]
  840
+    fu_each_src_dest(src, dest) do |s, d|
  841
+      unless File.exist?(d) and compare_file(s, d)
  842
+        remove_file d, true
  843
+        st = File.stat(s) if options[:preserve]
  844
+        copy_file s, d
  845
+        File.utime st.atime, st.mtime, d if options[:preserve]
  846
+        File.chmod options[:mode], d if options[:mode]
  847
+      end
  848
+    end
  849
+  end
  850
+  module_function :install
  851
+
  852
+  OPT_TABLE['install'] = [:mode, :preserve, :noop, :verbose]
  853
+
  854
+  #
  855
+  # Options: noop verbose
  856
+  # 
  857
+  # Changes permission bits on the named files (in +list+) to the bit pattern
  858
+  # represented by +mode+.
  859
+  # 
  860
+  #   FileUtils.chmod 0755, 'somecommand'
  861
+  #   FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
  862
+  #   FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true
  863
+  # 
  864
+  def chmod(mode, list, options = {})
  865
+    fu_check_options options, OPT_TABLE['chmod']
  866
+    list = fu_list(list)
  867
+    fu_output_message sprintf('chmod %o %s', mode, list.join(' ')) if options[:verbose]
  868
+    return if options[:noop]
  869
+    list.each do |path|
  870
+      Entry_.new(path).chmod mode
  871
+    end
  872
+  end
  873
+  module_function :chmod
  874
+
  875
+  OPT_TABLE['chmod'] = [:noop, :verbose]
  876
+
  877
+  #
  878
+  # Options: noop verbose force
  879
+  # 
  880
+  # Changes permission bits on the named files (in +list+)
  881
+  # to the bit pattern represented by +mode+.
  882
+  # 
  883
+  #   FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
  884
+  # 
  885
+  def chmod_R(mode, list, options = {})
  886
+    fu_check_options options, OPT_TABLE['chmod_R']
  887
+    list = fu_list(list)
  888
+    fu_output_message sprintf('chmod -R%s %o %s',
  889
+                              (options[:force] ? 'f' : ''),
  890
+                              mode, list.join(' ')) if options[:verbose]
  891
+    return if options[:noop]
  892
+    list.each do |root|
  893
+      Entry_.new(root).traverse do |ent|
  894
+        begin
  895
+          ent.chmod mode
  896
+        rescue
  897
+          raise unless options[:force]
  898
+        end
  899
+      end
  900
+    end
  901
+  end
  902
+  module_function :chmod_R
  903
+
  904
+  OPT_TABLE['chmod_R'] = [:noop, :verbose, :force]
  905
+
  906
+  #
  907
+  # Options: noop verbose
  908
+  # 
  909
+  # Changes owner and group on the named files (in +list+)
  910
+  # to the user +user+ and the group +group+.  +user+ and +group+
  911
+  # may be an ID (Integer/String) or a name (String).
  912
+  # If +user+ or +group+ is nil, this method does not change
  913
+  # the attribute.
  914
+  # 
  915
+  #   FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
  916
+  #   FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
  917
+  # 
  918
+  def chown(user, group, list, options = {})
  919
+    fu_check_options options, OPT_TABLE['chown']
  920
+    list = fu_list(list)
  921
+    fu_output_message sprintf('chown %s%s',
  922
+                              [user,group].compact.join(':') + ' ',
  923
+                              list.join(' ')) if options[:verbose]
  924
+    return if options[:noop]
  925
+    uid = fu_get_uid(user)
  926
+    gid = fu_get_gid(group)
  927
+    list.each do |path|
  928
+      Entry_.new(path).chown uid, gid
  929
+    end
  930
+  end
  931
+  module_function :chown
  932
+
  933
+  OPT_TABLE['chown'] = [:noop, :verbose]
  934
+
  935
+  #
  936
+  # Options: noop verbose force
  937
+  # 
  938
+  # Changes owner and group on the named files (in +list+)
  939
+  # to the user +user+ and the group +group+ recursively.
  940
+  # +user+ and +group+ may be an ID (Integer/String) or
  941
+  # a name (String).  If +user+ or +group+ is nil, this
  942
+  # method does not change the attribute.
  943
+  # 
  944
+  #   FileUtils.chown_R 'www', 'www', '/var/www/htdocs'
  945
+  #   FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
  946
+  # 
  947
+  def chown_R(user, group, list, options = {})
  948
+    fu_check_options options, OPT_TABLE['chown_R']
  949
+    list = fu_list(list)
  950
+    fu_output_message sprintf('chown -R%s %s%s',
  951
+                              (options[:force] ? 'f' : ''),
  952
+                              [user,group].compact.join(':') + ' ',
  953
+                              list.join(' ')) if options[:verbose]
  954
+    return if options[:noop]
  955
+    uid = fu_get_uid(user)
  956
+    gid = fu_get_gid(group)
  957
+    return unless uid or gid
  958
+    list.each do |root|
  959
+      Entry_.new(root).traverse do |ent|
  960
+        begin
  961
+          ent.chown uid, gid
  962
+        rescue
  963
+          raise unless options[:force]
  964
+        end
  965
+      end
  966
+    end
  967
+  end
  968
+  module_function :chown_R
  969
+
  970
+  OPT_TABLE['chown_R'] = [:noop, :verbose, :force]
  971
+
  972
+  begin
  973
+    require 'etc'
  974
+
  975
+    def fu_get_uid(user)   #:nodoc:
  976
+      return nil unless user
  977
+      user = user.to_s
  978
+      if /\A\d+\z/ =~ user
  979
+      then user.to_i
  980
+      else Etc.getpwnam(user).uid
  981
+      end
  982
+    end
  983
+    private_module_function :fu_get_uid
  984
+
  985
+    def fu_get_gid(group)   #:nodoc:
  986
+      return nil unless group
  987
+      if /\A\d+\z/ =~ group
  988
+      then group.to_i
  989
+      else Etc.getgrnam(group).gid
  990
+      end
  991
+    end
  992
+    private_module_function :fu_get_gid
  993
+
  994
+  rescue LoadError
  995
+    # need Win32 support???
  996
+
  997
+    def fu_get_uid(user)   #:nodoc:
  998
+      user    # FIXME
  999
+    end
  1000
+    private_module_function :fu_get_uid
  1001
+
  1002
+    def fu_get_gid(group)   #:nodoc:
  1003
+      group   # FIXME
  1004
+    end
  1005
+    private_module_function :fu_get_gid
  1006
+  end
  1007
+
  1008
+  #
  1009
+  # Options: noop verbose
  1010
+  # 
  1011
+  # Updates modification time (mtime) and access time (atime) of file(s) in
  1012
+  # +list+.  Files are created if they don't exist.
  1013
+  # 
  1014
+  #   FileUtils.touch 'timestamp'
  1015
+  #   FileUtils.touch Dir.glob('*.c');  system 'make'
  1016
+  # 
  1017
+  def touch(list, options = {})
  1018
+    fu_check_options options, OPT_TABLE['touch']
  1019
+    list = fu_list(list)
  1020
+    created = nocreate = options[:nocreate]
  1021
+    t = options[:mtime]
  1022
+    if options[:verbose]
  1023
+      fu_output_message "touch #{nocreate ? ' -c' : ''}#{t ? t.strftime(' -t %Y%m%d%H%M.%S') : ''}#{list.join ' '}"
  1024
+    end
  1025
+    return if options[:noop]
  1026
+    list.each do |path|
  1027
+      created = nocreate
  1028
+      begin
  1029
+        File.utime(t, t, path)
  1030
+      rescue Errno::ENOENT
  1031
+        raise if created
  1032
+        File.open(path, 'a') {
  1033
+          ;
  1034
+        }
  1035
+        created = true
  1036
+        retry if t
  1037
+      end
  1038
+    end
  1039
+  end
  1040
+  module_function :touch
  1041
+
  1042
+  OPT_TABLE['touch'] = [:noop, :verbose, :mtime, :nocreate]
  1043
+
  1044
+  private
  1045
+
  1046
+  module StreamUtils_
  1047
+    private
  1048
+
  1049
+    def fu_windows?
  1050
+      /mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
  1051
+    end
  1052
+
  1053
+    def fu_copy_stream0(src, dest, blksize)   #:nodoc:
  1054
+      # FIXME: readpartial?
  1055
+      while s = src.read(blksize)
  1056
+        dest.write s
  1057
+      end
  1058
+    end
  1059
+
  1060
+    def fu_stream_blksize(*streams)
  1061
+      streams.each do |s|
  1062
+        next unless s.respond_to?(:stat)
  1063
+        size = fu_blksize(s.stat)
  1064
+        return size if size
  1065
+      end
  1066
+      fu_default_blksize()
  1067
+    end
  1068
+
  1069
+    def fu_blksize(st)
  1070
+      s = st.blksize
  1071
+      return nil unless s
  1072
+      return nil if s == 0
  1073
+      s
  1074
+    end
  1075
+
  1076
+    def fu_default_blksize
  1077
+      1024
  1078
+    end
  1079
+  end
  1080
+
  1081
+  include StreamUtils_