class FakeFS::File

FakeFS File class inherit StringIO

Be careful using this, as it may break things if you obtain more that one flock per file using different descriptors. Real flock call blocks/returns false in that case - see man7.org/linux/man-pages/man2/flock.2.html, it says it “may be denied”, but it does, it fact, deny. This implementation simply returns 0. This may also be a problem if you, it fact, are accessing a real file, which is locked by another process.

Constants

DEFAULT_DIR_SIZE
DIR_ENTRY_SIZE
FAKE_FS_ALLOWED_FLOCK_MODES

yep, File::LOCK_UN | File::LOCK_NB is allowed

FILE_ACCESS_MODE
FILE_CREATION_MODES
FMODE_APPEND
FMODE_BINMODE
FMODE_CREATE
FMODE_EXCL
FMODE_READABLE
FMODE_READWRITE
FMODE_TEXTMODE
FMODE_TRUNC
FMODE_WRITABLE
MODES
MODE_BITMASK

copied from github.com/ruby/ruby/blob/v2_7_8/include/ruby/io.h#L108

TEXT_MODES

Attributes

autoclose[RW]
path[R]

Public Class Methods

absolute_path(file_name, dir_name = Dir.getwd) click to toggle source
# File lib/fakefs/file.rb, line 738
def self.absolute_path(file_name, dir_name = Dir.getwd)
  RealFile.absolute_path(file_name, dir_name)
end
basename(*args) click to toggle source
# File lib/fakefs/file.rb, line 180
def self.basename(*args)
  RealFile.basename(*args)
end
binread(file, length = nil, offset = 0) click to toggle source
# File lib/fakefs/file.rb, line 339
def self.binread(file, length = nil, offset = 0)
  File.read(file, length, offset, mode: 'rb:ASCII-8BIT')
end
binwrite(file, content, offset = nil) click to toggle source
# File lib/fakefs/file.rb, line 343
def self.binwrite(file, content, offset = nil)
  mode = offset ? 'r+b:ASCII-8BIT' : 'wb:ASCII-8BIT'
  File.write(file, content, offset, mode: mode)
end
birthtime(path) click to toggle source
# File lib/fakefs/file.rb, line 790
def self.birthtime(path)
  if exist?(path)
    FileSystem.find(path).birthtime
  else
    raise Errno::ENOENT
  end
end
chmod(new_mode, filename) click to toggle source
# File lib/fakefs/file.rb, line 302
def self.chmod(new_mode, filename)
  # chmod's mode can either be passed in in absolute mode, or symbolic mode
  # for reference: https://ruby-doc.org/stdlib-2.2.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-chmod
  # if the mode is passed in symbolic mode we must convert it to absolute mode
  is_absolute_mode = new_mode.is_a? Numeric
  unless is_absolute_mode
    current_mode = FileSystem.find(filename).mode
    new_mode = convert_symbolic_chmod_to_absolute(new_mode, current_mode)
  end
  FileSystem.find(filename).mode = 0o100000 + new_mode
end
chown(owner_int, group_int, filename) click to toggle source
# File lib/fakefs/file.rb, line 322
def self.chown(owner_int, group_int, filename)
  file = FileSystem.find(filename)

  if owner_int && owner_int != -1
    owner_int.is_a?(Integer) || raise(TypeError, "can't convert String into Integer")
    file.uid = owner_int
  end
  if group_int && group_int != -1
    group_int.is_a?(Integer) || raise(TypeError, "can't convert String into Integer")
    file.gid = group_int
  end
end
const_missing(name) click to toggle source
# File lib/fakefs/file.rb, line 142
def self.const_missing(name)
  RealFile.const_get(name)
end
delete(*files) click to toggle source
# File lib/fakefs/file.rb, line 271
def self.delete(*files)
  files.each do |file|
    file_name = (file.instance_of?(FakeFS::File) ? file.path : file.to_s)
    raise Errno::ENOENT, file_name unless exist?(file_name)

    FileUtils.rm(file_name)
  end

  files.size
