модуль FileUtils
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
Методы публичного класса
# File lib/fileutils.rb, line 117
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
# File lib/fileutils.rb, line 913
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.
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 930
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.#{$$}"
# File lib/fileutils.rb, line 958
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
# File lib/fileutils.rb, line 982
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
# File lib/fileutils.rb, line 724
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 742
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 411
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 427 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 439 def copy_stream(src, dest) IO.copy_stream(src, dest) end
Копирует поток src в dest. src должен отвечать на read(n), а dest должен отвечать на write(str).
# File lib/fileutils.rb, line 352
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
# File lib/fileutils.rb, line 385
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.
# File lib/fileutils.rb, line 763
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
# File lib/fileutils.rb, line 282
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.
# File lib/fileutils.rb, line 315
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'
# File lib/fileutils.rb, line 336 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)
# File lib/fileutils.rb, line 159
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
# File lib/fileutils.rb, line 185
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
Вы можете передать несколько каталогов одновременно в списке.
# File lib/fileutils.rb, line 454
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
# File lib/fileutils.rb, line 97 def pwd Dir.pwd end
Возвращает имя текущего каталога.
# File lib/fileutils.rb, line 713 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 685
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 608
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:
Для fileutils.rb эта уязвимость была сообщена в [ruby-dev:26100].
# File lib/fileutils.rb, line 702 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 500
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
# File lib/fileutils.rb, line 519 def rm_f(list, noop: nil, verbose: nil) rm list, force: true, noop: noop, verbose: verbose end
Эквивалентно
FileUtils.rm(list, :force => true)
# File lib/fileutils.rb, line 546
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), а текущий процесс обладает сильными привилегиями, такими как права суперпользователя Unix (root), и система использует символические ссылки. Для безопасного удаления внимательно изучите документацию remove_entry_secure и установите параметр :secure в значение true. По умолчанию :secure=>false.
ПРИМЕЧАНИЕ: Этот метод вызывает remove_entry_secure, если установлен параметр :secure. Смотрите также remove_entry_secure.
# File lib/fileutils.rb, line 568 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.
# File lib/fileutils.rb, line 242
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|
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 Удаляет один или несколько каталогов.
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 1041
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'
# File lib/fileutils.rb, line 134
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 1548
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"]
# File lib/fileutils.rb, line 1509 def self.commands OPT_TABLE.keys end
Возвращает массив имён методов, которые имеют какие-либо параметры.
p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
# File lib/fileutils.rb, line 1529
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
# File lib/fileutils.rb, line 1518
def self.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 1539
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"]
Методы частного экземпляра
# File lib/fileutils.rb, line 117
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
# File lib/fileutils.rb, line 913
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.
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 bit).
- “+”
-
— добавляется к указанному классу в соответствии с заданным режимом.
- “-”
-
— удаляется из данного класса в соответствии с заданным режимом.
- “=”
-
— точное значение класса будет задано в соответствии с заданным режимом.
# File lib/fileutils.rb, line 930
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.#{$$}"
# File lib/fileutils.rb, line 958
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
# File lib/fileutils.rb, line 982
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
# File lib/fileutils.rb, line 724
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 742
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 411
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 427 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 439 def copy_stream(src, dest) IO.copy_stream(src, dest) end
Копирует поток src в dest. src должен отвечать на read(n), а dest должен отвечать на write(str).
# File lib/fileutils.rb, line 352
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
# File lib/fileutils.rb, line 385
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.
# File lib/fileutils.rb, line 763
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
# File lib/fileutils.rb, line 282
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.
# File lib/fileutils.rb, line 315
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'
# File lib/fileutils.rb, line 336 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)
# File lib/fileutils.rb, line 159
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
# File lib/fileutils.rb, line 185
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
Вы можете передать несколько каталогов сразу в списке.
# File lib/fileutils.rb, line 454
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
# File lib/fileutils.rb, line 97 def pwd Dir.pwd end
Возвращает имя текущего каталога.
# File lib/fileutils.rb, line 713 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 685
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 608
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).
ПРЕДУПРЕЖДЕНИЕ: Вы должны убедиться, что ВСЕ родительские каталоги не могут быть изменены другими незащищёнными пользователями. Например, родительские каталоги не должны принадлежать незащищённым пользователям и не должны быть доступны для записи всем, за исключением случаев, когда установлен бит "sticky".
ПРЕДУПРЕЖДЕНИЕ: Только владелец удаляемой древовидной структуры каталогов или суперпользователь Unix (root) должен вызывать этот метод. В противном случае этот метод не работает.
Для получения подробной информации об этой уязвимости, см. пример из Perl:
Для fileutils.rb эта уязвимость описана в [ruby-dev:26100].
# File lib/fileutils.rb, line 702 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 500
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. Этот метод не может удалять каталоги. Все исключения 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 519 def rm_f(list, noop: nil, verbose: nil) rm list, force: true, noop: noop, verbose: verbose end
Эквивалентно
FileUtils.rm(list, :force => true)
# File lib/fileutils.rb, line 546
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.
# File lib/fileutils.rb, line 568 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.
# File lib/fileutils.rb, line 242
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|
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 Удаляет один или несколько каталогов.
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 1041
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'
# File lib/fileutils.rb, line 134
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.