модуль FileUtils
frozen_string_literal: false
fileutils.rb
Авторское право © 2000-2007 Minero Aoki
Эта программа является свободным программным обеспечением. Вы можете распространять/изменять эту программу на тех же условиях, что и рубин.
модуль FileUtils
Пространство имен для нескольких методов работы с файлами для копирования, перемещения, удаления и т.д.
Модуль Функции
require 'fileutils'
FileUtils.cd(dir, options)
FileUtils.cd(dir, options) {|dir| .... }
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(old, new, options)
FileUtils.ln(list, destdir, options)
FileUtils.ln_s(old, new, options)
FileUtils.ln_s(list, destdir, options)
FileUtils.ln_sf(src, dest, 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, mode = <src's>, 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
Методы публичного класса
# File lib/fileutils.rb, line 125
def cd(dir, options = {}, &block) # :yield: dir
fu_check_options options, OPT_TABLE['cd']
fu_output_message "cd #{dir}" if options[:verbose]
Dir.chdir(dir, &block)
fu_output_message 'cd -' if options[:verbose] and block
end Параметры: verbose
Изменяет текущий каталог на каталог dir.
Если этот метод вызывается с блоком, он возвращается к старому рабочему каталогу после завершения выполнения блока.
FileUtils.cd('/', :verbose => true) # chdir and report it
FileUtils.cd('/') do # chdir
[...] # do something
end # return to original directory # File lib/fileutils.rb, line 995
def chmod(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod']
list = fu_list(list)
fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if options[:verbose]
return if options[:noop]
list.each do |path|
Entry_.new(path).chmod(fu_mode(mode, path))
end
end Параметры: noop verbose
Изменяет биты разрешений указанных файлов (в 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”
-
— бит «липкий».
- “+”
-
— добавляется к классу, заданному указанным режимом.
- “-”
-
— удаляется из заданного класса, заданного режимом.
- “=”
-
— точное значение класса будет задано указанным режимом.
# File lib/fileutils.rb, line 1017
def chmod_R(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod_R']
list = fu_list(list)
fu_output_message sprintf('chmod -R%s %s %s',
(options[:force] ? 'f' : ''),
mode_to_s(mode), list.join(' ')) if options[:verbose]
return if options[:noop]
list.each do |root|
Entry_.new(root).traverse do |ent|
begin
ent.chmod(fu_mode(mode, ent.path))
rescue
raise unless options[:force]
end
end
end
end Параметры: noop verbose force
Изменяет биты разрешений указанных файлов (в list) на битовую комбинацию, представленную значением mode.
FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
# File lib/fileutils.rb, line 1050
def chown(user, group, list, options = {})
fu_check_options options, OPT_TABLE['chown']
list = fu_list(list)
fu_output_message sprintf('chown %s %s',
(group ? "#{user}:#{group}" : user || ':'),
list.join(' ')) if options[:verbose]
return if options[:noop]
uid = fu_get_uid(user)
gid = fu_get_gid(group)
list.each do |path|
Entry_.new(path).chown uid, gid
end
end Параметры: noop verbose
Изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group. user и group могут быть идентификатором (целое число/строка) или именем (строка). Если user или group равно null, этот метод не изменяет атрибут.
FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
# File lib/fileutils.rb, line 1079
def chown_R(user, group, list, options = {})
fu_check_options options, OPT_TABLE['chown_R']
list = fu_list(list)
fu_output_message sprintf('chown -R%s %s %s',
(options[:force] ? 'f' : ''),
(group ? "#{user}:#{group}" : user || ':'),
list.join(' ')) if options[:verbose]
return if options[: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 options[:force]
end
end
end
end Параметры: noop verbose force
Рекурсивно изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group. user и group могут быть идентификатором (целое число/строка) или именем (строка). Если user или group равно null, этот метод не изменяет атрибут.
FileUtils.chown_R 'www', 'www', '/var/www/htdocs' FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
# File lib/fileutils.rb, line 816
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('/bin/cp', '/bin/mv') #=> maybe false
# File lib/fileutils.rb, line 834
def compare_stream(a, b)
bsize = fu_stream_blksize(a, b)
sa = ""
sb = ""
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 идентичны.
# File lib/fileutils.rb, line 469
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)
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, этот метод удаляет каждый целевой файл перед копированием.
# File lib/fileutils.rb, line 485 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 должны быть именами путей.
# File lib/fileutils.rb, line 497 def copy_stream(src, dest) IO.copy_stream(src, dest) end
Копирует поток src в dest. src должен поддерживать чтение (n), а dest — запись (str).
# File lib/fileutils.rb, line 399
def cp(src, dest, options = {})
fu_check_options options, OPT_TABLE['cp']
fu_output_message "cp#{options[:preserve] ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest(src, dest) do |s, d|
copy_file s, d, options[:preserve]
end
end Параметры: preserve noop verbose
Копирует содержимое файла 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
# File lib/fileutils.rb, line 438
def cp_r(src, dest, options = {})
fu_check_options options, OPT_TABLE['cp_r']
fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
options = options.dup
options[:dereference_root] = true unless options.key?(:dereference_root)
fu_each_src_dest(src, dest) do |s, d|
copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination]
end
end Параметры: preserve noop verbose dereference_root remove_destination
Копирует 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/aamine/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.
# File lib/fileutils.rb, line 857
def install(src, dest, options = {})
fu_check_options options, OPT_TABLE['install']
fu_output_message "install -c#{options[:preserve] && ' -p'}#{options[:mode] ? (' -m 0%o' % options[:mode]) : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
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 options[:preserve]
File.chmod options[:mode], d if options[:mode]
end
end
end Параметры: mode preserve noop verbose
Если 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
# File lib/fileutils.rb, line 314
def ln(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln']
fu_output_message "ln#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
remove_file d, true if options[:force]
File.link s, d
end
end Параметры: force noop verbose
ln(old, new, options = {})
Создаёт жёсткую ссылку new которая указывает на old. Если new уже существует и это каталог, создаёт ссылку new/old. Если new уже существует и это не каталог, генерирует исключение Errno::EEXIST. Но если установлен параметр :force, перезаписывает new.
FileUtils.ln 'gcc', 'cc', :verbose => true FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
ln(list, destdir, options = {})
Создаёт несколько жёстких ссылок в каталоге, каждая из которых указывает на элемент в list. Если destdir не является каталогом, генерируется исключение Errno::ENOTDIR.
include FileUtils cd '/sbin' FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
# File lib/fileutils.rb, line 353
def ln_s(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_s']
fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
remove_file d, true if options[:force]
File.symlink s, d
end
end Параметры: force noop verbose
ln_s(old, new, options = {})
Создаёт символическую ссылку new которая указывает на old. Если new уже существует и это каталог, создаёт символическую ссылку new/old. Если new уже существует и это не каталог, генерируется исключение Errno::EEXIST. Но если установлен параметр :force, перезаписывает new.
FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby' FileUtils.ln_s 'verylongsourcefilename.c', 'c', :force => true
ln_s(list, destdir, options = {})
Создаёт несколько символических ссылок в каталоге, каждая из которых указывает на элемент в list. Если destdir не является каталогом, генерируется исключение Errno::ENOTDIR.
Если destdir не является каталогом, генерируется исключение Errno::ENOTDIR.
FileUtils.ln_s Dir.glob('bin/*.rb'), '/home/aamine/bin'
# File lib/fileutils.rb, line 376
def ln_sf(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_sf']
options = options.dup
options[:force] = true
ln_s src, dest, options
end Параметры: noop verbose
То же, что и
#ln_s(src, dest, :force => true)
# File lib/fileutils.rb, line 175
def mkdir(list, options = {})
fu_check_options options, OPT_TABLE['mkdir']
list = fu_list(list)
fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |dir|
fu_mkdir dir, options[:mode]
end
end Параметры: mode noop verbose
Создаёт один или несколько каталогов.
FileUtils.mkdir 'test' FileUtils.mkdir %w( tmp data ) FileUtils.mkdir 'notexist', :noop => true # Does not really create. FileUtils.mkdir 'tmp', :mode => 0700
# File lib/fileutils.rb, line 205
def mkdir_p(list, options = {})
fu_check_options options, OPT_TABLE['mkdir_p']
list = fu_list(list)
fu_output_message "mkdir -p #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return *list if options[:noop]
list.map {|path| remove_trailing_slash(path)}.each do |path|
# optimize for the most common case
begin
fu_mkdir path, options[: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, options[:mode]
rescue SystemCallError
raise unless File.directory?(dir)
end
end
end
return *list
end Параметры: mode noop verbose
Создаёт каталог и все его родительские каталоги. Например,
FileUtils.mkdir_p '/usr/local/lib/ruby'
приводит к созданию следующих каталогов, если они не существуют.
* /usr * /usr/local * /usr/local/lib * /usr/local/lib/ruby
Вы можете передать несколько каталогов одновременно в списке.
# File lib/fileutils.rb, line 514
def mv(src, dest, options = {})
fu_check_options options, OPT_TABLE['mv']
fu_output_message "mv#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[: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 options[:secure]
remove_entry_secure s, options[:force]
else
remove_entry s, options[:force]
end
end
rescue SystemCallError
raise unless options[:force]
end
end
end Параметры: force noop verbose
Перемещает файл(ы) 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/aamine/.trash/'
FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
# File lib/fileutils.rb, line 103 def pwd Dir.pwd end
Параметры: (нет)
Возвращает имя текущего каталога.
# File lib/fileutils.rb, line 805 def remove_dir(path, force = false) remove_entry path, force # FIXME?? check if it is a directory end
Удаляет каталог dir и его содержимое рекурсивно. Этот метод игнорирует StandardError, если force равно true.
# File lib/fileutils.rb, line 777
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.
# File lib/fileutils.rb, line 700
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 создаёт уязвимость, когда:
* Parent directory is world writable (including /tmp). * Removing directory tree includes world writable directory. * The system has symbolic link.
Чтобы избежать этой уязвимости, этот метод применяет специальную предподготовку. Если path является каталогом, этот метод использует chown(2) и chmod(2) для всех удаляемых каталогов. Это требует, чтобы текущий процесс был владельцем удаляемой цепочки каталогов или имел права суперпользователя (root).
ПРЕДУПРЕЖДЕНИЕ: Вы должны убедиться, что ВСЕ родительские каталоги не могут быть перемещены другими неуправляемыми пользователями. Например, родительские каталоги не должны принадлежать неуправляемым пользователям и не должны быть доступны для записи всем, кроме случаев установки бита "sticky".
ПРЕДУПРЕЖДЕНИЕ: Только владелец удаляемой цепочки каталогов или системный пользователь Unix (root) должны вызывать этот метод. В противном случае этот метод не сработает.
Для подробностей об этой уязвимости безопасности см. пример в Perl:
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452
Для fileutils.rb эта уязвимость описана в [ruby-dev:26100].
# File lib/fileutils.rb, line 794 def remove_file(path, force = false) Entry_.new(path).remove_file rescue raise unless force end
Удаляет файл path. Этот метод игнорирует StandardError, если force равно true.
# File lib/fileutils.rb, line 566
def rm(list, options = {})
fu_check_options options, OPT_TABLE['rm']
list = fu_list(list)
fu_output_message "rm#{options[:force] ? ' -f' : ''} #{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |path|
remove_file path, options[:force]
end
end Параметры: force noop verbose
Удаляет файлы, указанные в list. Этот метод не может удалять каталоги. Все StandardError игнорируются, когда установлен параметр :force.
FileUtils.rm %w( junk.txt dust.txt )
FileUtils.rm Dir.glob('*.so')
FileUtils.rm 'NotExistFile', :force => true # never raises exception
# File lib/fileutils.rb, line 591
def rm_f(list, options = {})
fu_check_options options, OPT_TABLE['rm_f']
options = options.dup
options[:force] = true
rm list, options
end Параметры: noop verbose
Эквивалентно
#rm(list, :force => true)
# File lib/fileutils.rb, line 626
def rm_r(list, options = {})
fu_check_options options, OPT_TABLE['rm_r']
# options[:secure] = true unless options.key?(:secure)
list = fu_list(list)
fu_output_message "rm -r#{options[:force] ? 'f' : ''} #{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |path|
if options[:secure]
remove_entry_secure path, options[:force]
else
remove_entry path, options[:force]
end
end
end Параметры: force noop verbose secure
Удаляет файлы list[0] list[1]… Если list[n] является каталогом, удаляет все его содержимое рекурсивно. Этот метод игнорирует StandardError при установке опции :force.
FileUtils.rm_r Dir.glob('/tmp/*')
FileUtils.rm_r '/', :force => true # :-)
ПРЕДУПРЕЖДЕНИЕ: Этот метод может привести к локальной уязвимости, если один из родительских каталогов или удаляемая древовидная структура каталогов имеют права доступа для всех пользователей (включая /tmp, чьи права доступа составляют 1777), а текущий процесс обладает сильными привилегиями, такими как права суперпользователя Unix (root), а система имеет символические ссылки. Для безопасного удаления внимательно прочитайте документацию по remove_entry_secure и установите опцию :secure в значение true. По умолчанию :secure=>false.
ПРИМЕЧАНИЕ: Этот метод вызывает remove_entry_secure, если опция :secure установлена. См. также remove_entry_secure.
# File lib/fileutils.rb, line 654
def rm_rf(list, options = {})
fu_check_options options, OPT_TABLE['rm_rf']
options = options.dup
options[:force] = true
rm_r list, options
end Параметры: noop verbose secure
Эквивалентно
#rm_r(list, :force => true)
ПРЕДУПРЕЖДЕНИЕ: Этот метод может привести к локальной уязвимости. Сначала ознакомьтесь с документацией по rm_r.
# File lib/fileutils.rb, line 269
def rmdir(list, options = {})
fu_check_options options, OPT_TABLE['rmdir']
list = fu_list(list)
parents = options[:parents]
fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |dir|
begin
Dir.rmdir(dir = remove_trailing_slash(dir))
if parents
until (parent = File.dirname(dir)) == '.' or parent == dir
dir = parent
Dir.rmdir(dir)
end
end
rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
end
end
end Параметры: parents, noop, verbose
Удаляет один или несколько каталогов.
FileUtils.rmdir 'somedir' FileUtils.rmdir %w(somedir anydir otherdir) # Does not really remove directory; outputs message. FileUtils.rmdir 'somedir', :verbose => true, :noop => true
# File lib/fileutils.rb, line 1143
def touch(list, options = {})
fu_check_options options, OPT_TABLE['touch']
list = fu_list(list)
nocreate = options[:nocreate]
t = options[:mtime]
if options[:verbose]
fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
end
return if options[: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 Параметры: noop verbose mtime nocreate
Обновляет время изменения (mtime) и время доступа (atime) файла(ов) в list. Файлы создаются, если они не существуют.
FileUtils.touch 'timestamp'
FileUtils.touch Dir.glob('*.c'); system 'make'
# File lib/fileutils.rb, line 148
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'
Методы закрытого класса
# File lib/fileutils.rb, line 1672
def FileUtils.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"]
# File lib/fileutils.rb, line 1633 def FileUtils.commands OPT_TABLE.keys end
Возвращает массив имён методов, которые имеют какие-либо опции.
p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
# File lib/fileutils.rb, line 1653
def FileUtils.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
# File lib/fileutils.rb, line 1642
def FileUtils.options
OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
end Возвращает массив имён опций.
p FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
# File lib/fileutils.rb, line 1663
def FileUtils.options_of(mid)
OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
end Возвращает массив имён опций метода mid.
p FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"]
Методы открытого экземпляра
# File lib/fileutils.rb, line 893
def apply_mask(mode, user_mask, op, mode_mask)
case op
when '='
(mode & ~user_mask) | (user_mask & mode_mask)
when '+'
mode | (user_mask & mode_mask)
when '-'
mode & ~(user_mask & mode_mask)
end
end # File lib/fileutils.rb, line 160 def remove_trailing_slash(dir) dir == '/' ? dir : dir.chomp(?/) end
Методы частного экземпляра
# File lib/fileutils.rb, line 125
def cd(dir, options = {}, &block) # :yield: dir
fu_check_options options, OPT_TABLE['cd']
fu_output_message "cd #{dir}" if options[:verbose]
Dir.chdir(dir, &block)
fu_output_message 'cd -' if options[:verbose] and block
end Параметры: verbose
Изменяет текущий каталог на каталог dir.
Если этот метод вызывается с блоком, он возвращается к старому рабочему каталогу после завершения выполнения блока.
FileUtils.cd('/', :verbose => true) # chdir and report it
FileUtils.cd('/') do # chdir
[...] # do something
end # return to original directory # File lib/fileutils.rb, line 995
def chmod(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod']
list = fu_list(list)
fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if options[:verbose]
return if options[:noop]
list.each do |path|
Entry_.new(path).chmod(fu_mode(mode, path))
end
end Параметры: noop verbose
Изменяет биты разрешений для указанных файлов (в 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».
- “+”
-
добавляется к классу с указанным режимом.
- “-”
-
удаляется из заданного класса с указанным режимом.
- “=”
-
устанавливается точный тип класса с указанным режимом.
# File lib/fileutils.rb, line 1017
def chmod_R(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod_R']
list = fu_list(list)
fu_output_message sprintf('chmod -R%s %s %s',
(options[:force] ? 'f' : ''),
mode_to_s(mode), list.join(' ')) if options[:verbose]
return if options[:noop]
list.each do |root|
Entry_.new(root).traverse do |ent|
begin
ent.chmod(fu_mode(mode, ent.path))
rescue
raise unless options[:force]
end
end
end
end Параметры: noop verbose force
Изменяет биты разрешений для указанных файлов (в list) на битовую модель, представленную mode.
FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
# File lib/fileutils.rb, line 1050
def chown(user, group, list, options = {})
fu_check_options options, OPT_TABLE['chown']
list = fu_list(list)
fu_output_message sprintf('chown %s %s',
(group ? "#{user}:#{group}" : user || ':'),
list.join(' ')) if options[:verbose]
return if options[:noop]
uid = fu_get_uid(user)
gid = fu_get_gid(group)
list.each do |path|
Entry_.new(path).chown uid, gid
end
end Параметры: noop verbose
Изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group.
user и group могут быть идентификатором (целое число/строка) или именем (строка). Если user или group равно null, этот метод не изменяет атрибут.
FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
# File lib/fileutils.rb, line 1079
def chown_R(user, group, list, options = {})
fu_check_options options, OPT_TABLE['chown_R']
list = fu_list(list)
fu_output_message sprintf('chown -R%s %s %s',
(options[:force] ? 'f' : ''),
(group ? "#{user}:#{group}" : user || ':'),
list.join(' ')) if options[:verbose]
return if options[: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 options[:force]
end
end
end
end Параметры: noop verbose force
Рекурсивно изменяет владельца и группу указанных файлов (в list) на пользователя user и группу group. user и group могут быть идентификатором (целое число/строка) или именем (строка). Если user или group равно null, этот метод не изменяет атрибут.
FileUtils.chown_R 'www', 'www', '/var/www/htdocs' FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
# File lib/fileutils.rb, line 816
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('/bin/cp', '/bin/mv') #=> maybe false
# File lib/fileutils.rb, line 834
def compare_stream(a, b)
bsize = fu_stream_blksize(a, b)
sa = ""
sb = ""
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 идентичны.
# File lib/fileutils.rb, line 469
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)
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, этот метод удаляет каждый целевой файл перед копированием.
# File lib/fileutils.rb, line 485 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 должны быть именами путей.
# File lib/fileutils.rb, line 497 def copy_stream(src, dest) IO.copy_stream(src, dest) end
Копирует поток src в dest.
src должен отвечать на чтение (read(n)), а dest — на запись (write(str)).
# File lib/fileutils.rb, line 399
def cp(src, dest, options = {})
fu_check_options options, OPT_TABLE['cp']
fu_output_message "cp#{options[:preserve] ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest(src, dest) do |s, d|
copy_file s, d, options[:preserve]
end
end Параметры: preserve noop verbose
Копирует содержимое файла 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
# File lib/fileutils.rb, line 438
def cp_r(src, dest, options = {})
fu_check_options options, OPT_TABLE['cp_r']
fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
options = options.dup
options[:dereference_root] = true unless options.key?(:dereference_root)
fu_each_src_dest(src, dest) do |s, d|
copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination]
end
end Параметры: preserve noop verbose dereference_root remove_destination
Копирует 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/aamine/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.
# File lib/fileutils.rb, line 857
def install(src, dest, options = {})
fu_check_options options, OPT_TABLE['install']
fu_output_message "install -c#{options[:preserve] && ' -p'}#{options[:mode] ? (' -m 0%o' % options[:mode]) : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
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 options[:preserve]
File.chmod options[:mode], d if options[:mode]
end
end
end Параметры: mode preserve noop verbose
Если 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
# File lib/fileutils.rb, line 314
def ln(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln']
fu_output_message "ln#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
remove_file d, true if options[:force]
File.link s, d
end
end Параметры: force noop verbose
ln(old, new, options = {})
Создаёт жёсткую ссылку new , которая указывает на old. Если new уже существует и это каталог, создаёт ссылку new/old. Если new уже существует и это не каталог, генерирует исключение Errno::EEXIST. Но если установлен параметр :force, перезаписывает new.
FileUtils.ln 'gcc', 'cc', :verbose => true FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
ln(list, destdir, options = {})
Создаёт несколько жёстких ссылок в каталоге, каждая из которых указывает на элемент в list. Если destdir не является каталогом, генерирует исключение Errno::ENOTDIR.
include FileUtils cd '/sbin' FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
# File lib/fileutils.rb, line 353
def ln_s(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_s']
fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
remove_file d, true if options[:force]
File.symlink s, d
end
end Параметры: force noop verbose
ln_s(old, new, options = {})
Создаёт символическую ссылку new , которая указывает на old. Если new уже существует и это каталог, создаёт символическую ссылку new/old. Если new уже существует и это не каталог, генерирует исключение Errno::EEXIST. Но если установлен параметр :force, перезаписывает new.
FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby' FileUtils.ln_s 'verylongsourcefilename.c', 'c', :force => true
ln_s(list, destdir, options = {})
Создаёт несколько символических ссылок в каталоге, каждая из которых указывает на элемент в list. Если destdir не является каталогом, генерирует исключение Errno::ENOTDIR.
Если destdir не является каталогом, генерирует исключение Errno::ENOTDIR.
FileUtils.ln_s Dir.glob('bin/*.rb'), '/home/aamine/bin'
# File lib/fileutils.rb, line 376
def ln_sf(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_sf']
options = options.dup
options[:force] = true
ln_s src, dest, options
end Параметры: noop verbose
То же, что и
#ln_s(src, dest, :force => true)
# File lib/fileutils.rb, line 175
def mkdir(list, options = {})
fu_check_options options, OPT_TABLE['mkdir']
list = fu_list(list)
fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |dir|
fu_mkdir dir, options[:mode]
end
end Параметры: mode noop verbose
Создаёт один или несколько каталогов.
FileUtils.mkdir 'test' FileUtils.mkdir %w( tmp data ) FileUtils.mkdir 'notexist', :noop => true # Does not really create. FileUtils.mkdir 'tmp', :mode => 0700
# File lib/fileutils.rb, line 205
def mkdir_p(list, options = {})
fu_check_options options, OPT_TABLE['mkdir_p']
list = fu_list(list)
fu_output_message "mkdir -p #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return *list if options[:noop]
list.map {|path| remove_trailing_slash(path)}.each do |path|
# optimize for the most common case
begin
fu_mkdir path, options[: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, options[:mode]
rescue SystemCallError
raise unless File.directory?(dir)
end
end
end
return *list
end Параметры: mode noop verbose
Создаёт каталог и все его родительские каталоги. Например,
FileUtils.mkdir_p '/usr/local/lib/ruby'
приводит к созданию следующих каталогов, если они не существуют.
* /usr * /usr/local * /usr/local/lib * /usr/local/lib/ruby
Вы можете передавать несколько каталогов одновременно в списке.
# File lib/fileutils.rb, line 514
def mv(src, dest, options = {})
fu_check_options options, OPT_TABLE['mv']
fu_output_message "mv#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[: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 options[:secure]
remove_entry_secure s, options[:force]
else
remove_entry s, options[:force]
end
end
rescue SystemCallError
raise unless options[:force]
end
end
end Параметры: force noop verbose
Перемещает файл(ы) 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/aamine/.trash/'
FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
# File lib/fileutils.rb, line 103 def pwd Dir.pwd end
Параметры: (нет)
Возвращает имя текущего каталога.
# File lib/fileutils.rb, line 805 def remove_dir(path, force = false) remove_entry path, force # FIXME?? check if it is a directory end
Удаляет каталог dir и его содержимое рекурсивно. Этот метод игнорирует StandardError, если force равно true.
# File lib/fileutils.rb, line 777
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.
# File lib/fileutils.rb, line 700
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 создаёт уязвимость, когда:
* Parent directory is world writable (including /tmp). * Removing directory tree includes world writable directory. * The system has symbolic link.
Для предотвращения этой уязвимости, этот метод применяет специальную предподготовку. Если path является каталогом, этот метод использует chown(2) и chmod(2) для всех удаляемых каталогов. Это требует, чтобы текущий процесс был владельцем всего удаляемого дерева каталогов или был суперпользователем (root).
ПРЕДУПРЕЖДЕНИЕ: Вы должны убедиться, что ВСЕ родительские каталоги не могут быть перемещены другими неуверенными пользователями. Например, родительские каталоги не должны принадлежать неуверенным пользователям и не должны быть доступны для записи всем, за исключением случаев, когда установлен битовой атрибут «только для чтения».
ПРЕДУПРЕЖДЕНИЕ: Только владелец удаляемого дерева каталогов или суперпользователь Unix (root) должен вызывать этот метод. В противном случае этот метод не будет работать.
Для подробной информации об этой уязвимости безопасности см. пример для Perl:
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452
Для fileutils.rb эта уязвимость описана в [ruby-dev:26100].
# File lib/fileutils.rb, line 794 def remove_file(path, force = false) Entry_.new(path).remove_file rescue raise unless force end
Удаляет файл path. Этот метод игнорирует StandardError, если force равно true.
# File lib/fileutils.rb, line 566
def rm(list, options = {})
fu_check_options options, OPT_TABLE['rm']
list = fu_list(list)
fu_output_message "rm#{options[:force] ? ' -f' : ''} #{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |path|
remove_file path, options[:force]
end
end Параметры: force noop verbose
Удаляет файлы, указанные в list. Этот метод не может удалять каталоги. Все StandardErrors игнорируются, когда установлен параметр :force.
FileUtils.rm %w( junk.txt dust.txt )
FileUtils.rm Dir.glob('*.so')
FileUtils.rm 'NotExistFile', :force => true # never raises exception
# File lib/fileutils.rb, line 591
def rm_f(list, options = {})
fu_check_options options, OPT_TABLE['rm_f']
options = options.dup
options[:force] = true
rm list, options
end Параметры: noop verbose
Эквивалентно
#rm(list, :force => true)
# File lib/fileutils.rb, line 626
def rm_r(list, options = {})
fu_check_options options, OPT_TABLE['rm_r']
# options[:secure] = true unless options.key?(:secure)
list = fu_list(list)
fu_output_message "rm -r#{options[:force] ? 'f' : ''} #{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |path|
if options[:secure]
remove_entry_secure path, options[:force]
else
remove_entry path, options[:force]
end
end
end Параметры: force noop verbose secure
Удаляет файлы list[0] list[1]… Если list[n] — это директория, удаляет все её содержимое рекурсивно. Этот метод игнорирует StandardError, когда установлен параметр :force.
FileUtils.rm_r Dir.glob('/tmp/*')
FileUtils.rm_r '/', :force => true # :-)
ВНИМАНИЕ: Этот метод может привести к локальной уязвимости, если одна из родительских директорий или удаляемая директория имеют права доступа world writable (включая /tmp, у которого права 1777), а текущий процесс имеет сильные привилегии, такие как суперпользователь Unix (root), и система содержит символические ссылки. Для безопасного удаления внимательно прочтите документацию remove_entry_secure и установите параметр :secure в значение true. По умолчанию :secure=>false.
ПРИМЕЧАНИЕ: Этот метод вызывает remove_entry_secure, если установлен параметр :secure. Также см. remove_entry_secure.
# File lib/fileutils.rb, line 654
def rm_rf(list, options = {})
fu_check_options options, OPT_TABLE['rm_rf']
options = options.dup
options[:force] = true
rm_r list, options
end Параметры: noop verbose secure
Эквивалентно
#rm_r(list, :force => true)
ВНИМАНИЕ: Этот метод может привести к локальной уязвимости. Сначала прочтите документацию rm_r.
# File lib/fileutils.rb, line 269
def rmdir(list, options = {})
fu_check_options options, OPT_TABLE['rmdir']
list = fu_list(list)
parents = options[:parents]
fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if options[:verbose]
return if options[:noop]
list.each do |dir|
begin
Dir.rmdir(dir = remove_trailing_slash(dir))
if parents
until (parent = File.dirname(dir)) == '.' or parent == dir
dir = parent
Dir.rmdir(dir)
end
end
rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
end
end
end Параметры: parents, noop, verbose
Удаляет одну или несколько директорий.
FileUtils.rmdir 'somedir' FileUtils.rmdir %w(somedir anydir otherdir) # Does not really remove directory; outputs message. FileUtils.rmdir 'somedir', :verbose => true, :noop => true
# File lib/fileutils.rb, line 1143
def touch(list, options = {})
fu_check_options options, OPT_TABLE['touch']
list = fu_list(list)
nocreate = options[:nocreate]
t = options[:mtime]
if options[:verbose]
fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
end
return if options[: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 Параметры: noop verbose mtime nocreate
Обновляет время изменения (mtime) и время доступа (atime) файла(ов) в list. Файлы создаются, если они не существуют.
FileUtils.touch 'timestamp'
FileUtils.touch Dir.glob('*.c'); system 'make'
# File lib/fileutils.rb, line 148
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.