end
Also aliased as: unlink
directory?(path) click to toggle source
# File lib/fakefs/file.rb, line 146
def self.directory?(path)
  if path.respond_to? :entry
    path.entry.is_a? FakeDir
  else
    result = FileSystem.find(path)
    result ? result.entry.is_a?(FakeDir) : false
  end
end
dirname(*args) click to toggle source
# File lib/fakefs/file.rb, line 184
def self.dirname(*args)
  RealFile.dirname(*args)
end
empty?(path)
Alias for: zero?
executable?(filename) click to toggle source

Not exactly right, returns true if the file is chmod +x for owner. In the context of when you would use fakefs, this is usually what you want.

# File lib/fakefs/file.rb, line 316
def self.executable?(filename)
  file = FileSystem.find(filename)
  return false unless file
  (file.mode - 0o100000) & 0o100 != 0
end
exist?(path) click to toggle source
# File lib/fakefs/file.rb, line 66
def self.exist?(path)
  if File.symlink?(path)
    referent = File.expand_path(File.readlink(path), File.dirname(path))
    exist?(referent)
  else
    !FileSystem.find(path).nil?
  end
end
expand_path(file_name, dir_string = FileSystem.current_dir.to_s) click to toggle source
# File lib/fakefs/file.rb, line 176
def self.expand_path(file_name, dir_string = FileSystem.current_dir.to_s)
  RealFile.expand_path(file_name, RealFile.expand_path(dir_string, Dir.pwd))
end
extname(path) click to toggle source
# File lib/fakefs/file.rb, line 54
def self.extname(path)
  RealFile.extname(path)
end
file?(path) click to toggle source
# File lib/fakefs/file.rb, line 163
def self.file?(path)
  if path.respond_to? :entry
    path.entry.is_a? FakeFile
  else
    result = FileSystem.find(path)
    result ? result.entry.is_a?(FakeFile) : false
  end
end
fnmatch(pattern, path, flags = 0)
Alias for: fnmatch?
fnmatch?(pattern, path, flags = 0) click to toggle source
# File lib/fakefs/file.rb, line 348
def self.fnmatch?(pattern, path, flags = 0)
  RealFile.fnmatch?(pattern, path, flags)
end
Also aliased as: fnmatch
foreach(path, *args, &block) click to toggle source
# File lib/fakefs/file.rb, line 219
def self.foreach(path, *args, &block)
  file = new(path)
  if file.exists?
    FileSystem.find(path).atime = Time.now
    if block_given?
      file.each_line(*args, &block)
    else
      file.each_line(*args)
    end
  else
    raise Errno::ENOENT
  end
end
ftype(filename) click to toggle source
# File lib/fakefs/file.rb, line 172
def self.ftype(filename)
  File.lstat(filename).ftype
end
identical?(one_path, another_path) click to toggle source
# File lib/fakefs/file.rb, line 76
def identical?(one_path, another_path)
  FileSystem.find(one_path) == FileSystem.find(another_path)
end
join(*parts) click to toggle source
# File lib/fakefs/file.rb, line 58
def self.join(*parts)
  RealFile.join(parts)
end
lstat(file) click to toggle source
# File lib/fakefs/file.rb, line 294
def self.lstat(file)
  File::Stat.new(file, true)
