Spec-Zone.ru › Ruby 2.5

модуль FileUtils

Включенные модули:
FileUtils::StreamUtils_

fileutils.rb

Авторское право © 2000-2007 Minero Aoki

Эта программа — свободное программное обеспечение. Вы можете распространять/изменять эту программу на тех же условиях, что и Ruby.

модуль FileUtils

Пространство имён для нескольких методов работы с файлами для копирования, перемещения, удаления и т. д.

Функции модуля

require 'fileutils'

FileUtils.cd(dir, options)
FileUtils.cd(dir, options) {|dir| block }
FileUtils.pwd()
FileUtils.mkdir(dir, options)
FileUtils.mkdir(list, options)
FileUtils.mkdir_p(dir, options)
FileUtils.mkdir_p(list, options)
FileUtils.rmdir(dir, options)
FileUtils.rmdir(list, options)
FileUtils.ln(target, link, options)
FileUtils.ln(targets, dir, options)
FileUtils.ln_s(target, link, options)
FileUtils.ln_s(targets, dir, options)
FileUtils.ln_sf(target, link, options)
FileUtils.cp(src, dest, options)
FileUtils.cp(list, dir, options)
FileUtils.cp_r(src, dest, options)
FileUtils.cp_r(list, dir, options)
FileUtils.mv(src, dest, options)
FileUtils.mv(list, dir, options)
FileUtils.rm(list, options)
FileUtils.rm_r(list, options)
FileUtils.rm_rf(list, options)
FileUtils.install(src, dest, options)
FileUtils.chmod(mode, list, options)
FileUtils.chmod_R(mode, list, options)
FileUtils.chown(user, group, list, options)
FileUtils.chown_R(user, group, list, options)
FileUtils.touch(list, options)

Параметр options — это хеш с опциями, взятыми из списка :force, :noop, :preserve, и :verbose. :noop означает, что никаких изменений не производится. Остальные три очевидны. Каждый метод документирует опции, которые он поддерживает.

Все методы, которые имеют понятие «исходного» файла или каталога, могут принимать либо один файл, либо список файлов в качестве аргумента. Примеры см. в документации к методу.

Есть некоторые методы «низкого уровня», которые не принимают никаких опций:

FileUtils.copy_entry(src, dest, preserve = false, dereference = false)
FileUtils.copy_file(src, dest, preserve = false, dereference = true)
FileUtils.copy_stream(srcstream, deststream)
FileUtils.remove_entry(path, force = false)
FileUtils.remove_entry_secure(path, force = false)
FileUtils.remove_file(path, force = false)
FileUtils.compare_file(path_a, path_b)
FileUtils.compare_stream(stream_a, stream_b)
FileUtils.uptodate?(file, cmp_list)

модуль FileUtils::Verbose

Этот модуль содержит все методы модуля FileUtils, но он выводит сообщения перед действием. Это эквивалентно передаче флага :verbose методам в модуле FileUtils.

модуль FileUtils::NoWrite

Этот модуль содержит все методы модуля FileUtils, но никогда не изменяет файлы/каталоги. Это эквивалентно передаче флага :noop методам в модуле FileUtils.

модуль FileUtils::DryRun

Этот модуль содержит все методы модуля FileUtils, но никогда не изменяет файлы/каталоги. Это эквивалентно передаче флагов :noop и :verbose методам в модуле FileUtils.

Константы

LOW_METHODS
METHODS
VERSION

Методы публичного класса

cd(dir, verbose: nil) { |dir| ... } Показать исходный код
# File lib/fileutils.rb, line 119
def cd(dir, verbose: nil, &block) # :yield: dir
  fu_output_message "cd #{dir}" if verbose
  Dir.chdir(dir, &block)
  fu_output_message 'cd -' if verbose and block
end

Изменяет текущий каталог на каталог dir.

Если этот метод вызывается с блоком, он возвращается в старый рабочий каталог после завершения выполнения блока.

FileUtils.cd('/', :verbose => true)   # chdir and report it

FileUtils.cd('/') do  # chdir
  # ...               # do something
