virtfs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +154 -0
  8. data/Rakefile +5 -0
  9. data/lib/virtfs-nativefs-thick.rb +1 -0
  10. data/lib/virtfs-nativefs-thin.rb +1 -0
  11. data/lib/virtfs.rb +38 -0
  12. data/lib/virtfs/activation.rb +97 -0
  13. data/lib/virtfs/block_io.rb +140 -0
  14. data/lib/virtfs/byte_range.rb +71 -0
  15. data/lib/virtfs/context.rb +300 -0
  16. data/lib/virtfs/context_manager.rb +175 -0
  17. data/lib/virtfs/context_switch_class_methods.rb +96 -0
  18. data/lib/virtfs/delegate_module.rb +40 -0
  19. data/lib/virtfs/dir_instance_delegate.rb +3 -0
  20. data/lib/virtfs/exception.rb +13 -0
  21. data/lib/virtfs/file_instance_delegate.rb +3 -0
  22. data/lib/virtfs/file_modes_and_options.rb +293 -0
  23. data/lib/virtfs/find_class_methods.rb +106 -0
  24. data/lib/virtfs/io_buffer.rb +133 -0
  25. data/lib/virtfs/io_instance_delegate.rb +3 -0
  26. data/lib/virtfs/kernel.rb +146 -0
  27. data/lib/virtfs/nativefs/thick.rb +30 -0
  28. data/lib/virtfs/nativefs/thick/dir_class_methods.rb +38 -0
  29. data/lib/virtfs/nativefs/thick/file_class_methods.rb +178 -0
  30. data/lib/virtfs/nativefs/thin.rb +32 -0
  31. data/lib/virtfs/nativefs/thin/dir.rb +30 -0
  32. data/lib/virtfs/nativefs/thin/dir_class_methods.rb +41 -0
  33. data/lib/virtfs/nativefs/thin/file.rb +112 -0
  34. data/lib/virtfs/nativefs/thin/file_class_methods.rb +181 -0
  35. data/lib/virtfs/protofs/protofs.rb +7 -0
  36. data/lib/virtfs/protofs/protofs_base.rb +12 -0
  37. data/lib/virtfs/protofs/protofs_dir.rb +13 -0
  38. data/lib/virtfs/protofs/protofs_dir_class.rb +31 -0
  39. data/lib/virtfs/protofs/protofs_file.rb +27 -0
  40. data/lib/virtfs/protofs/protofs_file_class.rb +136 -0
  41. data/lib/virtfs/stat.rb +100 -0
  42. data/lib/virtfs/thin_dir_delegator.rb +79 -0
  43. data/lib/virtfs/thin_file_delegator.rb +77 -0
  44. data/lib/virtfs/thin_io_delegator_methods.rb +301 -0
  45. data/lib/virtfs/thin_io_delegator_methods_bufferio.rb +337 -0
  46. data/lib/virtfs/v_dir.rb +238 -0
  47. data/lib/virtfs/v_file.rb +480 -0
  48. data/lib/virtfs/v_io.rb +243 -0
  49. data/lib/virtfs/v_pathname.rb +128 -0
  50. data/lib/virtfs/version.rb +3 -0
  51. data/spec/activate_spec.rb +202 -0
  52. data/spec/chroot_spec.rb +120 -0
  53. data/spec/context_manager_class_spec.rb +246 -0
  54. data/spec/context_manager_instance_spec.rb +255 -0
  55. data/spec/context_spec.rb +335 -0
  56. data/spec/data/UTF-16LE-data.txt +0 -0
  57. data/spec/data/UTF-8-data.txt +212 -0
  58. data/spec/dir_class_spec.rb +506 -0
  59. data/spec/dir_instance_spec.rb +208 -0
  60. data/spec/file_class_spec.rb +2106 -0
  61. data/spec/file_instance_spec.rb +154 -0
  62. data/spec/file_modes_and_options_spec.rb +1556 -0
  63. data/spec/find_spec.rb +142 -0
  64. data/spec/io_bufferio_size_shared_examples.rb +371 -0
  65. data/spec/io_bufferio_size_spec.rb +861 -0
  66. data/spec/io_bufferio_spec.rb +801 -0
  67. data/spec/io_class_spec.rb +145 -0
  68. data/spec/io_instance_spec.rb +516 -0
  69. data/spec/kernel_spec.rb +285 -0
  70. data/spec/mount_spec.rb +186 -0
  71. data/spec/nativefs_local_root_spec.rb +132 -0
  72. data/spec/path_spec.rb +39 -0
  73. data/spec/spec_helper.rb +126 -0
  74. data/tasks/rspec.rake +3 -0
  75. data/tasks/yard.rake +7 -0
  76. data/test/UTF-8-demo.txt +212 -0
  77. data/test/bench.rb +18 -0
  78. data/test/bio_internal_test.rb +45 -0
  79. data/test/delegate_io.rb +31 -0
  80. data/test/delegate_module.rb +62 -0
  81. data/test/encode_test.rb +42 -0
  82. data/test/enoent_test.rb +30 -0
  83. data/test/namespace_test.rb +42 -0
  84. data/test/read_block_valid_encoding.rb +44 -0
  85. data/test/read_test.rb +78 -0
  86. data/test/stream_readers.rb +46 -0
  87. data/test/utf-16-demo.txt +0 -0
  88. data/test/utf8_to_utf16.rb +77 -0
  89. data/test/wrapper_test.rb +34 -0
  90. data/virtfs.gemspec +29 -0
  91. metadata +230 -0