end
new(path, *args) click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 503
def initialize(path, *args)
  # unable to pass args otherwise on jruby, it may cause false passes on MRI, though
  # because explicit hash isn't supported
  opts = args.last.is_a?(Hash) ? args.pop : {}
  if args.size > 2
    raise ArgumentError, "wrong number of arguments (given #{args.size + 1}, expected 1..3)"
  end
  mode, _perm = args

  @path = path
  @file = FileSystem.find(@path)
  # real rb_scan_open_args - and rb_io_extract_modeenc - is much more complex
  raise ArgumentError, 'mode specified twice' unless mode.nil? || opts[:mode].nil?

  mode_opt = mode.nil? ? opts[:mode] : mode
  # see vmode_handle
  if mode_opt.nil?
    @oflags = RealFile::RDONLY
  elsif mode_opt.respond_to?(:to_int) && (intmode = mode_opt.to_int).instance_of?(Integer)
    @oflags = intmode
  else
    unless mode_opt.is_a?(String)
      unless mode_opt.respond_to?(:to_str)
        raise TypeError, "no implicit conversion of #{mode_opt.class} into String"
      end

      strmode = mode_opt.to_str
      unless strmode.is_a?(String)
        raise TypeError, "can't convert #{mode_opt.class} to String " \
          "(#{mode_opt.class}#to_str gives #{strmode.class})"
      end

      mode_opt = strmode
    end

    @oflags, @fmode = parse_strmode_oflags(mode_opt)
  end
  unless opts[:flags].nil?
    if opts[:flags].is_a?(Integer)
      @oflags |= opts[:flags]
    elsif opts[:flags].respond_to?(:to_int)
      intflags = opts[:flags].to_int
      unless intflags.instance_of?(Integer)
        raise TypeError, "can't convert #{opts[:flags].class} to Integer " \
          "(#{opts[:flags].class}#to_int gives #{intflags.class})"
      end

      @oflags |= intflags
      @fmode = create_fmode(@oflags)
    else
      raise TypeError, "no implicit conversion of #{opts[:flags].class} into Integer"
    end
  end
  @fmode ||= create_fmode(@oflags)
  @fmode = extract_binmode(opts, @fmode)

  @autoclose = true
  file_creation_mode? ? create_missing_file : check_file_existence!
  # StringIO changes enciding of the underlying string to binary
  # when binary data is written if it's opened in binary mode,
  # so content might have binary encoding. StringIO also switches to
  # binary mode if its string have binary encoding, but it might not
  # be what we want, so insteed we use encoding parsed after super call
  # and force set it back.

  # truncate doesn't work
  unless @file.is_a?(FakeFS::FakeDir)
    @file.content = @file.content.dup.force_encoding(Encoding.default_external)
  end
  # StringIO.new 'content', nil, **{} # works in MRI, but fails in JRuby
  # but File.open 'filename', nil, **{} is ok both in MRI and JRuby

  # JRuby StringIO doesn't support kwargs without mode
  #  StringIO.new "buff", encoding: 'binary' # work on MRI, fails on JRuby
  if RUBY_PLATFORM == "java"
    # other opts aren't supported
    super(@file.content, mode_opt || 'r')
    binmode if binmode? # Looks like it doesn't care about 'b'
    mode_opt_str = mode_opt.is_a?(String) ? mode_opt : ''
    raise ArgumentError, 'encoding specified twice' if mode_opt_str[':'] && opts[:encoding]

    # Might raise where real File just warns
    str_encoding = mode_opt_str.split(':')[1] # internal encoding is ignored anyway
    if opts[:encoding]
      set_encoding(opts[:encoding])
    elsif str_encoding && str_encoding != ''
      set_encoding(str_encoding)
    elsif opts[:binmode]
      set_encoding(Encoding::BINARY)
    end
  else
    super(@file.content, mode, **opts)
  end

  # StringIO is wrtable and readable by default, so we need to disable it
  # but maybe it was explicitly disabled by opts
  close_write if @fmode & FMODE_WRITABLE == 0 && !StringIO.instance_method(:closed_write?).bind(self).call
  close_read if @fmode & FMODE_READABLE == 0 && !StringIO.instance_method(:closed_read?).bind(self).call
end
path(file) click to toggle source
# File lib/fakefs/file.rb, line 62
def self.path(file)
  RealFile.path(file)
end
read(path, *args) click to toggle source

TODO: support open_key_args

# File lib/fakefs/file.rb, line 195
def self.read(path, *args)
  options = args[-1].is_a?(Hash) ? args.pop : {}
  length = args.empty? ? nil : args.shift
  offset = args.empty? ? 0 : args.shift
  file = new(path, **options)

  raise Errno::ENOENT unless file.exists?
  raise Errno::EISDIR, path.to_s if directory?(path)

  FileSystem.find(path).atime = Time.now
  file.seek(offset)
  file.read(length)
end
readable?(path) click to toggle source
# File lib/fakefs/file.rb, line 86
def self.readable?(path)
  return false unless exist? path
  File.lstat(path).readable?