end                   # return to original directory
Также алиас: chdir
chdir(dir, verbose: nil)
Псевдоним для: cd
chmod(mode, list, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 915
def chmod(mode, list, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
  return if noop
  list.each do |path|
    Entry_.new(path).chmod(fu_mode(mode, path))
  end
end

Изменяет биты разрешений указанных файлов (в list) на битовую схему, представленную mode.

Можно использовать символический и абсолютный режим.

Абсолютный режим

FileUtils.chmod 0755, 'somecommand'
FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true

Символический режим

FileUtils.chmod "u=wrx,go=rx", 'somecommand'
FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb)
FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', :verbose => true
“a”

— маска для пользователя, группы, других.

“u”

— маска для пользователя.

“g”

— маска для группы.

“o”

— маска для других.

“w”

— разрешение на запись.

“r”

— разрешение на чтение.

“x”

— разрешение на выполнение.

“X”

— разрешение на выполнение только для каталогов, должно использоваться совместно с “+”.

“s”

— uid, gid.

“t”

— битовая метка «sticky».

“+”

— добавляется к классу, заданному указанным режимом.

“-”

— удаляется из указанного класса, заданного режимом.

“=”

— точное значение класса будет задано указанным режимом.

chmod_R(mode, list, noop: nil, verbose: nil, force: nil) Показать исходный код
# File lib/fileutils.rb, line 932
def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
  list = fu_list(list)
  fu_output_message sprintf('chmod -R%s %s %s',
                            (force ? 'f' : ''),
                            mode_to_s(mode), list.join(' ')) if verbose
  return if noop
  list.each do |root|
    Entry_.new(root).traverse do |ent|
      begin
        ent.chmod(fu_mode(mode, ent.path))
      rescue
        raise unless force
      end
    end
  end
end

Изменяет биты разрешений указанных файлов (в list) на битовую схему, представленную mode.

FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
chown(user, group, list, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 960
def chown(user, group, list, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message sprintf('chown %s %s',
                            (group ? "#{user}:#{group}" : user || ':'),
                            list.join(' ')) if verbose
  return if noop
  uid = fu_get_uid(user)
  gid = fu_get_gid(group)
  list.each do |path|
    Entry_.new(path).chown uid, gid
  end
end

Изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group. user и group могут быть ID (целое число/строка) или именем (строка). Если user или group равно nil, этот метод не изменяет атрибут.

FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
chown_R(user, group, list, noop: nil, verbose: nil, force: nil) Показать исходный код
# File lib/fileutils.rb, line 984
def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
  list = fu_list(list)
  fu_output_message sprintf('chown -R%s %s %s',
                            (force ? 'f' : ''),
                            (group ? "#{user}:#{group}" : user || ':'),
                            list.join(' ')) if verbose
  return if noop
  uid = fu_get_uid(user)
  gid = fu_get_gid(group)
  list.each do |root|
    Entry_.new(root).traverse do |ent|
      begin
        ent.chown uid, gid
      rescue
        raise unless force
      end
    end
  end
end

Рекурсивно изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group рекурсивно. user и group могут быть ID (целое число/строка) или именем (строка). Если user или group равно nil, этот метод не изменяет атрибут.

FileUtils.chown_R 'www', 'www', '/var/www/htdocs'
FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
cmp(a, b)
Псевдоним для: compare_file
compare_file(a, b) Показать исходный код
# File lib/fileutils.rb, line 726
def compare_file(a, b)
  return false unless File.size(a) == File.size(b)
  File.open(a, 'rb') {|fa|
    File.open(b, 'rb') {|fb|
      return compare_stream(fa, fb)
    }
  }
end

Возвращает true, если содержимое файла a и файла b идентичны.

FileUtils.compare_file('somefile', 'somefile')       #=> true
FileUtils.compare_file('/dev/null', '/dev/urandom')  #=> false
Также алиас: identical?, cmp
compare_stream(a, b) Показать исходный код
# File lib/fileutils.rb, line 744
def compare_stream(a, b)
  bsize = fu_stream_blksize(a, b)
  sa = String.new(capacity: bsize)
  sb = String.new(capacity: bsize)
  begin
    a.read(bsize, sa)
    b.read(bsize, sb)
    return true if sa.empty? && sb.empty?
  end while sa == sb
  false
end

Возвращает true, если содержимое потока a и b идентичны.

copy(src, dest, preserve: nil, noop: nil, verbose: nil)
Псевдоним для: cp
copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) Показать исходный код
# File lib/fileutils.rb, line 413
def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
  Entry_.new(src, nil, dereference_root).wrap_traverse(proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
    ent.copy destent.path
  end, proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    ent.copy_metadata destent.path if preserve
  end)
end

Копирует элемент файловой системы src в dest. Если src является каталогом, этот метод копирует его содержимое рекурсивно. Этот метод сохраняет типы файлов, например, символическую ссылку, каталог… (FIFO, файлы устройств и т. д. пока не поддерживаются)

Оба src и dest должны быть именами путей. src должен существовать, dest не должен существовать.

Если preserve равно true, этот метод сохраняет владельца, группу и время изменения. Разрешения копируются независимо preserve.

Если dereference_root равно true, этот метод делает дереференец корня дерева.

Если remove_destination равно true, этот метод удаляет каждый целевой файл перед копированием.

copy_file(src, dest, preserve = false, dereference = true) Показать исходный код
# File lib/fileutils.rb, line 429
def copy_file(src, dest, preserve = false, dereference = true)
  ent = Entry_.new(src, nil, dereference)
  ent.copy_file dest
  ent.copy_metadata dest if preserve
end

Копирует содержимое файла src в dest. Оба src и dest должны быть именами путей.

copy_stream(src, dest) Показать исходный код
# File lib/fileutils.rb, line 441
def copy_stream(src, dest)
  IO.copy_stream(src, dest)
end

Копирует поток src в dest. src должен отвечать на чтение (n), а dest должен отвечать на запись (строка).

cp(src, dest, preserve: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 354
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
  fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_file s, d, preserve
  end
end

Копирует содержимое файла src в dest. Если dest является каталогом, копирует src в dest/src.

Если src является списком файлов, то dest должен быть каталогом.

FileUtils.cp 'eval.c', 'eval.c.org'
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true
FileUtils.cp 'symlink', 'dest'   # copy content, "dest" is not a symlink
Также алиас: copy
cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil) Показать исходный код
# File lib/fileutils.rb, line 387
def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
         dereference_root: true, remove_destination: nil)
  fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_entry s, d, preserve, dereference_root, remove_destination
  end
end

Копирует src в dest. Если src является каталогом, этот метод рекурсивно копирует все его содержимое. Если dest является каталогом, копирует src в dest/src.

src может быть списком файлов.

# Installing Ruby library "mylib" under the site_ruby
FileUtils.rm_r site_ruby + '/mylib', :force
FileUtils.cp_r 'lib/', site_ruby + '/mylib'

# Examples of copying several files to target directory.
FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', :noop => true, :verbose => true

# If you want to copy all contents of a directory instead of the
# directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
# use following code.
FileUtils.cp_r 'src/.', 'dest'     # cp_r('src', 'dest') makes dest/src,
                                   # but this doesn't.
getwd()
Псевдоним для: pwd
identical?(a, b)
Псевдоним для: compare_file
install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 765
def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
            noop: nil, verbose: nil)
  if verbose
    msg = +"install -c"
    msg << ' -p' if preserve
    msg << ' -m ' << mode_to_s(mode) if mode
    msg << " -o #{owner}" if owner
    msg << " -g #{group}" if group
    msg << ' ' << [src,dest].flatten.join(' ')
    fu_output_message msg
  end
  return if noop
  uid = fu_get_uid(owner)
  gid = fu_get_gid(group)
  fu_each_src_dest(src, dest) do |s, d|
    st = File.stat(s)
    unless File.exist?(d) and compare_file(s, d)
      remove_file d, true
      copy_file s, d
      File.utime st.atime, st.mtime, d if preserve
      File.chmod fu_mode(mode, st), d if mode
      File.chown uid, gid, d if uid or gid
    end
  end
end

Если src не совпадает с dest, копирует его и изменяет режим разрешений на mode. Если dest является каталогом, назначение — dest/src. Этот метод удаляет назначение перед копированием.

FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true
FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true
END_OF_DOCUMENT_MARKER
link(src, dest, force: nil, noop: nil, verbose: nil)
Псевдоним для: ln
ln(target, link, force: nil, noop: nil, verbose: nil) Показать исходный код
ln(target, dir, force: nil, noop: nil, verbose: nil)
ln(targets, dir, force: nil, noop: nil, verbose: nil)
# File lib/fileutils.rb, line 284
def ln(src, dest, force: nil, noop: nil, verbose: nil)
  fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest0(src, dest) do |s,d|
    remove_file d, true if force
    File.link s, d
  end
end

В первом случае создаёт жёсткую ссылку link, которая указывает на target. Если link уже существует, генерируется исключение Errno::EEXIST. Но если установлен параметр :force, то link перезаписывается.

FileUtils.ln 'gcc', 'cc', verbose: true
FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'

Во втором случае создаётся ссылка dir/target на target. В третьем случае создаются несколько жёстких ссылок в каталоге dir, указывающих на каждый элемент в targets. Если dir не является каталогом, генерируется исключение Errno::ENOTDIR.

FileUtils.cd '/sbin'
FileUtils.ln %w(cp mv mkdir), '/bin'   # Now /sbin/cp and /bin/cp are linked.
Также используется как: link
ln_s(target, link, force: nil, noop: nil, verbose: nil) Показать исходный код
ln_s(target, dir, force: nil, noop: nil, verbose: nil)
ln_s(targets, dir, force: nil, noop: nil, verbose: nil)
# File lib/fileutils.rb, line 317
def ln_s(src, dest, force: nil, noop: nil, verbose: nil)
  fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest0(src, dest) do |s,d|
    remove_file d, true if force
    File.symlink s, d
  end
end

В первом случае создаёт символическую ссылку link на target. Если link уже существует, генерируется исключение Errno::EEXIST. Но если установлен параметр :force, то link перезаписывается.

FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true

Во втором случае создаётся ссылка dir/target на target. В третьем случае создаются несколько символических ссылок в каталоге dir, указывающих на каждый элемент в targets. Если dir не является каталогом, генерируется исключение Errno::ENOTDIR.

FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin'
Также используется как: symlink
ln_sf(*args) Показать исходный код
# File lib/fileutils.rb, line 338
def ln_sf(src, dest, noop: nil, verbose: nil)
  ln_s src, dest, force: true, noop: noop, verbose: verbose
end

То же самое, что

