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
Public Class Methods
# 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
# File lib/fakefs/file.rb, line 180 def self.basename(*args) RealFile.basename(*args) end
# 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
# 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
# File lib/fakefs/file.rb, line 790 def self.birthtime(path) if exist?(path) FileSystem.find(path).birthtime else raise Errno::ENOENT end end
# 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
# 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
# File lib/fakefs/file.rb, line 142 def self.const_missing(name) RealFile.const_get(name) end
# 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
# 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
# File lib/fakefs/file.rb, line 184 def self.dirname(*args) RealFile.dirname(*args) end
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
# 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
# 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
# File lib/fakefs/file.rb, line 54 def self.extname(path) RealFile.extname(path) end
# 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
# File lib/fakefs/file.rb, line 348 def self.fnmatch?(pattern, path, flags = 0) RealFile.fnmatch?(pattern, path, flags) end
# 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
# File lib/fakefs/file.rb, line 172 def self.ftype(filename) File.lstat(filename).ftype end
# File lib/fakefs/file.rb, line 76 def identical?(one_path, another_path) FileSystem.find(one_path) == FileSystem.find(another_path) end
# File lib/fakefs/file.rb, line 58 def self.join(*parts) RealFile.join(parts) end
# File lib/fakefs/file.rb, line 259 def self.link(source, dest) raise Errno::EPERM, "#{source} or #{dest}" if directory?(source) raise Errno::ENOENT, "#{source} or #{dest}" unless exist?(source) raise Errno::EEXIST, "#{source} or #{dest}" if exist?(dest) source = FileSystem.find(source) dest = FileSystem.add(dest, source.entry.clone) source.link(dest) 0 end
# File lib/fakefs/file.rb, line 294 def self.lstat(file) File::Stat.new(file, true) end
# 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
# File lib/fakefs/file.rb, line 62 def self.path(file) RealFile.path(file) end
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
# File lib/fakefs/file.rb, line 86 def self.readable?(path) return false unless exist? path File.lstat(path).readable? end
# 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
# File lib/fakefs/file.rb, line 188 def self.readlink(path) symlink = FileSystem.find(path) raise Errno::ENOENT unless symlink symlink.target end
# File lib/fakefs/file.rb, line 754 def self.realdirpath(*args) RealFile.realdirpath(*args) end
# File lib/fakefs/file.rb, line 717 def self.realpath(*args) RealFile.realpath(*args) end
# 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
# 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
# File lib/fakefs/file.rb, line 128 def self.size?(path) size(path) if exist?(path) && !size(path).zero? end
# File lib/fakefs/file.rb, line 298 def self.split(path) RealFile.split(path) end
# File lib/fakefs/file.rb, line 290 def self.stat(file) File::Stat.new(file) end
Assume nothing is sticky.
# File lib/fakefs/file.rb, line 81 def sticky?(_path) false end
# File lib/fakefs/file.rb, line 286 def self.symlink(source, dest) FileUtils.ln_s(source, dest) end
# File lib/fakefs/file.rb, line 155 def self.symlink?(path) if path.respond_to? :entry path.is_a? FakeSymlink else FileSystem.find(path).is_a? FakeSymlink end end
# File lib/fakefs/file.rb, line 335 def self.umask(*args) RealFile.umask(*args) end
# 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
# File lib/fakefs/file.rb, line 91 def self.writable?(path) return false unless exist? path File.lstat(path).writable? end
# 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
# File lib/fakefs/file.rb, line 132 def self.zero?(path) exist?(path) && size(path) == 0 end
Private Class Methods
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
# 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
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
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
# File lib/fakefs/file.rb, line 758 def advise(_advice, _offset = 0, _len = 0); end
# File lib/fakefs/file.rb, line 675 def atime self.class.atime(@path) end
# File lib/fakefs/file.rb, line 744 def autoclose? @autoclose ? true : false end
# File lib/fakefs/file.rb, line 721 def binmode? # File.open('test_mode', mode: 'w:binary').binmode? # => false @fmode & FMODE_BINMODE != 0 end
# File lib/fakefs/file.rb, line 798 def birthtime self.class.birthtime(@path) end
# 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
# 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
# File lib/fakefs/file.rb, line 726 def close_on_exec=(_bool) raise NotImplementedError end
# File lib/fakefs/file.rb, line 730 def close_on_exec? raise NotImplementedError end
# File lib/fakefs/file.rb, line 679 def ctime self.class.ctime(@path) end
# File lib/fakefs/file.rb, line 603 def exists? true end
# File lib/fakefs/file.rb, line 683 def flock(*) raise NotImplementedError end
# File lib/fakefs/file.rb, line 640 def ioctl(*) raise NotImplementedError end
# File lib/fakefs/file.rb, line 632 def is_a?(klass) RealFile.allocate.is_a?(klass) end
# File lib/fakefs/file.rb, line 652 def lstat self.class.lstat(@path) end
# File lib/fakefs/file.rb, line 687 def mtime self.class.mtime(@path) end
# File lib/fakefs/file.rb, line 644 def read_nonblock raise NotImplementedError end
# File lib/fakefs/file.rb, line 671 def readpartial(*) super end
# File lib/fakefs/file.rb, line 750 def size File.size(@path) end
# File lib/fakefs/file.rb, line 648 def stat self.class.stat(@path) end
# File lib/fakefs/file.rb, line 636 def string gets(nil) end
# File lib/fakefs/file.rb, line 656 def sysseek(position, whence = SEEK_SET) seek(position, whence) pos end
# File lib/fakefs/file.rb, line 663 def to_io self end
# File lib/fakefs/file.rb, line 734 def to_path @path end
# File lib/fakefs/file.rb, line 607 def write(*args) val = super(*args) @file.mtime = Time.now val end
# File lib/fakefs/file.rb, line 667 def write_nonblock(*) raise NotImplementedError end
Private Instance Methods
# File lib/fakefs/file.rb, line 1048 def check_file_existence! raise Errno::ENOENT, @path.to_s unless @file end
# 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 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
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 lib/fakefs/file.rb, line 1052 def file_creation_mode? mode_in?(RealFile::CREAT) end
# File lib/fakefs/file.rb, line 1056 def mode_in?(mask) (@oflags & mask) != 0 end
# 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