end
readlines(path, chomp: false) click to toggle source
# File lib/fakefs/file.rb, line 209
def self.readlines(path, chomp: false)
  file = new(path)
  if file.exists?
    FileSystem.find(path).atime = Time.now
    chomp ? file.readlines.map(&:chomp) : file.readlines
  else
    raise Errno::ENOENT
  end
end
realdirpath(*args) click to toggle source
# File lib/fakefs/file.rb, line 754
def self.realdirpath(*args)
  RealFile.realdirpath(*args)
end
realpath(*args) click to toggle source
# File lib/fakefs/file.rb, line 717
def self.realpath(*args)
  RealFile.realpath(*args)
end
rename(source, dest) click to toggle source
# File lib/fakefs/file.rb, line 233
def self.rename(source, dest)
  if directory?(source) && file?(dest)
    raise Errno::ENOTDIR, "#{source} or #{dest}"
  elsif file?(source) && directory?(dest)
    raise Errno::EISDIR, "#{source} or #{dest}"
  elsif !exist?(dirname(dest))
    raise Errno::ENOENT, "#{source} or #{dest}"
  end

  if (target = FileSystem.find(source))
    return 0 if source == dest

    if target.is_a?(FakeFS::FakeSymlink)
      File.symlink(target.target, dest)
    else
      FileSystem.add(dest, target.entry.clone)
    end

    FileSystem.delete(source)
  else
    raise Errno::ENOENT, "#{source} or #{dest}"
  end

  0
end
size(path) click to toggle source
# File lib/fakefs/file.rb, line 120
def self.size(path)
  if directory?(path)
    DEFAULT_DIR_SIZE + (DIR_ENTRY_SIZE * FileSystem.find(path).entries.size)
  else
    read(path).bytesize
  end
end
size?(path) click to toggle source
# File lib/fakefs/file.rb, line 128
def self.size?(path)
  size(path) if exist?(path) && !size(path).zero?
end
split(path) click to toggle source
# File lib/fakefs/file.rb, line 298
def self.split(path)
  RealFile.split(path)
end
stat(file) click to toggle source
# File lib/fakefs/file.rb, line 290
def self.stat(file)
  File::Stat.new(file)
end
sticky?(_path) click to toggle source

Assume nothing is sticky.

# File lib/fakefs/file.rb, line 81
def sticky?(_path)
  false
end
umask(*args) click to toggle source
# File lib/fakefs/file.rb, line 335
def self.umask(*args)
  RealFile.umask(*args)
end
utime(atime, mtime, *paths) click to toggle source
# File lib/fakefs/file.rb, line 106
def self.utime(atime, mtime, *paths)
  paths.each do |path|
    file_node = FileSystem.find(path)
    if file_node
      file_node.atime = atime
      file_node.mtime = mtime
    else
      raise Errno::ENOENT, "No such file or directory - #{path}"
    end
  end

  paths.size
end
writable?(path) click to toggle source
# File lib/fakefs/file.rb, line 91
def self.writable?(path)
  return false unless exist? path
  File.lstat(path).writable?
end
write(filename, contents, offset = nil, **open_args) click to toggle source
# File lib/fakefs/file.rb, line 760
def self.write(filename, contents, offset = nil, **open_args)
  mode = offset ? 'r+' : 'w'
  if open_args[:open_args]
    # see open_key_args
    # todo: foreach, readlines, read also use it
    # Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
    open_args = open_args[:open_args]
    if open_args.last.is_a?(Hash)
      args = open_args[0...-1]
      opt = open_args.last
    else
      args = open_args
      opt = {}
    end
  else
    args = [open_args.delete(:mode) || mode]
    opt = open_args
  end
  if offset
    open(filename, *args, **opt) do |f| # rubocop:disable Security/Open
      f.seek(offset)
      f.write(contents)
    end
  else
    open(filename, *args, **opt) do |f| # rubocop:disable Security/Open
      f.write(contents)
    end
  end
end
zero?(path) click to toggle source
# File lib/fakefs/file.rb, line 132
def self.zero?(path)
  exist?(path) && size(path) == 0