FileUtils.ln_s(*args, force: true)
makedirs(list, mode: nil, noop: nil, verbose: nil)
Псевдоним для: mkdir_p
mkdir(list, mode: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 161
def mkdir(list, mode: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
  return if noop

  list.each do |dir|
    fu_mkdir dir, mode
  end
end

Создаёт один или несколько каталогов.

FileUtils.mkdir 'test'
FileUtils.mkdir %w( tmp data )
FileUtils.mkdir 'notexist', :noop => true  # Does not really create.
FileUtils.mkdir 'tmp', :mode => 0700
mkdir_p(list, mode: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 187
def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
  return *list if noop

  list.map {|path| remove_trailing_slash(path)}.each do |path|
    # optimize for the most common case
    begin
      fu_mkdir path, mode
      next
    rescue SystemCallError
      next if File.directory?(path)
    end

    stack = []
    until path == stack.last   # dirname("/")=="/", dirname("C:/")=="C:/"
      stack.push path
      path = File.dirname(path)
    end
    stack.pop                 # root directory should exist
    stack.reverse_each do |dir|
      begin
        fu_mkdir dir, mode
      rescue SystemCallError
        raise unless File.directory?(dir)
      end
    end
  end

  return *list
end

Создаёт каталог и все его родительские каталоги. Например,

FileUtils.mkdir_p '/usr/local/lib/ruby'

приводит к созданию следующих каталогов, если они не существуют.

  • /usr

  • /usr/local

  • /usr/local/lib

  • /usr/local/lib/ruby

Можно передавать несколько каталогов в списке.

Также используется как: mkpath, makedirs
mkpath(list, mode: nil, noop: nil, verbose: nil)
Псевдоним для: mkdir_p
move(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
Псевдоним для: mv
mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) Показать исходный код
# File lib/fileutils.rb, line 456
def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
  fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    destent = Entry_.new(d, nil, true)
    begin
      if destent.exist?
        if destent.directory?
          raise Errno::EEXIST, d
        else
          destent.remove_file if rename_cannot_overwrite_file?
        end
      end
      begin
        File.rename s, d
      rescue Errno::EXDEV
        copy_entry s, d, true
        if secure
          remove_entry_secure s, force
        else
          remove_entry s, force
        end
      end
    rescue SystemCallError
      raise unless force
    end
  end
end

Перемещает файл(ы) src в dest. Если file и dest находятся на разных разделах диска, файл копируется, а затем удаляется исходный файл.

FileUtils.mv 'badname.rb', 'goodname.rb'
FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', :force => true  # no error

FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/'
FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
Также используется как: move
pwd() Показать исходный код
# File lib/fileutils.rb, line 99
def pwd
  Dir.pwd
end

Возвращает имя текущего каталога.

Также используется как: getwd
remove(list, force: nil, noop: nil, verbose: nil)
Псевдоним для: rm
remove_dir(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 715
def remove_dir(path, force = false)
  remove_entry path, force   # FIXME?? check if it is a directory
end

Удаляет каталог dir и его содержимое рекурсивно. Этот метод игнорирует StandardError, если force равно true.

remove_entry(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 687
def remove_entry(path, force = false)
  Entry_.new(path).postorder_traverse do |ent|
    begin
      ent.remove
    rescue
      raise unless force
    end
  end
rescue
  raise unless force
end

Этот метод удаляет элемент файловой системы path. path может быть обычным файлом, каталогом или чем-то другим. Если path является каталогом, удаляет его рекурсивно.

См. также remove_entry_secure.

remove_entry_secure(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 610
def remove_entry_secure(path, force = false)
  unless fu_have_symlink?
    remove_entry path, force
    return
  end
  fullpath = File.expand_path(path)
  st = File.lstat(fullpath)
  unless st.directory?
    File.unlink fullpath
    return
  end
  # is a directory.
  parent_st = File.stat(File.dirname(fullpath))
  unless parent_st.world_writable?
    remove_entry path, force
    return
  end
  unless parent_st.sticky?
    raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
  end
  # freeze tree root
  euid = Process.euid
  File.open(fullpath + '/.') {|f|
    unless fu_stat_identical_entry?(st, f.stat)
      # symlink (TOC-to-TOU attack?)
      File.unlink fullpath
      return
    end
    f.chown euid, -1
    f.chmod 0700
    unless fu_stat_identical_entry?(st, File.lstat(fullpath))
      # TOC-to-TOU attack?
      File.unlink fullpath
      return
    end
  }
  # ---- tree root is frozen ----
  root = Entry_.new(path)
  root.preorder_traverse do |ent|
    if ent.directory?
      ent.chown euid, -1
      ent.chmod 0700
    end
  end
  root.postorder_traverse do |ent|
    begin
      ent.remove
    rescue
      raise unless force
    end
  end
rescue
  raise unless force
end

Этот метод удаляет элемент файловой системы path. path должен быть обычным файлом, каталогом или чем-то другим. Если path является каталогом, удаляет его рекурсивно. Этот метод необходим для предотвращения местной проблемы безопасности TOCTTOU (проверка состояния — время выполнения). rm_r вызывает проблему безопасности, когда:

  • Родительский каталог имеет права записи для всех (включая /tmp).

  • Удаляемая древовидная структура каталогов включает каталог с правами записи для всех.

  • В системе есть символические ссылки.

Для предотвращения этой проблемы безопасности этот метод применяет специальную предподготовку. Если path является каталогом, этот метод применяет chown(2) и chmod(2) ко всем удаляемым каталогам. Это требует, чтобы текущий процесс был владельцем всего удаляемого древовидного каталога или был суперпользователем (root).

ПРЕДУПРЕЖДЕНИЕ: Вы должны убедиться, что ВСЕ родительские каталоги не могут быть изменены другими пользователями, которым не доверяют. Например, родительские каталоги не должны принадлежать пользователям, которым не доверяют, и не должны иметь права записи для всех, за исключением случаев, когда установлен бит сохранения.

ПРЕДУПРЕЖДЕНИЕ: Только владелец удаляемой древовидной структуры каталогов или Unix-суперпользователь (root) должен вызывать этот метод. В противном случае этот метод не работает.

Для получения подробностей об этой проблеме безопасности см. примеры Perl:

  • www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448

  • www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452

Для fileutils.rb эта проблема безопасности была описана в [ruby-dev:26100].

remove_file(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 704
def remove_file(path, force = false)
  Entry_.new(path).remove_file
rescue
  raise unless force
end

Удаляет файл path. Этот метод игнорирует StandardError, если force равно true.

rm(list, force: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 502
def rm(list, force: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose
  return if noop

  list.each do |path|
    remove_file path, force
  end
end

Удаляет файлы, указанные в list. Этот метод не может удалять каталоги. Все StandardErrors игнорируются, когда параметр :force установлен.

FileUtils.rm %w( junk.txt dust.txt )
FileUtils.rm Dir.glob('*.so')
FileUtils.rm 'NotExistFile', :force => true   # never raises exception
Также используется как: remove
END_OF_DOCUMENT_MARKER
rm_f(list, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 521
def rm_f(list, noop: nil, verbose: nil)
  rm list, force: true, noop: noop, verbose: verbose
end

Эквивалентно

FileUtils.rm(list, :force => true)
Также алиасируется как: safe_unlink
rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) Показать исходный код
# File lib/fileutils.rb, line 548
def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
  list = fu_list(list)
  fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose
  return if noop
  list.each do |path|
    if secure
      remove_entry_secure path, force
    else
      remove_entry path, force
    end
  end
end

Удаляет файлы list[0] list[1]… Если list[n] является каталогом, удаляет его содержимое рекурсивно. Этот метод игнорирует StandardError, когда установлен параметр :force.

FileUtils.rm_r Dir.glob('/tmp/*')
FileUtils.rm_r 'some_dir', :force => true

ВНИМАНИЕ: Этот метод может привести к уязвимости в локальной системе, если один из родительских каталогов или удаляемая структура каталогов имеют права доступа "для всех" (включая /tmp, права которого составляют 1777), а текущий процесс обладает высокими привилегиями, такими как права суперпользователя (root), и на системе имеются символические ссылки. Для безопасного удаления внимательно изучите документацию remove_entry_secure и установите параметр :secure в значение true. По умолчанию :secure=>false.

ПРИМЕЧАНИЕ: Этот метод вызывает remove_entry_secure, если параметр :secure установлен. Смотрите также remove_entry_secure.

rm_rf(list, noop: nil, verbose: nil, secure: nil) Показать исходный код
# File lib/fileutils.rb, line 570
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
  rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
end

Эквивалентно

FileUtils.rm_r(list, :force => true)

ВНИМАНИЕ: Этот метод может привести к уязвимости в локальной системе. Сначала ознакомьтесь с документацией rm_r.

Также алиасируется как: rmtree
rmdir(list, parents: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 244
def rmdir(list, parents: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
  return if noop
  list.each do |dir|
    Dir.rmdir(dir = remove_trailing_slash(dir))
    if parents
      begin
        until (parent = File.dirname(dir)) == '.' or parent == dir
          dir = parent
          Dir.rmdir(dir)
        end
      rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
      end
    end
  end
end

Удаляет один или несколько каталогов.

FileUtils.rmdir 'somedir'
FileUtils.rmdir %w(somedir anydir otherdir)
# Does not really remove directory; outputs message.
FileUtils.rmdir 'somedir', :verbose => true, :noop => true
rmtree(list, noop: nil, verbose: nil, secure: nil)
Псевдоним для: rm_rf
safe_unlink(list, noop: nil, verbose: nil)
Псевдоним для: rm_f
symlink(src, dest, force: nil, noop: nil, verbose: nil)
Псевдоним для: ln_s
touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) Показать исходный код
# File lib/fileutils.rb, line 1043
def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
  list = fu_list(list)
  t = mtime
  if verbose
    fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
  end
  return if noop
  list.each do |path|
    created = nocreate
    begin
      File.utime(t, t, path)
    rescue Errno::ENOENT
      raise if created
      File.open(path, 'a') {
        ;
      }
      created = true
      retry if t
    end
  end
end

Обновляет время изменения (mtime) и время доступа (atime) файла(ов) в list. Файлы создаются, если они не существуют.

FileUtils.touch 'timestamp'
FileUtils.touch Dir.glob('*.c');  system 'make'
uptodate?(new, old_list) Показать исходный код
# File lib/fileutils.rb, line 136
def uptodate?(new, old_list)
  return false unless File.exist?(new)
  new_time = File.mtime(new)
  old_list.each do |old|
    if File.exist?(old)
      return false unless new_time > File.mtime(old)
    end
  end
  true
end

Возвращает true, если new новее всех old_list. Несуществующие файлы считаются старше любого файла.

FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
    system 'make hello.o'

Методы класса (private)

collect_method(opt) Показать исходный код
# File lib/fileutils.rb, line 1550
def self.collect_method(opt)
  OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
end

Возвращает массив имён методов, которые имеют параметр opt.

p FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"]
commands() Показать исходный код
# File lib/fileutils.rb, line 1511
def self.commands
  OPT_TABLE.keys
end

Возвращает массив имён методов, которые имеют любые параметры.

p FileUtils.commands  #=> ["chmod", "cp", "cp_r", "install", ...]
have_option?(mid, opt) Показать исходный код
# File lib/fileutils.rb, line 1531
def self.have_option?(mid, opt)
  li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
  li.include?(opt)
end

Возвращает true, если метод mid имеет параметр opt.

p FileUtils.have_option?(:cp, :noop)     #=> true
p FileUtils.have_option?(:rm, :force)    #=> true
p FileUtils.have_option?(:rm, :preserve) #=> false
options() Показать исходный код
# File lib/fileutils.rb, line 1520
def self.options
  OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
end

Возвращает массив имён параметров.

p FileUtils.options  #=> ["noop", "force", "verbose", "preserve", "mode"]
options_of(mid) Показать исходный код
# File lib/fileutils.rb, line 1541
def self.options_of(mid)
  OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
end

Возвращает массив имён параметров метода mid.

p FileUtils.options_of(:rm)  #=> ["noop", "verbose", "force"]

Методы частного экземпляра

cd(dir, verbose: nil) { |dir| ... } Показать исходный код
# File lib/fileutils.rb, line 119
def cd(dir, verbose: nil, &block) # :yield: dir
  fu_output_message "cd #{dir}" if verbose
  Dir.chdir(dir, &block)
  fu_output_message 'cd -' if verbose and block
end

Изменяет текущую директорию на указанную директорию dir.

Если метод вызывается с блоком, восстанавливает предыдущую рабочую директорию после завершения выполнения блока.

FileUtils.cd('/', :verbose => true)   # chdir and report it

FileUtils.cd('/') do  # chdir
  # ...               # do something
end                   # return to original directory
Также известен как: chdir
chdir(dir, verbose: nil)
Псевдоним для: cd
chmod(mode, list, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 915
def chmod(mode, list, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
  return if noop
  list.each do |path|
    Entry_.new(path).chmod(fu_mode(mode, path))
  end
end

Изменяет биты разрешений указанных файлов (в list) на битовую комбинацию, представленную mode.

Доступны символьный и абсолютный режимы.

Абсолютный режим

FileUtils.chmod 0755, 'somecommand'
FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true

Символьный режим

FileUtils.chmod "u=wrx,go=rx", 'somecommand'
FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb)
FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', :verbose => true
“a”

маска для пользователя, группы и других.

“u”

маска для пользователя.

“g”

маска для группы.

“o”

маска для других.

“w”

разрешение на запись.

“r”

разрешение на чтение.

“x”

разрешение на выполнение.

“X”

разрешение на выполнение только для каталогов, должно использоваться в сочетании с “+”

“s”

uid, gid.

“t”

бит "sticky".

“+”

добавляется к классу, заданному указанным режимом.

“-”

удаляется из класса, заданного указанным режимом.

“=”

устанавливает точный класс с указанным режимом.

chmod_R(mode, list, noop: nil, verbose: nil, force: nil) Показать исходный код
# File lib/fileutils.rb, line 932
def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
  list = fu_list(list)
  fu_output_message sprintf('chmod -R%s %s %s',
                            (force ? 'f' : ''),
                            mode_to_s(mode), list.join(' ')) if verbose
  return if noop
  list.each do |root|
    Entry_.new(root).traverse do |ent|
      begin
        ent.chmod(fu_mode(mode, ent.path))
      rescue
        raise unless force
      end
    end
  end
end

Изменяет биты разрешений указанных файлов (в list) на битовую комбинацию, представленную mode.

FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
chown(user, group, list, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 960
def chown(user, group, list, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message sprintf('chown %s %s',
                            (group ? "#{user}:#{group}" : user || ':'),
                            list.join(' ')) if verbose
  return if noop
  uid = fu_get_uid(user)
  gid = fu_get_gid(group)
  list.each do |path|
    Entry_.new(path).chown uid, gid
  end
end

Изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group. user и group могут быть идентификаторами (целые числа/строки) или именами (строки). Если user или group равно nil, атрибут не изменяется.

FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
chown_R(user, group, list, noop: nil, verbose: nil, force: nil) Показать исходный код
# File lib/fileutils.rb, line 984
def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
  list = fu_list(list)
  fu_output_message sprintf('chown -R%s %s %s',
                            (force ? 'f' : ''),
                            (group ? "#{user}:#{group}" : user || ':'),
                            list.join(' ')) if verbose
  return if noop
  uid = fu_get_uid(user)
  gid = fu_get_gid(group)
  list.each do |root|
    Entry_.new(root).traverse do |ent|
      begin
        ent.chown uid, gid
      rescue
        raise unless force
      end
    end
  end
end

Рекурсивно изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group. user и group могут быть идентификаторами (целые числа/строки) или именами (строки). Если user или group равно nil, атрибут не изменяется.

FileUtils.chown_R 'www', 'www', '/var/www/htdocs'
FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
cmp(a, b)
Псевдоним для: compare_file
compare_file(a, b) Показать исходный код
# File lib/fileutils.rb, line 726
def compare_file(a, b)
  return false unless File.size(a) == File.size(b)
  File.open(a, 'rb') {|fa|
    File.open(b, 'rb') {|fb|
      return compare_stream(fa, fb)
    }
  }
end

Возвращает true, если содержимое файла a и файла b идентичны.

FileUtils.compare_file('somefile', 'somefile')       #=> true
FileUtils.compare_file('/dev/null', '/dev/urandom')  #=> false
Также известен как: identical?, cmp
compare_stream(a, b) Показать исходный код
# File lib/fileutils.rb, line 744
def compare_stream(a, b)
  bsize = fu_stream_blksize(a, b)
  sa = String.new(capacity: bsize)
  sb = String.new(capacity: bsize)
  begin
    a.read(bsize, sa)
    b.read(bsize, sb)
    return true if sa.empty? && sb.empty?
  end while sa == sb
  false
end

Возвращает true, если содержимое потока a и b идентичны.

copy(src, dest, preserve: nil, noop: nil, verbose: nil)
Псевдоним для: cp
copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) Показать исходный код
# File lib/fileutils.rb, line 413
def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
  Entry_.new(src, nil, dereference_root).wrap_traverse(proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
    ent.copy destent.path
  end, proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    ent.copy_metadata destent.path if preserve
  end)
end

Копирует системную запись src в dest. Если src - это каталог, метод копирует его содержимое рекурсивно. Метод сохраняет типы файлов, например, ссылки, каталоги… (FIFO, файлы устройств и т. д. пока не поддерживаются)

И src, и dest должны быть именами путей. src должен существовать, dest не должен существовать.

Если preserve равно true, метод сохраняет владельца, группу и время последнего изменения. Разрешения копируются независимо от preserve.

Если dereference_root равно true, метод дереференцирует корень дерева.

Если remove_destination равно true, метод удаляет каждый целевой файл перед копированием.

copy_file(src, dest, preserve = false, dereference = true) Показать исходный код
# File lib/fileutils.rb, line 429
def copy_file(src, dest, preserve = false, dereference = true)
  ent = Entry_.new(src, nil, dereference)
  ent.copy_file dest
  ent.copy_metadata dest if preserve
end

Копирует содержимое файла src в dest. И src, и dest должны быть именами путей.

copy_stream(src, dest) Показать исходный код
# File lib/fileutils.rb, line 441
def copy_stream(src, dest)
  IO.copy_stream(src, dest)
end

Копирует поток src в dest Поток src должен поддерживать чтение (read(n)), а поток dest - запись (write(str)).

cp(src, dest, preserve: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 354
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
  fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_file s, d, preserve
  end
end

Копирует содержимое файла src в dest. Если dest - каталог, копирует src в dest/src.

Если src - список файлов, то dest должен быть каталогом.

FileUtils.cp 'eval.c', 'eval.c.org'
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true
FileUtils.cp 'symlink', 'dest'   # copy content, "dest" is not a symlink
Также известен как: copy
cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil) Показать исходный код
# File lib/fileutils.rb, line 387
def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
         dereference_root: true, remove_destination: nil)
  fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_entry s, d, preserve, dereference_root, remove_destination
  end
end

Копирует src в dest. Если src - каталог, метод копирует все его содержимое рекурсивно. Если dest - каталог, копирует src в dest/src.

src может быть списком файлов.

# Installing Ruby library "mylib" under the site_ruby
FileUtils.rm_r site_ruby + '/mylib', :force
FileUtils.cp_r 'lib/', site_ruby + '/mylib'

# Examples of copying several files to target directory.
FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', :noop => true, :verbose => true

# If you want to copy all contents of a directory instead of the
# directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
# use following code.
FileUtils.cp_r 'src/.', 'dest'     # cp_r('src', 'dest') makes dest/src,
                                   # but this doesn't.
getwd()
Псевдоним для: pwd
identical?(a, b)
Псевдоним для: compare_file
install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 765
def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
            noop: nil, verbose: nil)
  if verbose
    msg = +"install -c"
    msg << ' -p' if preserve
    msg << ' -m ' << mode_to_s(mode) if mode
    msg << " -o #{owner}" if owner
    msg << " -g #{group}" if group
    msg << ' ' << [src,dest].flatten.join(' ')
    fu_output_message msg
  end
  return if noop
  uid = fu_get_uid(owner)
  gid = fu_get_gid(group)
  fu_each_src_dest(src, dest) do |s, d|
    st = File.stat(s)
    unless File.exist?(d) and compare_file(s, d)
      remove_file d, true
      copy_file s, d
      File.utime st.atime, st.mtime, d if preserve
      File.chmod fu_mode(mode, st), d if mode
      File.chown uid, gid, d if uid or gid
    end
  end
end

Если src не совпадает с dest, копирует его и изменяет режим разрешений на mode. Если dest - каталог, назначения dest/src . Метод удаляет назначение перед копированием.

FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true
FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true
link(src, dest, force: nil, noop: nil, verbose: nil)
Псевдоним для: ln
ln(target, link, force: nil, noop: nil, verbose: nil) Показать исходный код
ln(target, dir, force: nil, noop: nil, verbose: nil)
ln(targets, dir, force: nil, noop: nil, verbose: nil)
# File lib/fileutils.rb, line 284
def ln(src, dest, force: nil, noop: nil, verbose: nil)
  fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest0(src, dest) do |s,d|
    remove_file d, true if force
    File.link s, d
  end
end

В первом варианте создаёт жёсткую ссылку link, которая указывает на target. Если link уже существует, генерируется исключение Errno::EEXIST. Но если задан параметр :force, link перезаписывается.

FileUtils.ln 'gcc', 'cc', verbose: true
FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'

Во втором варианте создаёт ссылку dir/target , указывающую на target. В третьем варианте создаёт несколько жёстких ссылок в каталоге dir, указывающих на каждый элемент в targets. Если dir не является каталогом, генерируется исключение Errno::ENOTDIR.

FileUtils.cd '/sbin'
FileUtils.ln %w(cp mv mkdir), '/bin'   # Now /sbin/cp and /bin/cp are linked.
Также используется как: link
ln_s(target, link, force: nil, noop: nil, verbose: nil) Показать исходный код
ln_s(target, dir, force: nil, noop: nil, verbose: nil)
ln_s(targets, dir, force: nil, noop: nil, verbose: nil)
# File lib/fileutils.rb, line 317
def ln_s(src, dest, force: nil, noop: nil, verbose: nil)
  fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest0(src, dest) do |s,d|
    remove_file d, true if force
    File.symlink s, d
  end
end

В первом варианте создаёт символическую ссылку link, которая указывает на target. Если link уже существует, генерируется исключение Errno::EEXIST. Но если задан параметр :force, link перезаписывается.

FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true

Во втором варианте создаёт ссылку dir/target , указывающую на target. В третьем варианте создаёт несколько символических ссылок в каталоге dir, указывающих на каждый элемент в targets. Если dir не является каталогом, генерируется исключение Errno::ENOTDIR.

FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin'
Также используется как: symlink
ln_sf(*args) Показать исходный код
# File lib/fileutils.rb, line 338
def ln_sf(src, dest, noop: nil, verbose: nil)
  ln_s src, dest, force: true, noop: noop, verbose: verbose
end

То же самое, что и

FileUtils.ln_s(*args, force: true)
makedirs(list, mode: nil, noop: nil, verbose: nil)
Псевдоним для: mkdir_p
mkdir(list, mode: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 161
def mkdir(list, mode: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
  return if noop

  list.each do |dir|
    fu_mkdir dir, mode
  end
end

Создаёт один или несколько каталогов.

FileUtils.mkdir 'test'
FileUtils.mkdir %w( tmp data )
FileUtils.mkdir 'notexist', :noop => true  # Does not really create.
FileUtils.mkdir 'tmp', :mode => 0700
mkdir_p(list, mode: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 187
def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
  return *list if noop

  list.map {|path| remove_trailing_slash(path)}.each do |path|
    # optimize for the most common case
    begin
      fu_mkdir path, mode
      next
    rescue SystemCallError
      next if File.directory?(path)
    end

    stack = []
    until path == stack.last   # dirname("/")=="/", dirname("C:/")=="C:/"
      stack.push path
      path = File.dirname(path)
    end
    stack.pop                 # root directory should exist
    stack.reverse_each do |dir|
      begin
        fu_mkdir dir, mode
      rescue SystemCallError
        raise unless File.directory?(dir)
      end
    end
  end

  return *list
end

Создаёт каталог и все его родительские каталоги. Например,

FileUtils.mkdir_p '/usr/local/lib/ruby'

приводит к созданию следующих каталогов, если они не существуют.

  • /usr

  • /usr/local

  • /usr/local/lib

  • /usr/local/lib/ruby

Вы можете передать несколько каталогов одновременно в списке.

Также используется как: mkpath, makedirs
mkpath(list, mode: nil, noop: nil, verbose: nil)
Псевдоним для: mkdir_p
move(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
Псевдоним для: mv
mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) Показать исходный код
# File lib/fileutils.rb, line 456
def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
  fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    destent = Entry_.new(d, nil, true)
    begin
      if destent.exist?
        if destent.directory?
          raise Errno::EEXIST, d
        else
          destent.remove_file if rename_cannot_overwrite_file?
        end
      end
      begin
        File.rename s, d
      rescue Errno::EXDEV
        copy_entry s, d, true
        if secure
          remove_entry_secure s, force
        else
          remove_entry s, force
        end
      end
    rescue SystemCallError
      raise unless force
    end
  end
end

Перемещает файл(ы) src в dest. Если file и dest находятся на разных разделах диска, файл копируется, а затем удаляется исходный файл.

FileUtils.mv 'badname.rb', 'goodname.rb'
FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', :force => true  # no error

FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/'
FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
Также используется как: move
pwd() Показать исходный код
# File lib/fileutils.rb, line 99
def pwd
  Dir.pwd
end

Возвращает имя текущего каталога.

Также используется как: getwd
remove(list, force: nil, noop: nil, verbose: nil)
Псевдоним для: rm
remove_dir(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 715
def remove_dir(path, force = false)
  remove_entry path, force   # FIXME?? check if it is a directory
end

Удаляет каталог dir и его содержимое рекурсивно. Этот метод игнорирует StandardError, если force равно true.

remove_entry(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 687
def remove_entry(path, force = false)
  Entry_.new(path).postorder_traverse do |ent|
    begin
      ent.remove
    rescue
      raise unless force
    end
  end
rescue
  raise unless force
end

Этот метод удаляет системный элемент path. path может быть обычным файлом, каталогом или чем-то другим. Если path является каталогом, удаляет его рекурсивно.

См. также remove_entry_secure.

remove_entry_secure(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 610
def remove_entry_secure(path, force = false)
  unless fu_have_symlink?
    remove_entry path, force
    return
  end
  fullpath = File.expand_path(path)
  st = File.lstat(fullpath)
  unless st.directory?
    File.unlink fullpath
    return
  end
  # is a directory.
  parent_st = File.stat(File.dirname(fullpath))
  unless parent_st.world_writable?
    remove_entry path, force
    return
  end
  unless parent_st.sticky?
    raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
  end
  # freeze tree root
  euid = Process.euid
  File.open(fullpath + '/.') {|f|
    unless fu_stat_identical_entry?(st, f.stat)
      # symlink (TOC-to-TOU attack?)
      File.unlink fullpath
      return
    end
    f.chown euid, -1
    f.chmod 0700
    unless fu_stat_identical_entry?(st, File.lstat(fullpath))
      # TOC-to-TOU attack?
      File.unlink fullpath
      return
    end
  }
  # ---- tree root is frozen ----
  root = Entry_.new(path)
  root.preorder_traverse do |ent|
    if ent.directory?
      ent.chown euid, -1
      ent.chmod 0700
    end
  end
  root.postorder_traverse do |ent|
    begin
      ent.remove
    rescue
      raise unless force
    end
  end
rescue
  raise unless force
end

Этот метод удаляет системный элемент path. path должен быть обычным файлом, каталогом или чем-то другим. Если path является каталогом, удаляет его рекурсивно. Этот метод необходим для предотвращения уязвимости TOCTTOU (проверка времени - время использования) локальной безопасности метода rm_r. rm_r создаёт уязвимость безопасности, когда:

  • Родительский каталог имеет разрешения на запись для всех (включая /tmp).

  • Удаление дерева каталогов включает каталог с разрешениями на запись для всех.

  • В системе есть символическая ссылка.

Чтобы избежать этой уязвимости, этот метод применяет специальную предобработку. Если path является каталогом, этот метод устанавливает права доступа chown(2) и chmod(2) для всех удаляемых каталогов. Это требует, чтобы текущий процесс был владельцем всего удаляемого дерева каталогов или имел права суперпользователя (root).

ПРЕДУПРЕЖДЕНИЕ: Вы должны убедиться, что ВСЕ родительские каталоги не могут быть изменены другими неуверенными пользователями. Например, родительские каталоги не должны принадлежать неуверенным пользователям и не должны иметь разрешения на запись для всех, за исключением случаев, когда установлен бит «вклейки».

ПРЕДУПРЕЖДЕНИЕ: Только владелец удаляемого дерева каталогов или суперпользователь Unix (root) должен вызывать этот метод. В противном случае этот метод не работает.

Для получения подробностей об этой уязвимости см. примеры в Perl:

  • www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448

  • www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452

Для fileutils.rb эта уязвимость была сообщена в [ruby-dev:26100].

remove_file(path, force = false) Показать исходный код
# File lib/fileutils.rb, line 704
def remove_file(path, force = false)
  Entry_.new(path).remove_file
rescue
  raise unless force
end

Удаляет файл path. Этот метод игнорирует StandardError, если force равно true.

rm(list, force: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 502
def rm(list, force: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose
  return if noop

  list.each do |path|
    remove_file path, force
  end
end

Удаляет файлы, указанные в list. Этот метод не может удалять каталоги. Все StandardErrors игнорируются, когда задан параметр :force.

FileUtils.rm %w( junk.txt dust.txt )
FileUtils.rm Dir.glob('*.so')
FileUtils.rm 'NotExistFile', :force => true   # never raises exception
Также используется как: remove
rm_f(list, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 521
def rm_f(list, noop: nil, verbose: nil)
  rm list, force: true, noop: noop, verbose: verbose
end

Эквивалентно

FileUtils.rm(list, :force => true)
Также алиасируется как: safe_unlink
rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) Показать исходный код
# File lib/fileutils.rb, line 548
def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
  list = fu_list(list)
  fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose
  return if noop
  list.each do |path|
    if secure
      remove_entry_secure path, force
    else
      remove_entry path, force
    end
  end
end

Удаляет файлы list[0] list[1]… Если list[n] является каталогом, удаляет все его содержимое рекурсивно. Этот метод игнорирует StandardError, когда установлен параметр :force.

FileUtils.rm_r Dir.glob('/tmp/*')
FileUtils.rm_r 'some_dir', :force => true

ПРЕДУПРЕЖДЕНИЕ: Этот метод может привести к уязвимости локальной системы, если один из родительских каталогов или удаляемая структура каталогов имеют права записи для всех (включая /tmp, разрешения которого составляют 1777), и текущий процесс обладает расширенными привилегиями, такими как права суперпользователя (root), а в системе присутствуют символические ссылки. Для безопасного удаления внимательно ознакомьтесь с документацией remove_entry_secure и установите параметр :secure в значение true. По умолчанию :secure=>false.

ПРИМЕЧАНИЕ: Этот метод вызывает remove_entry_secure, если параметр :secure установлен. Смотрите также remove_entry_secure.

rm_rf(list, noop: nil, verbose: nil, secure: nil) Показать исходный код
# File lib/fileutils.rb, line 570
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
  rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
end

Эквивалентно

FileUtils.rm_r(list, :force => true)

ПРЕДУПРЕЖДЕНИЕ: Этот метод может привести к уязвимости локальной системы. Сначала ознакомьтесь с документацией rm_r.

Также алиасируется как: rmtree
rmdir(list, parents: nil, noop: nil, verbose: nil) Показать исходный код
# File lib/fileutils.rb, line 244
def rmdir(list, parents: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
  return if noop
  list.each do |dir|
    Dir.rmdir(dir = remove_trailing_slash(dir))
    if parents
      begin
        until (parent = File.dirname(dir)) == '.' or parent == dir
          dir = parent
          Dir.rmdir(dir)
        end
      rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
      end
    end
  end
end

Удаляет один или несколько каталогов.

FileUtils.rmdir 'somedir'
FileUtils.rmdir %w(somedir anydir otherdir)
# Does not really remove directory; outputs message.
FileUtils.rmdir 'somedir', :verbose => true, :noop => true
rmtree(list, noop: nil, verbose: nil, secure: nil)
Псевдоним для: rm_rf
safe_unlink(list, noop: nil, verbose: nil)
Псевдоним для: rm_f
symlink(src, dest, force: nil, noop: nil, verbose: nil)
Псевдоним для: ln_s
touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) Показать исходный код
# File lib/fileutils.rb, line 1043
def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
  list = fu_list(list)
  t = mtime
  if verbose
    fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
  end
  return if noop
  list.each do |path|
    created = nocreate
    begin
      File.utime(t, t, path)
    rescue Errno::ENOENT
      raise if created
      File.open(path, 'a') {
        ;
      }
      created = true
      retry if t
    end
  end
end

Обновляет время изменения (mtime) и время доступа (atime) файла(ов) в list. Файлы создаются, если они не существуют.

FileUtils.touch 'timestamp'
FileUtils.touch Dir.glob('*.c');  system 'make'
uptodate?(new, old_list) Показать исходный код
# File lib/fileutils.rb, line 136
def uptodate?(new, old_list)
  return false unless File.exist?(new)
  new_time = File.mtime(new)
  old_list.each do |old|
    if File.exist?(old)
      return false unless new_time > File.mtime(old)
    end
  end
  true
end

Возвращает true, если new новее всех old_list. Несуществующие файлы считаются старше любого файла.

FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
    system 'make hello.o'

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API