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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6347d643cd70f383dfe6e5738525ca3ddfc0b40d
4
+ data.tar.gz: 18b7fb18ba46b1958fc27e26cf2e071c5b502f3e
5
+ SHA512:
6
+ metadata.gz: 791b4b067addfe0070a50e8a78d8ad826e87452e9deed22dda8318c6ca414c7458aa5003ec30b71a74c942eefa01131f637f717fdd445051da140d0c05ecd269
7
+ data.tar.gz: 226904fefb083d84c7535e6e58e893f1c0f1e5b4061ef63f80cfdb0b9f90b974b1d6c8eeb18b2e37cf726ddbf08bea6afcf11d6e2498e23cfcb86eb11e6c8a99
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.2"
4
+ sudo: false
5
+ cache: bundler
6
+ env:
7
+ - FS_INTERFACE=thin
8
+ - FS_INTERFACE=thick
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in virtfs.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Richard Oliveri
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,154 @@
1
+ # VirtFS
2
+
3
+ [![Build Status](https://travis-ci.org/ManageIQ/virtfs.svg)](https://travis-ci.org/ManageIQ/virtfs)
4
+ [![Code Climate](https://codeclimate.com/github/ManageIQ/virtfs/badges/gpa.svg)](https://codeclimate.com/github/ManageIQ/virtfs)
5
+
6
+ A virtual (pseudo) filesystem facility for Ruby.
7
+
8
+ Provides an infrastructure where instances of various filesystem **plugins** can be _mounted_ within the filesystem namespace of a Ruby process, and accessed via Ruby `File` and `Dir` classes and objects.
9
+
10
+ Typically, these **plugins** implement a filesystem access paradigm on top of various storage mechanisms and/or programmatic data generation.
11
+
12
+ **For example:** a plugin can be implemented that stores and maintains filesystem-like information in a database - say Berkeley DB - we'll call that plugin `BdbFS`, which is also the name of the Ruby class implementing the plugin. Instantiating an instance of this class will return an instance of the `BdbFS` filesystem, which can then be mounted and accessed through the **VirtFS** facility.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'virtfs'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install virtfs
27
+
28
+ ## Usage
29
+ ### Mounting root
30
+ By default, **VirtFS** does not mount the native filesystem of the system on which the Ruby process is running. It needs to be done explicitly. This is accomplished through the use of a **plugin** that simply _wraps_ the native filsystem in a class that enables its access through **VirtFS**.
31
+
32
+ Typically, one of the first things a **VirtFS** client does, is _mount_ the native filesystem:
33
+ ```ruby
34
+ require "virtfs-nativefs-thick"
35
+
36
+ # Instantiate an instance of the native filesystem.
37
+ native_fs = VirtFS::NativeFS::Thick.new
38
+
39
+ # Mount the native filesystem on root "/"
40
+ VirtFS.mount(native_fs, "/")
41
+ ```
42
+ ### Access
43
+
44
+ Once the native filesystem is mounted, **VirtFS** can be accessed explicitly through the `VirtFS` class, or it can be _activated_, enabling access through Ruby's `File` and `Dir` classes.
45
+
46
+ #### Explicit access
47
+ ```ruby
48
+ require "virtfs-nativefs-thick"
49
+
50
+ # Instantiate an instance of the native filesystem
51
+ native_fs = VirtFS::NativeFS::Thick.new
52
+
53
+ # Mount the native filesystem on root "/"
54
+ VirtFS.mount(native_fs, "/")
55
+
56
+ VirtFS::VDir.chdir("/etc")
57
+ VirtFS::VDir.getwd # => "/etc"
58
+
59
+ VirtFS::VDir.foreach(this_dir) do |f|
60
+ puts f
61
+ end
62
+
63
+ # Note: this does not change the state of Ruby's standard filesystem.
64
+ Dir.getwd # => the original cwd of the ruby process.
65
+ ```
66
+ #### Activation
67
+ ```ruby
68
+ require "virtfs-nativefs-thick"
69
+
70
+ # Instantiate an instance of the native filesystem.
71
+ native_fs = VirtFS::NativeFS::Thick.new
72
+
73
+ # Mount the native filesystem on root "/"
74
+ VirtFS.mount(native_fs, "/")
75
+
76
+ VirtFS.activate!
77
+ VirtFS.activated? # => true
78
+
79
+ # Dir and File classes now go through VirtFS.
80
+ Dir.chdir("/etc")
81
+ Dir.getwd # => "/etc"
82
+
83
+ Dir.foreach(this_dir) do |f|
84
+ puts f
85
+ end
86
+
87
+ VirtFS.deactivate!
88
+ VirtFS.activated? # => false
89
+ ```
90
+ Activation can be confined to a block through the use of the `with` class method:
91
+ ```ruby
92
+ VirtFS.activated? # => false
93
+ VirtFS.with do
94
+ VirtFS.activated? # => true
95
+ end
96
+ VirtFS.activated? # => false
97
+ ```
98
+
99
+ ### Mounting other filesystems
100
+
101
+ Let's use the, yet to be implemented, `BdbFS` plugin as an example:
102
+ ```ruby
103
+ require "virtfs-nativefs-thick"
104
+ require "virtfs-bdbfs"
105
+
106
+ # The Berkeley DB file containing the filesystem data.
107
+ bdbfs_file = "/usr/me/my_bdbfs_file"
108
+
109
+ # Where to mount the BdbFS instance under the native filesystem.
110
+ bdbfs_mount_point = "/usr/me/bdbfs_root"
111
+
112
+ #
113
+ # Mount the native filesystem.
114
+ #
115
+ native_fs = VirtFS::NativeFS::Thick.new
116
+ VirtFS.mount(native_fs, "/")
117
+
118
+ #
119
+ # Instantiate a BdbFS instance and mount it.
120
+ #
121
+ bdb_fs = VirtFS::BdbFS.new(bdbfs_file)
122
+ VirtFS.mount(bdb_fs, bdbfs_mount_point)
123
+
124
+ VirtFS.with do
125
+ Dir.chdir(bdbfs_mount_point)
126
+ Dir.getwd # => "/usr/me/bdbfs_root"
127
+
128
+ # List the files at the root of the BdbFS.
129
+ Dir.foreach(this_dir) do |f|
130
+ puts f
131
+ end
132
+ end
133
+ ```
134
+
135
+ ## Plugins
136
+
137
+ There are two types of filesystem plugins for **VirtFS**; they are distinguished by the type of interface they present to the **VirtFS** infrastructure - the interface that **VirtFS** uses to call into the plugin.
138
+
139
+ * **Thin** interface plugins implement the minimum low-level methods required by **VirtFS**. Most of the common filesystem functionality is provided by the **VirtFS** infrastructure itself (like buffered IO and character encoding), making this type of plugin easier to implement.
140
+ * **Thick** interface plugins implement most, if not all, of the filesystem functionality within the plugin, overriding the common implementations within **VirtFS**. While these plugins require more work to implement, they do provide a measurable performance improvement.
141
+
142
+ In reality, most plugins will be of the **thin** type. More often than not, **thick** plugins will be used to interface **VirtFS** to an underlying technology that already implements the full filesystem interface. An obvious example of this is the plugin that interfaces with Ruby's native filesystem interface.
143
+
144
+ Notice in the examples above, when mounting the native filesystem on root, we used the `VirtFS::NativeFS::Thick` plugin class. This plugin passes most requests directly to the underlying Ruby filesystem implementation, bypassing the common implementations in **VirtFS**.
145
+
146
+ There is a **thin** version of this plugin: `VirtFS::NativeFS::Thin`. It only calls down into the underlying Ruby filesystem implementation for low-level operations, relying on the common functionality provided by **VirtFS** for everything else. While this plugin is less performant than its **thick** counterpart, it's extremely useful in testing the common filesystem functionality implemented within **VirtFS**. In fact the _spec_ tests for **VirtFS** are run using both **thick** and **thin** interfaces, to ensure the expected results are identical.
147
+
148
+ ## Contributing
149
+
150
+ 1. Fork it
151
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
152
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
153
+ 4. Push to the branch (`git push origin my-new-feature`)
154
+ 5. Create new Pull Request
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ Dir.glob('tasks/**/*.rake').each(&method(:import))
3
+
4
+ task :test => :spec
5
+ task :default => :spec
@@ -0,0 +1 @@
1
+ require_relative "virtfs/nativefs/thick"
@@ -0,0 +1 @@
1
+ require_relative "virtfs/nativefs/thin"
@@ -0,0 +1,38 @@
1
+ require 'pathname'
2
+
3
+ VfsRealDir = ::Dir
4
+ VfsRealFile = ::File
5
+ VfsRealIO = ::IO
6
+ VfsRealPathname = ::Pathname
7
+
8
+ require_relative 'virtfs/version.rb'
9
+ require_relative 'virtfs/exception.rb'
10
+ require_relative 'virtfs/context.rb'
11
+ require_relative 'virtfs/context_manager.rb'
12
+ require_relative 'virtfs/file_modes_and_options.rb'
13
+ require_relative 'virtfs/context_switch_class_methods.rb'
14
+ require_relative 'virtfs/find_class_methods.rb'
15
+ require_relative 'virtfs/activation.rb'
16
+ require_relative 'virtfs/delegate_module.rb'
17
+ require_relative 'virtfs/stat.rb'
18
+ require_relative 'virtfs/thin_dir_delegator.rb'
19
+ require_relative 'virtfs/thin_file_delegator.rb'
20
+ require_relative 'virtfs/kernel'
21
+ require_relative 'virtfs/v_pathname.rb'
22
+
23
+ # VirtFS - Ruby Virtual File System Interface
24
+ module VirtFS
25
+ @activated = false
26
+
27
+ extend Activation
28
+ extend DelegateModule
29
+ extend ContextSwitchClassMethods
30
+ extend FindClassMethods
31
+ end
32
+
33
+ require_relative 'virtfs/dir_instance_delegate.rb'
34
+ require_relative 'virtfs/file_instance_delegate.rb'
35
+ require_relative 'virtfs/io_instance_delegate.rb'
36
+ require_relative 'virtfs/v_io.rb'
37
+ require_relative 'virtfs/v_file.rb'
38
+ require_relative 'virtfs/v_dir.rb'
@@ -0,0 +1,97 @@
1
+ module VirtFS
2
+ module Activation
3
+ def activate_mutex
4
+ @activate_mutex ||= Mutex.new
5
+ end
6
+
7
+ # @return [Boolean] indicating if VirtFS is active
8
+ #
9
+ # @see .activate!
10
+ # @see .deactivate!
11
+ def activated?
12
+ @activated
13
+ end
14
+
15
+ # Overrides Ruby's native Dir, File, and IO classes
16
+ # with corresponding VirtFS classes
17
+ def activate!(enable_require = false)
18
+ activate_mutex.synchronize do
19
+ raise "VirtFS.activate! already activated" if @activated
20
+ @activated = true
21
+
22
+ Object.class_eval do
23
+ remove_const(:Dir)
24
+ remove_const(:File)
25
+ remove_const(:IO)
26
+ remove_const(:Pathname)
27
+
28
+ const_set(:Dir, VirtFS::VDir)
29
+ const_set(:File, VirtFS::VFile)
30
+ const_set(:IO, VirtFS::VIO)
31
+ const_set(:Pathname, VirtFS::VPathname)
32
+ end
33
+
34
+ if enable_require
35
+ VirtFS::Kernel.inject
36
+ VirtFS::Kernel.enable
37
+ end
38
+ end
39
+ true
40
+ end
41
+
42
+ # Restores Ruby's native Dir, File, and IO classes
43
+ # to their defaults
44
+ def deactivate!
45
+ activate_mutex.synchronize do
46
+ raise "VirtFS.deactivate! not activated" unless @activated
47
+ @activated = false
48
+
49
+ Object.class_eval do
50
+ remove_const(:Dir)
51
+ remove_const(:File)
52
+ remove_const(:IO)
53
+ remove_const(:Pathname)
54
+
55
+ const_set(:Dir, VfsRealDir)
56
+ const_set(:File, VfsRealFile)
57
+ const_set(:IO, VfsRealIO)
58
+ const_set(:Pathname, VfsRealPathname)
59
+ end
60
+ VirtFS::Kernel.disable
61
+ end
62
+ true
63
+ end
64
+
65
+ # Invokes the given block in an activated context
66
+ #
67
+ # @see .activate!
68
+ def with(enable_require = false)
69
+ if activated?
70
+ yield
71
+ else
72
+ begin
73
+ activate!(enable_require)
74
+ yield
75
+ ensure
76
+ deactivate!
77
+ end
78
+ end
79
+ end
80
+
81
+ # Invokes the given block in a deactivated context
82
+ #
83
+ # @see .deactivate!
84
+ def without
85
+ if !activated?
86
+ yield
87
+ else
88
+ begin
89
+ deactivate!
90
+ yield
91
+ ensure
92
+ activate!
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,140 @@
1
+ module VirtFS
2
+ # Block IO Adapter, used internally by VirtFS to perform read and write operations
3
+ # via an underlying 'block-like' interface.
4
+ #
5
+ # The class requires a handle to an object defining #raw_read and #raw_write methods
6
+ # facilitating raw block access.
7
+ #
8
+ # This class behaves similarily to a tradional disk device, providing a 'seek'
9
+ # position at which read/write operations occur after which the pos is updated
10
+ #
11
+ class BlockIO
12
+ MIN_BLOCKS_TO_CACHE = 64
13
+
14
+ # Optional absolute block offset, always applied
15
+ attr_accessor :offset
16
+
17
+ # BlockIO initializer
18
+ #
19
+ # @param io_obj [RawIO] instance of class defining #raw_read and #raw_write
20
+ #
21
+ def initialize(io_obj)
22
+ @io_obj = io_obj
23
+ @block_size = @io_obj.block_size # Size of block in bytes
24
+ @size = @io_obj.size # Size of file in bytes
25
+ @size_in_blocks = @size / @block_size # Size of file in blocks
26
+ @start_byte_addr = 0
27
+ @end_byte_addr = @size - 1
28
+ @lba_end = @size_in_blocks - 1
29
+ @seek_pos = 0
30
+ @cache_range = Range.new(-1, -1)
31
+ @offset = 0
32
+ end
33
+
34
+ # Read len bytes from the block device and update seek_pos
35
+ #
36
+ # @param len [Integer] number of bytes to read
37
+ # @return [Array<Byte>,nil] array of up to len bytes read from block device,
38
+ # or nil if no bytes can be read
39
+ def read(len)
40
+ return nil if @seek_pos >= @end_byte_addr
41
+ len = @end_byte_addr - @seek_pos if (@seek_pos + len) > @end_byte_addr
42
+
43
+ start_sector, start_offset = @seek_pos.divmod(@block_size)
44
+ end_sector = (@seek_pos + len - 1) / @block_size
45
+ num_sector = end_sector - start_sector + 1
46
+
47
+ rbuf = bread_cached(start_sector, num_sector)
48
+ @seek_pos += len
49
+
50
+ rbuf[start_offset, len]
51
+ end
52
+
53
+ # Write buffer of specified length to block device and update seek_pos
54
+ #
55
+ # @param buf [Array<Byte>] bytes to write to disk device
56
+ # @return [Integer,nil] number of bytes written to device, or nil if none
57
+ # can be written
58
+ def write(buf, len)
59
+ return nil if @seek_pos >= @end_byte_addr
60
+ len = @end_byte_addr - @seek_pos if (@seek_pos + len) > @end_byte_addr
61
+
62
+ start_sector, start_offset = @seek_pos.divmod(@block_size)
63
+ end_sector = (@seek_pos + len - 1) / @block_size
64
+ num_sector = end_sector - start_sector + 1
65
+
66
+ rbuf = bread(start_sector, num_sector)
67
+ rbuf[start_offset, len] = buf[0, len]
68
+
69
+ bwrite(start_sector, num_sector, rbuf)
70
+ @seek_pos += len
71
+
72
+ len
73
+ end
74
+
75
+ # Advance seek pointer via the specified mechanism
76
+ #
77
+ # @param amt [Integer] absolute amount which to advance seek pointer
78
+ # @param whence [IO::SEEK_SET, IO::SEEK_CUR, IO::SEEK_END] mechanism
79
+ # which to update seek pos
80
+ #
81
+ # @see ::IO::SEEK_SET
82
+ # @see ::IO::SEEK_CUR
83
+ # @see ::IO::SEEK_END
84
+ #
85
+ def seek(amt, whence = IO::SEEK_SET)
86
+ case whence
87
+ when IO::SEEK_CUR
88
+ @seek_pos += amt
89
+ when IO::SEEK_END
90
+ @seek_pos = @end_byte_addr + amt
91
+ when IO::SEEK_SET
92
+ @seek_pos = amt + @start_byte_addr
93
+ end
94
+ @seek_pos
95
+ end
96
+
97
+ # @return [Integer] size of block device
98
+ def size
99
+ @size
100
+ end
101
+
102
+ # Close block device, after this no additional read/writes can occur
103
+ def close
104
+ @io_obj.close
105
+ end
106
+
107
+ private
108
+
109
+ def bread(start_sector, num_sectors)
110
+ # $log.debug "RawBlockIO.bread: start_sector = #{start_sector}, num_sectors = #{num_sectors}, @lba_end = #{@lba_end}"
111
+ return nil if start_sector > @lba_end
112
+ num_sectors = @size_in_blocks - start_sector if (start_sector + num_sectors) > @size_in_blocks
113
+ @io_obj.raw_read(start_sector * @block_size + @offset, num_sectors * @block_size)
114
+ end
115
+
116
+ def bwrite(start_sector, num_sectors, buf)
117
+ return nil if start_sector > @lba_end
118
+ num_sectors = @size_in_blocks - start_sector if (start_sector + num_sectors) > @size_in_blocks
119
+ @io_obj.raw_write(buf, start_sector * @block_size + @offset, num_sectors * @block_size)
120
+ end
121
+
122
+ def bread_cached(start_sector, num_sectors)
123
+ # $log.debug "RawBlockIO.bread_cached: start_sector = #{start_sector}, num_sectors = #{num_sectors}"
124
+ if !@cache_range.include?(start_sector) || !@cache_range.include?(start_sector + num_sectors - 1)
125
+ sectors_to_read = [MIN_BLOCKS_TO_CACHE, num_sectors].max
126
+ @cache = bread(start_sector, sectors_to_read)
127
+ sectors_read = @cache.length / @block_size
128
+ end_sector = start_sector + sectors_read - 1
129
+ @cache_range = Range.new(start_sector, end_sector)
130
+ end
131
+
132
+ sector_offset = start_sector - @cache_range.first
133
+ buffer_offset = sector_offset * @block_size
134
+ length = num_sectors * @block_size
135
+ # $log.debug "RawBlockIO.bread_cached: buffer_offset = #{buffer_offset}, length = #{length}"
136
+
137
+ @cache[buffer_offset, length]
138
+ end
139
+ end
140
+ end