end
Also aliased as: empty?

Private Class Methods

calculate_chmod_amt_for_mode(modes) click to toggle source

given a list of modes [rwx] (a) ensure all modes are valid and (b) return the numeric value associated with the modes

# File lib/fakefs/file.rb, line 929
def self.calculate_chmod_amt_for_mode(modes)
  valid_modes_to_numeric_vals = { 'r' => 0o4, 'w' => 0o2, 'x' => 0o1 }

  # if we give no modes, then we are removing all permission
  chmod_perm_num = 0o0
  if modes != ''
    # make sure there are no invalid flags in the modes and that we discard duplicates as chmod does
    given_modes = modes.split('')
    given_modes = given_modes.uniq
    given_modes.each do |specific_mode|
      # ensure that the mode is valid
      unless valid_modes_to_numeric_vals.key? specific_mode
        raise ArgumentError, "Invalid `perm' symbol in file mode: #{specific_mode}"
      end

      chmod_perm_num += valid_modes_to_numeric_vals[specific_mode]
    end
  end

  chmod_perm_num
end
convert_symbolic_chmod_to_absolute(new_mode, current_mode) click to toggle source
# File lib/fakefs/file.rb, line 802
def self.convert_symbolic_chmod_to_absolute(new_mode, current_mode)
  # mode always must be of form <GROUP1>=<FLAGS>,<GROUP2>=<FLAGS,...
  # e.g.: u=wr,go=x
  chmod_pairs = new_mode.split(',')

  # - duplicating groups is OK ( e.g.: 'ugouuoouu' is valid and is interpretted as 'ugo' )
  # - duplicating modes is OK ( e.g.: 'wwwwwwwww' is interpreted as 'w' )
  # - omitting the right hand side is interpretted as removing all permission
  # ( e.g.: 'ugo=' is really 'chmod 000' )
  # - omitting the left hand side is interpretted as all groups ( e.g.: '=rwx' is really 'ugo=rwx' )
  # - if we list a group more than once, we only apply the rightmost permissions
  # ( e.g.: 'ug=rx,g=x' is really 'u=r,g=x' )
  # - we cannot list any flags that are not 'rwx' ( e.g.: converting 'ug=rwx' to 'ug=7' is invalid )
  # or else an error is raised
  #   - in the example above, the following error is raised: 'invalid `perm' symbol in file mode: 7 (ArgumentError)'
  # - we cannot put in any groups that are not 'ugo' ( e.g.: listing groups as 'uzg=x' is invalid )
  # or else an error is raised
  #   - in the example above, the following error is raised: 'invalid `who' symbol in file mode: z (ArgumentError)'
  valid_groups_to_numeric_vals = { 'u' => 0o100, 'g' => 0o10, 'o' => 0o1 }

  # make sure we preload the current group values.
  # chmod works by calculating new permissions based off of existing permissions
  current_groups_to_vals = { 0o100 => 0o0, 0o10 => 0o0, 0o1 => 0o0 }
  [0o100, 0o10, 0o1].each do |group_num|
    perm_amt = get_perms_for_group(current_mode, group_num)
    current_groups_to_vals[group_num] = perm_amt
  end

  chmod_pairs.each do |pair|
    # see if we are dealing with +/- ( granting or removing permissions ) or = ( assigning permissions )
    # note that it IS valid to mix assignment and granting/revoking perissions ( things like u=wrx,g+x are valid )
    assign_perms = '='
    remove_perms = '-'
    add_perms = '+'
    assignment_mode = nil
    if pair.include? remove_perms
      assignment_mode = remove_perms
    elsif pair.include? add_perms
      assignment_mode = add_perms
    elsif pair.include? assign_perms
      assignment_mode = assign_perms
    end

    # if we can't find a mode, then raise an exception as real `chmod` would
    if assignment_mode.nil?
      raise ArgumentError, "Invalid file mode: #{mode}"
    end
    adding_removing_perms = [add_perms, remove_perms].include?(assignment_mode)

    groups = pair.rpartition(assignment_mode).first
    modes = pair.rpartition(assignment_mode).last

    # get the numeric chmod value associated with the symbolic entry
    chmod_perm_num = calculate_chmod_amt_for_mode modes

    # if we give no groups, then we are giving all groups
    if groups == ''
      if adding_removing_perms
        [0o100, 0o10, 0o1].each do |group_num|
          perm_amt = set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num)
          current_groups_to_vals[group_num] = perm_amt
        end
      else
        [0o100, 0o10, 0o1].each do |group_num|
          current_groups_to_vals[group_num] = chmod_perm_num
        end
      end
    else
      # make sure there are no invalid flags in the groups and that we discard duplicates as chmod does
      given_groups = groups.split('')
      given_groups = given_groups.uniq
      given_groups.each do |specific_group|
        # ensure that the group is valid
        unless valid_groups_to_numeric_vals.key? specific_group
          raise ArgumentError, "Invalid `who' symbol in file mode: #{specific_group}"
        end

        # take the current chmod amt from earlier and associate that as the current chmod factor for the group
        # if we are adding or removing groups ( via +/- ) then we must make sure that we adjust
        # the current chmod perm number for the group
        group_num = valid_groups_to_numeric_vals[specific_group]
        adjusted_chmod = chmod_perm_num
        if adding_removing_perms
          adjusted_chmod = set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num)
        end
        current_groups_to_vals[group_num] = adjusted_chmod
      end
    end
  end

  # return an octal chmod value for the value
  0o100 * current_groups_to_vals[0o100] + 0o10 * current_groups_to_vals[0o10] + current_groups_to_vals[0o1]