@@ -0,0 +1,18 @@
1
+ big_string = "0123456789" * 1000
2
+ big_string.force_encoding("ASCII-8BIT")
3
+
4
+ t0 = Time.now
5
+ (0...2_000_000).each do
6
+ s = big_string.dup
7
+ s[-1] = ""
8
+ end
9
+ t1 = Time.now
10
+ puts "Index: #{t1 - t0} seconds"
11
+
12
+ t0 = Time.now
13
+ (0...2_000_000).each do
14
+ s = big_string.dup
15
+ s.chop!
16
+ end
17
+ t1 = Time.now
18
+ puts "chop!: #{t1 - t0} seconds"
@@ -0,0 +1,45 @@
1
+ require "../lib/virtfs"
2
+ require "tempfile"
3
+
4
+ begin
5
+ @start_marker = "START OF FILE:\n"
6
+ @end_marker = ":END OF FILE"
7
+ @data1 = "0123456789"
8
+ @data2 = "abcdefghijklmnopqrstuvwxyz\n"
9
+
10
+ @temp_file = Tempfile.new("VirtFS-IO")
11
+ @temp_file.write(@start_marker)
12
+ (0..9).each do
13
+ @temp_file.write(@data1)
14
+ @temp_file.write(@data2)
15
+ end
16
+ @temp_file.write(@end_marker)
17
+ @temp_file.close
18
+
19
+ @full_path = @temp_file.path
20
+ @rel_path = File.basename(@full_path)
21
+ @parent_dir = File.dirname(@full_path)
22
+ @file_size = VfsRealFile.size(@full_path)
23
+
24
+ @utf_8_filename = VfsRealFile.join(__dir__, "UTF-8-demo.txt")
25
+
26
+ require "../lib/nativefs"
27
+ @root = File::SEPARATOR
28
+ @native_fs = NativeFS.new
29
+ VirtFS.mount(@native_fs, @root)
30
+
31
+ @vfile_read_obj = VirtFS::VFile.new(@full_path, "r:UTF-8")
32
+ @vfile_read_obj.send(:min_read_buf_sz=, 1)
33
+ range = @vfile_read_obj.read_buffer.range
34
+
35
+ puts "pos = #{@vfile_read_obj.pos}, Range(#{range.first}, #{range.end})"
36
+
37
+ char = "X"
38
+ @vfile_read_obj.ungetc(char)
39
+ puts "pos = #{@vfile_read_obj.pos}, Range(#{range.first}, #{range.end})"
40
+ @vfile_read_obj.getc
41
+
42
+ rescue => err
43
+ puts err.to_s
44
+ puts err.backtrace.join("\n")
45
+ end
@@ -0,0 +1,31 @@
1
+ require "delegate"
2
+
3
+ begin
4
+
5
+ class MyFile < DelegateClass(::File)
6
+ SUPER_CLASSES = [File, IO]
7
+
8
+ def initialize(*args)
9
+ fobj = ::File.new(*args)
10
+ super(fobj)
11
+ end
12
+
13
+ def is_a?(klass)
14
+ super(klass) || SUPER_CLASSES.include?(klass)
15
+ end
16
+ alias_method :kind_of?, :is_a?
17
+ end
18
+
19
+ f = MyFile.new(__FILE__, "r")
20
+
21
+ puts "f.is_a?(File) = #{f.is_a?(File)}"
22
+ puts "f.is_a?(IO) = #{f.is_a?(IO)}"
23
+ puts "f.is_a?(MyFile) = #{f.is_a?(MyFile)}"
24
+ puts "f.is_a?(String) = #{f.is_a?(String)}"
25
+
26
+ f.close
27
+
28
+ rescue => err
29
+ puts err.to_s
30
+ puts err.backtrace.join("\n")
31
+ end
@@ -0,0 +1,62 @@
1
+ require "delegate"
2
+
3
+ begin
4
+
5
+ def DelegateModule(superclass)
6
+ klass = Module.new
7
+ methods = superclass.instance_methods
8
+ methods -= ::Delegator.public_api
9
+ methods -= [:to_s,:inspect,:=~,:!~,:===]
10
+ klass.module_eval do
11
+ def __getobj__ # :nodoc:
12
+ unless defined?(@delegate_dc_obj)
13
+ return yield if block_given?
14
+ __raise__ ::ArgumentError, "not delegated"
15
+ end
16
+ @delegate_dc_obj
17
+ end
18
+ def __setobj__(obj) # :nodoc:
19
+ __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
20
+ @delegate_dc_obj = obj
21
+ end
22
+ methods.each do |method|
23
+ define_method(method, Delegator.delegating_block(method))
24
+ end
25
+ end
26
+ klass.define_singleton_method :public_instance_methods do |all=true|
27
+ super(all) - superclass.protected_instance_methods
28
+ end
29
+ klass.define_singleton_method :protected_instance_methods do |all=true|
30
+ super(all) | superclass.protected_instance_methods
31
+ end
32
+ return klass
33
+ end
34
+
35
+ FileDelegate = DelegateModule(File)
36
+
37
+ class MyIO
38
+ end
39
+
40
+ class MyFile < MyIO
41
+ include FileDelegate
42
+
43
+ def initialize(dobj)
44
+ __setobj__(dobj)
45
+ end
46
+ end
47
+
48
+ fobj = File.new(__FILE__, "r")
49
+
50
+ mf = MyFile.new(fobj)
51
+
52
+ puts "mf.is_a?(MyFile) = #{mf.is_a?(MyFile)}"
53
+ puts "mf.is_a?(MyIO) = #{mf.is_a?(MyIO)}"
54
+
55
+ puts
56
+ mf.each { |l| puts l }
57
+ mf.close
58
+
59
+ rescue => err
60
+ puts err.to_s
61
+ puts err.backtrace.join("\n")
62
+ end
@@ -0,0 +1,42 @@
1
+ begin
2
+ #
3
+ # Find the offset within the file of the first multi-byte character.
4
+ #
5
+ binary_string = ""
6
+ File.open("UTF-16-demo.txt", "rb") do |io|
7
+ binary_string = io.read
8
+ end
9
+ puts "\tbinary_string.encoding.name = #{binary_string.encoding.name} (valid: #{binary_string.valid_encoding?})"
10
+ puts "\tbinary_string.length = #{binary_string.length}"
11
+ puts "\tbinary_string.bytesize = #{binary_string.bytesize}"
12
+ puts
13
+
14
+ utf8_string = ""
15
+ ec = Encoding::Converter.new("UTF-16le", "UTF-8")
16
+ rv = ec.primitive_convert(binary_string, utf8_string)
17
+ puts "primitive_convert --> #{rv}"
18
+ puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
19
+ puts "\tutf8_string.length = #{utf8_string.length}"
20
+ puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
21
+ puts
22
+
23
+ nchunk = 0
24
+ utf8_string = ""
25
+ ec = Encoding::Converter.new("UTF-16le", "UTF-8")
26
+ File.open("UTF-16-demo.txt", "rb") do |io|
27
+ while (binary_string = io.read(99))
28
+ rv = ec.primitive_convert(binary_string, utf8_string, nil, nil, :partial_input => true)
29
+ puts "Chunk: #{nchunk}, rv = #{rv}"
30
+ nchunk += 1
31
+ end
32
+ end
33
+
34
+ puts "nchunk = #{nchunk}"
35
+ puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
36
+ puts "\tutf8_string.length = #{utf8_string.length}"
37
+ puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
38
+ puts
39
+ rescue => err
40
+ puts err.to_s
41
+ puts err.backtrace.join("\n")
42
+ end
@@ -0,0 +1,30 @@
1
+ require "yaml"
2
+
3
+ begin
4
+ begin
5
+ Dir.new("/not/a/dir")
6
+ rescue => err
7
+ puts " err => #{err.class.name}"
8
+ puts " err => #{err.inspect}"
9
+ puts " err.errno = #{err.errno}"
10
+ puts " err.class::Errno = #{err.class::Errno}"
11
+ err = YAML.load(YAML.dump(err))
12
+ nerr = SystemCallError.new("dir", err.class::Errno)
13
+ # nerr.message = err.message
14
+ raise nerr
15
+ end
16
+ rescue Errno::ENOENT => oerr
17
+ puts "**** Got Errno::ENOENT"
18
+ puts "oerr => #{oerr.class.name}"
19
+ puts "oerr => #{oerr.inspect}"
20
+ puts "oerr.errno = #{oerr.errno}"
21
+ puts "oerr.class::Errno = #{oerr.class::Errno}"
22
+ rescue SystemCallError => oerr
23
+ puts "**** Got SystemCallError"
24
+ rescue => oerr
25
+ puts "**** Not Errno::ENOENT"
26
+ puts "oerr => #{oerr.class.name}"
27
+ puts "oerr => #{oerr.inspect}"
28
+ puts "oerr.errno = #{oerr.errno}"
29
+ puts "oerr.class::Errno = #{oerr.class::Errno}"
30
+ end
@@ -0,0 +1,42 @@
1
+ class MyFile
2
+ def self.name
3
+ "MyFile"
4
+ end
5
+ end
6
+
7
+ class Vfs
8
+ def self.nest(ext)
9
+ ext.const_set(:File, MyFile)
10
+ end
11
+ end
12
+
13
+ begin
14
+
15
+ Module.new do
16
+ class << self
17
+ puts self.class.name
18
+ puts constants.inspect
19
+ puts File.name
20
+
21
+ Vfs.nest(self)
22
+ puts constants.inspect
23
+ puts File.name
24
+ end
25
+ end
26
+
27
+ puts
28
+
29
+ Module.new do
30
+ class << self
31
+ puts self.class.name
32
+ puts constants.inspect
33
+ puts File.name
34
+ end
35
+ end
36
+
37
+ puts File.name
38
+
39
+ rescue => err
40
+ puts err.to_s
41
+ puts err.backtrace.join("\n")
42
+ end
@@ -0,0 +1,44 @@
1
+ require "tempfile"
2
+
3
+ begin
4
+ input_file_name = "UTF-8-demo.txt"
5
+ external_encoding = Encoding.find("UTF-8")
6
+ binary_encoding = Encoding.find("ASCII-8BIT")
7
+ buffer_size = 95
8
+
9
+ temp_file = Tempfile.new("rbve")
10
+
11
+ File.open(input_file_name, "rb") do |io|
12
+ block = 0
13
+ while (binary_string = io.read(buffer_size))
14
+ binary_string.force_encoding(external_encoding)
15
+ puts "Block: #{block}, valid: #{binary_string.valid_encoding?}"
16
+ push_back = 0
17
+ (0...8).each do
18
+ break if binary_string.valid_encoding?
19
+ binary_string.force_encoding(binary_encoding)
20
+ binary_string[-1] = ""
21
+ binary_string.force_encoding(external_encoding)
22
+ push_back += 1
23
+ end
24
+ raise "Invalid byte sequence" unless binary_string.valid_encoding?
25
+ puts "Block: #{block}, valid: #{binary_string.valid_encoding?}, push_back: #{push_back}"
26
+ temp_file.write(binary_string)
27
+ io.seek(-push_back, IO::SEEK_CUR) unless push_back == 0
28
+ block += 1
29
+ end
30
+ end
31
+
32
+ temp_file.close
33
+
34
+ input = File.read(input_file_name)
35
+ output = File.read(temp_file.path)
36
+
37
+ puts
38
+ puts "Input size: #{input.bytesize}"
39
+ puts "Output size: #{output.bytesize}"
40
+ puts "Data check pass: #{input == output}"
41
+ rescue => err
42
+ puts err.to_s
43
+ puts err.backtrace.join("\n")
44
+ end
@@ -0,0 +1,78 @@
1
+ begin
2
+ #
3
+ # Find the offset within the file of the first multi-byte character.
4
+ #
5
+ first_mb_char_pos = 0
6
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
7
+ io.each_char do |c|
8
+ if c.length != c.bytesize
9
+ puts "first_mb_char_pos = #{first_mb_char_pos}, char = '#{c}' #{c.bytes.to_a.inspect}"
10
+ puts
11
+ break
12
+ end
13
+ first_mb_char_pos += 1
14
+ end
15
+ end
16
+
17
+ puts "Read whole file as binary:"
18
+ binary_string = ""
19
+ File.open("UTF-8-demo.txt", "rb") do |io|
20
+ binary_string = io.read
21
+ end
22
+ puts "\tbinary_string.encoding.name = #{binary_string.encoding.name} (valid: #{binary_string.valid_encoding?})"
23
+ puts "\tbinary_string.length = #{binary_string.length}"
24
+ puts "\tbinary_string.bytesize = #{binary_string.bytesize}"
25
+ puts
26
+
27
+ puts "Read whole file as utf-8:"
28
+ utf8_string = ""
29
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
30
+ utf8_string = io.read
31
+ end
32
+ puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
33
+ puts "\tutf8_string.length = #{utf8_string.length}"
34
+ puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
35
+ puts
36
+
37
+ puts "Partial read (100 bytes) as utf-8:"
38
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
39
+ utf8_string = io.read(100)
40
+ end
41
+ puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
42
+ puts "\tutf8_string.length = #{utf8_string.length}"
43
+ puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
44
+ puts
45
+
46
+ puts "Offset read (on char boundary) as utf-8:"
47
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
48
+ io.seek(first_mb_char_pos, IO::SEEK_SET)
49
+ utf8_string = io.read
50
+ end
51
+ puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
52
+ puts "\tutf8_string.length = #{utf8_string.length}"
53
+ puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
54
+ puts
55
+
56
+ puts "Offset read (not on char boundary) as utf-8:"
57
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
58
+ io.seek(first_mb_char_pos+1, IO::SEEK_SET)
59
+ utf8_string = io.read
60
+ end
61
+ puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
62
+ puts "\tutf8_string.length = #{utf8_string.length}"
63
+ puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
64
+ puts
65
+
66
+ # File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
67
+ # while utf8_string = io.gets
68
+ # puts utf8_string
69
+ # puts "\tutf8_string.encoding.name = #{utf8_string.encoding.name} (valid: #{utf8_string.valid_encoding?})"
70
+ # puts "\tutf8_string.length = #{utf8_string.length}"
71
+ # puts "\tutf8_string.bytesize = #{utf8_string.bytesize}"
72
+ # puts
73
+ # end
74
+ # end
75
+ rescue => err
76
+ puts err.to_s
77
+ puts err.backtrace.join("\n")
78
+ end
@@ -0,0 +1,46 @@
1
+ begin
2
+ first_mb_char_pos = 0
3
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
4
+ io.each_char do |c|
5
+ if c.length != c.bytesize
6
+ puts "first_mb_char_pos = #{first_mb_char_pos}, char = '#{c}' #{c.bytes.to_a.inspect}"
7
+ puts
8
+ break
9
+ end
10
+ first_mb_char_pos += 1
11
+ end
12
+ end
13
+
14
+ File.open("UTF-8-demo.txt", "r:utf-8:utf-8") do |io|
15
+ puts "File opened"
16
+ puts "\tio.pos = #{io.pos}"
17
+ puts
18
+
19
+ puts "Reading 10 bytes."
20
+ barray = io.each_byte.first(10)
21
+ puts "\tio.pos = #{io.pos}"
22
+ puts
23
+
24
+ puts "Reading 10 bytes."
25
+ barray = io.each_char.first(10)
26
+ puts "\tio.pos = #{io.pos}"
27
+ puts
28
+
29
+ puts "Reading 10 lines."
30
+ ln = 0
31
+ io.each_line do |line|
32
+ break if ln >= 10
33
+ puts "Line: #{ln}"
34
+ puts "\tline.length = #{line.length}"
35
+ puts "\tline.bytesize = #{line.bytesize}"
36
+ puts "\tline.codepoints.length = #{line.codepoints.length}"
37
+ puts "\tio.pos = #{io.pos}"
38
+ puts "\tio.lineno = #{io.lineno}"
39
+ puts
40
+ ln += 1
41
+ end
42
+ end
43
+ rescue => err
44
+ puts err.to_s
45
+ puts err.backtrace.join("\n")
46
+ end