end
get_perms_for_group(current_file_mode, group_num) click to toggle source

return the group mode for group num based off the provided current_file_mode

# File lib/fakefs/file.rb, line 897
def self.get_perms_for_group(current_file_mode, group_num)
  # get the current recorded mode of the group and return it to the caller
  # note we don't shift for 'o' since that is the bottom 3 bits
  # note we multiply by 7 since the group num is 1, and octal represents digits 1-7 and we want all 3 bits
  current_group_mode = current_file_mode & (group_num * 7)
  if group_num == 0o100
    current_group_mode >>= 6
  elsif group_num == 0o10
    current_group_mode >>= 3
  end

  current_group_mode
end
set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num) click to toggle source

given the current chmod values for a file return the result of adding or removing chmod_perm_num from the requested groups permissions ( so performing <GROUP>+<PERMS> or <GROUP>-<PERMS>

# File lib/fakefs/file.rb, line 913
def self.set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num)
  # get the current recorded mode of the group
  current_group_mode = current_groups_to_vals[group_num]

  # now that we have the current value of the group, add or remove bits accordingly
  if assignment_mode == '+'
    current_group_mode | chmod_perm_num
  elsif assignment_mode == '-'
    current_group_mode & ~chmod_perm_num
  else
    raise ArgumentError, "Unknown assignment mode #{assignment_mode}"
  end
end

Public Instance Methods

advise(_advice, _offset = 0, _len = 0) click to toggle source
# File lib/fakefs/file.rb, line 758
def advise(_advice, _offset = 0, _len = 0); end
atime() click to toggle source
# File lib/fakefs/file.rb, line 675
def atime
  self.class.atime(@path)
end
autoclose?() click to toggle source
# File lib/fakefs/file.rb, line 744
def autoclose?
  @autoclose ? true : false
end
binmode?() click to toggle source
# File lib/fakefs/file.rb, line 721
def binmode?
  # File.open('test_mode', mode: 'w:binary').binmode? # => false
  @fmode & FMODE_BINMODE != 0
end
birthtime() click to toggle source
# File lib/fakefs/file.rb, line 798
def birthtime
  self.class.birthtime(@path)
end
chmod(new_mode) click to toggle source
# File lib/fakefs/file.rb, line 691
def chmod(new_mode)
  # chmod's mode can either be passed in in absolute mode, or symbolic mode
  # for reference: https://ruby-doc.org/stdlib-2.2.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-chmod
  # if the mode is passed in symbolic mode we must convert it to absolute mode
  is_absolute_mode = new_mode.is_a? Numeric
  unless is_absolute_mode
    current_mode = @file.mode
    new_mode = convert_symbolic_chmod_to_absolute(new_mode, current_mode)
  end
  @file.mode = 0o100000 + new_mode
end
chown(owner_int, group_int) click to toggle source
# File lib/fakefs/file.rb, line 703
def chown(owner_int, group_int)
  return unless group_int && group_int != -1

  owner_int.is_a?(Integer) || raise(
    TypeError, "can't convert String into Integer"
  )
  @file.uid = owner_int

  group_int.is_a?(Integer) || raise(
    TypeError, "can't convert String into Integer"
  )
  @file.gid = group_int
end
close_on_exec=(_bool) click to toggle source
# File lib/fakefs/file.rb, line 726
def close_on_exec=(_bool)
  raise NotImplementedError
end
close_on_exec?() click to toggle source
# File lib/fakefs/file.rb, line 730
def close_on_exec?
  raise NotImplementedError
end
ctime() click to toggle source
# File lib/fakefs/file.rb, line 679
def ctime
  self.class.ctime(@path)
end
exists?() click to toggle source
# File lib/fakefs/file.rb, line 603
def exists?
  true
end
flock(*) click to toggle source
# File lib/fakefs/file.rb, line 683
def flock(*)
  raise NotImplementedError
end
ioctl(*) click to toggle source
# File lib/fakefs/file.rb, line 640
def ioctl(*)
  raise NotImplementedError
end
is_a?(klass) click to toggle source
# File lib/fakefs/file.rb, line 632
def is_a?(klass)
  RealFile.allocate.is_a?(klass)
end
lstat() click to toggle source
# File lib/fakefs/file.rb, line 652
def lstat
  self.class.lstat(@path)
end
mtime() click to toggle source
# File lib/fakefs/file.rb, line 687
def mtime
  self.class.mtime(@path)
end
read_nonblock() click to toggle source
# File lib/fakefs/file.rb, line 644
def read_nonblock
  raise NotImplementedError
end
readpartial(*) click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 671
def readpartial(*)
  super
end
size() click to toggle source
# File lib/fakefs/file.rb, line 750
def size
  File.size(@path)
end
stat() click to toggle source
# File lib/fakefs/file.rb, line 648
def stat
  self.class.stat(@path)
end
string() click to toggle source
# File lib/fakefs/file.rb, line 636
def string
  gets(nil)
end
sysseek(position, whence = SEEK_SET) click to toggle source
# File lib/fakefs/file.rb, line 656
def sysseek(position, whence = SEEK_SET)
  seek(position, whence)
  pos
end
syswrite(*args)
Alias for: write
to_io() click to toggle source
# File lib/fakefs/file.rb, line 663
def to_io
  self
end
to_path() click to toggle source
# File lib/fakefs/file.rb, line 734
def to_path
  @path
end
write(*args) click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 607
def write(*args)
  val = super(*args)
  @file.mtime = Time.now
  val
end
Also aliased as: syswrite
write_nonblock(*) click to toggle source
# File lib/fakefs/file.rb, line 667
def write_nonblock(*)
  raise NotImplementedError
end

Private Instance Methods

check_file_existence!() click to toggle source
# File lib/fakefs/file.rb, line 1048
def check_file_existence!
  raise Errno::ENOENT, @path.to_s unless @file
end
create_fmode(oflags) click to toggle source
# File lib/fakefs/file.rb, line 982
def create_fmode(oflags)
  # rb_io_oflags_fmode
  fmode = 0
  case oflags & FILE_ACCESS_MODE
  when RealFile::RDONLY
    fmode = FMODE_READABLE
  when RealFile::WRONLY
    fmode = FMODE_WRITABLE
  when RealFile::RDWR
    fmode = FMODE_READWRITE
  end
  fmode |= FMODE_APPEND if (oflags & RealFile::APPEND) != 0
  fmode |= FMODE_TRUNC if (oflags & RealFile::TRUNC) != 0
  fmode |= FMODE_CREATE if (oflags & RealFile::CREAT) != 0
  fmode |= FMODE_EXCL if (oflags & RealFile::EXCL) != 0
  fmode |= FMODE_BINMODE if (oflags & RealFile::BINARY) != 0
  fmode
end
create_missing_file() click to toggle source

Create a missing file if the path is valid.

# File lib/fakefs/file.rb, line 1062
def create_missing_file
  if @file
    raise Errno::EEXIST, @path.to_s if mode_in?(RealFile::EXCL)
    raise Errno::EISDIR, path.to_s if File.directory?(@path)
    return
  end
  dirname = RealFile.dirname @path

  unless dirname == '.'
    dir = FileSystem.find dirname

    raise Errno::ENOENT, path.to_s unless dir.is_a? FakeDir
  end

  @file = FileSystem.add(path, FakeFile.new)
end
extract_binmode(opts, fmode) click to toggle source

split the private class method decleration so rubocop doesn’t complain the line is too long

# File lib/fakefs/file.rb, line 957
def extract_binmode(opts, fmode)
  textmode = opts[:textmode]
  unless textmode.nil?
    raise ArgumentError, "textmode specified twice" if fmode & FMODE_TEXTMODE != 0
    raise ArgumentError, "both textmode and binmode specified" if fmode & FMODE_BINMODE != 0

    # yep, false has no effect here, but still causes ArgumentError
    fmode |= FMODE_TEXTMODE if textmode
  end

  binmode = opts[:binmode]
  unless binmode.nil?
    raise ArgumentError, "binmode specified twice" if fmode & FMODE_BINMODE != 0
    raise ArgumentError, "both textmode and binmode specified" if fmode & FMODE_TEXTMODE != 0

    fmode |= FMODE_BINMODE if binmode
  end

  if fmode & FMODE_BINMODE != 0 && fmode & FMODE_TEXTMODE != 0
    raise ArgumentError, "both textmode and binmode specified"
  end

  fmode
end
file_creation_mode?() click to toggle source
# File lib/fakefs/file.rb, line 1052
def file_creation_mode?
  mode_in?(RealFile::CREAT)
end
mode_in?(mask) click to toggle source
# File lib/fakefs/file.rb, line 1056
def mode_in?(mask)
  (@oflags & mask) != 0
end
parse_strmode_oflags(mode) click to toggle source
# File lib/fakefs/file.rb, line 1001
def parse_strmode_oflags(mode)
  # rb_io_modestr_fmode
  access_mode = mode[0]
  mode_modificators = mode[1..-1].split(':', 2).first
  fmode = TEXT_MODES[access_mode]
  raise ArgumentError, "invalid access mode #{mode}" unless fmode

  mode_modificators&.each_char do |m|
    case m
    when 'b'
      fmode |= FMODE_BINMODE
    when 't'
      fmode |= FMODE_TEXTMODE
    when '+'
      fmode |= FMODE_READWRITE
    when 'x'
      raise ArgumentError, "invalid access mode #{mode}" unless access_mode == 'w'

      fmode |= FMODE_EXCL
    else
      raise ArgumentError, "invalid access mode #{mode}"
    end
  end
  if (fmode & FMODE_BINMODE).nonzero? && (fmode & FMODE_TEXTMODE).nonzero?
    raise ArgumentError, "invalid access mode #{mode}"
  end

  # rb_io_fmode_oflags
  oflags = 0
  case fmode & FMODE_READWRITE
  when FMODE_READABLE
    oflags |= RealFile::RDONLY
  when FMODE_WRITABLE
    oflags |= RealFile::WRONLY
  when FMODE_READWRITE
    oflags |= RealFile::RDWR
  end

  oflags |= RealFile::APPEND if (fmode & FMODE_APPEND).nonzero?
  oflags |= RealFile::TRUNC if (fmode & FMODE_TRUNC).nonzero?
  oflags |= RealFile::CREAT if (fmode & FMODE_CREATE).nonzero?
  oflags |= RealFile::EXCL if (fmode & FMODE_EXCL).nonzero?
  oflags |= RealFile::BINARY if (fmode & FMODE_BINMODE).nonzero?

  [oflags, fmode]
end