virt_disk 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.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +1 -0
- data/Rakefile +6 -0
- data/lib/virt_disk.rb +9 -0
- data/lib/virt_disk/block_file.rb +32 -0
- data/lib/virt_disk/client_head.rb +56 -0
- data/lib/virt_disk/disk.rb +21 -0
- data/lib/virt_disk/disk_unicode.rb +43 -0
- data/lib/virt_disk/disk_uuid.rb +22 -0
- data/lib/virt_disk/export_methods.rb +74 -0
- data/lib/virt_disk/file_io.rb +42 -0
- data/lib/virt_disk/partition.rb +39 -0
- data/lib/virt_disk/partition_type.rb +16 -0
- data/lib/virt_disk/partition_type/dos_partition.rb +113 -0
- data/lib/virt_disk/partition_type/gpt_partition.rb +71 -0
- data/lib/virt_disk/version.rb +3 -0
- data/spec/data/dos_partition.img +0 -0
- data/spec/data/gpt_partition.img +0 -0
- data/spec/data/no_partition.img +0 -0
- data/spec/dos_partition_spec.rb +49 -0
- data/spec/export_methods_spec.rb +257 -0
- data/spec/gpt_partition_spec.rb +58 -0
- data/spec/partition_shared_examples.rb +55 -0
- data/spec/partition_type_spec.rb +74 -0
- data/spec/spec_helper.rb +20 -0
- data/tasks/rspec.rake +3 -0
- data/tasks/yard.rake +7 -0
- data/virt_disk.gemspec +31 -0
- metadata +182 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 78ec73c22b2c23d9ba2b2e92c673e81017de439a
|
4
|
+
data.tar.gz: 025ee06aa5d102e2f0bcc1c2b27ea419fd4b63d3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e302b6b3a6d75bba33696d2e246db31516cf4be131ae0959b0f3bdedf55c3b54454834f705daca9973cf3f116d5b30b0fcbae06c6549c82f1fc3039cc95db1ea
|
7
|
+
data.tar.gz: 628a7c6ead32e9b48d37c908992d0347913f75b3c2e20c5cc82e4d619fc242894910394bafb19bc3ba099b335e71f383dcca649825b32501c0320cb8c98a35a1
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 ManageIQ
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# virt_disk
|
data/Rakefile
ADDED
data/lib/virt_disk.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'log_decorator'
|
2
|
+
require 'virt_disk/export_methods'
|
3
|
+
require 'virt_disk/client_head'
|
4
|
+
require 'virt_disk/disk'
|
5
|
+
require 'virt_disk/partition'
|
6
|
+
require 'virt_disk/partition_type'
|
7
|
+
require 'virt_disk/partition_type/dos_partition'
|
8
|
+
require 'virt_disk/partition_type/gpt_partition'
|
9
|
+
require 'virt_disk/file_io'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
class BlockFile
|
3
|
+
attr_accessor :path
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
@file = defined?(VirtFS) ? VirtFS::VFile.open(path) : File.open(path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def block_size
|
11
|
+
1
|
12
|
+
end
|
13
|
+
|
14
|
+
def size
|
15
|
+
@file.size
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@file.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw_read(start, len)
|
23
|
+
@file.seek start
|
24
|
+
@file.read len
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_write(buf, start, len)
|
28
|
+
@file.seek start
|
29
|
+
@file.write buf, len
|
30
|
+
end
|
31
|
+
end # class BlockFile
|
32
|
+
end # module VirtDisk
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
class ClientHead
|
3
|
+
attr_reader :size, :start_byte_addr, :end_byte_addr, :seek_pos
|
4
|
+
|
5
|
+
include ExportMethods
|
6
|
+
|
7
|
+
def initialize(up_stream_module)
|
8
|
+
@up_stream_module = up_stream_module
|
9
|
+
@start_byte_addr = 0
|
10
|
+
@size = @up_stream_module.size
|
11
|
+
@end_byte_addr = @size - 1
|
12
|
+
@seek_pos = @start_byte_addr
|
13
|
+
self.delegate = @up_stream_module
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
@up_stream_module.close
|
18
|
+
end
|
19
|
+
|
20
|
+
def seek_pos
|
21
|
+
@seek_pos - @start_byte_addr
|
22
|
+
end
|
23
|
+
|
24
|
+
def seek(amt, whence = IO::SEEK_SET)
|
25
|
+
case whence
|
26
|
+
when IO::SEEK_CUR
|
27
|
+
@seek_pos += amt
|
28
|
+
when IO::SEEK_END
|
29
|
+
@seek_pos = @endByteAddr + amt
|
30
|
+
when IO::SEEK_SET
|
31
|
+
@seek_pos = amt + @start_byte_addr
|
32
|
+
end
|
33
|
+
@seek_pos
|
34
|
+
end
|
35
|
+
|
36
|
+
def read(len)
|
37
|
+
rb = mod_read(@seek_pos, len)
|
38
|
+
@seek_pos += rb.length unless rb.nil?
|
39
|
+
rb
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(buf, len)
|
43
|
+
nbytes = @up_stream_module.mod_write(@seek_pos, buf, len)
|
44
|
+
@seek_pos += nbytes
|
45
|
+
nbytes
|
46
|
+
end
|
47
|
+
|
48
|
+
def mod_read(offset, len)
|
49
|
+
@up_stream_module.mod_read(offset, len)
|
50
|
+
end
|
51
|
+
|
52
|
+
def mod_write(offset, buffer, len)
|
53
|
+
@up_stream_module.mod_write(offset, buffer, len)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
class Disk < ClientHead
|
3
|
+
DEFAULT_BLOCK_SIZE = 512
|
4
|
+
DISK_SIG_OFFSET = 0x1B8
|
5
|
+
DISK_SIG_SIZE = 4
|
6
|
+
|
7
|
+
def initialize(up_stream_module)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def block_size
|
12
|
+
return @up_stream_module.block_size if @up_stream_module.respond_to?(:block_size)
|
13
|
+
DEFAULT_BLOCK_SIZE
|
14
|
+
end
|
15
|
+
export :block_size
|
16
|
+
|
17
|
+
def disk_sig
|
18
|
+
@disk_sig ||= @up_stream_module.mod_read(DISK_SIG_OFFSET, DISK_SIG_SIZE).unpack('L')[0]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class String
|
2
|
+
# See Programming Ruby 1.9 - The Pragmatic Programmers’ Guide
|
3
|
+
# Figure 17.1. "Encodings and Their Aliases" in the for available encodings.
|
4
|
+
def UnicodeToUtf8
|
5
|
+
dup.force_encoding("UTF-16LE").encode("UTF-8")
|
6
|
+
end
|
7
|
+
|
8
|
+
def UnicodeToUtf8!
|
9
|
+
force_encoding("UTF-16LE").encode!("UTF-8")
|
10
|
+
end
|
11
|
+
|
12
|
+
def Utf8ToUnicode
|
13
|
+
dup.force_encoding("UTF-8").encode("UTF-16LE")
|
14
|
+
end
|
15
|
+
|
16
|
+
def Utf8ToUnicode!
|
17
|
+
force_encoding("UTF-8").encode!("UTF-16LE")
|
18
|
+
end
|
19
|
+
|
20
|
+
def AsciiToUtf8
|
21
|
+
dup.force_encoding("ISO-8859-1").encode("UTF-8")
|
22
|
+
end
|
23
|
+
|
24
|
+
def AsciiToUtf8!
|
25
|
+
force_encoding("ISO-8859-1").encode!("UTF-8")
|
26
|
+
end
|
27
|
+
|
28
|
+
def Utf8ToAscii
|
29
|
+
dup.force_encoding("UTF-8").encode("ISO-8859-1")
|
30
|
+
end
|
31
|
+
|
32
|
+
def Utf8ToAscii!
|
33
|
+
force_encoding("UTF-8").encode!("ISO-8859-1")
|
34
|
+
end
|
35
|
+
|
36
|
+
def Ucs2ToAscii
|
37
|
+
dup.force_encoding("UTF-16LE").encode("ISO-8859-1")
|
38
|
+
end
|
39
|
+
|
40
|
+
def Ucs2ToAscii!
|
41
|
+
force_encoding("UTF-16LE").encode!("ISO-8859-1")
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'uuidtools'
|
2
|
+
|
3
|
+
module DiskUUID
|
4
|
+
REGEX_FORMAT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
5
|
+
|
6
|
+
def self.clean_guid(guid)
|
7
|
+
return nil if guid.nil?
|
8
|
+
g = guid.to_s.downcase
|
9
|
+
return nil if g.strip.empty?
|
10
|
+
return g if g.length == 36 && g =~ REGEX_FORMAT
|
11
|
+
g.delete!('^0-9a-f')
|
12
|
+
g.sub!(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, '\1-\2-\3-\4-\5')
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.new_guid
|
16
|
+
UUIDTools::UUID.timestamp_create.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.method_missing(m, *args)
|
20
|
+
UUIDTools::UUID.send(m, *args)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
# Utility module used by VirtDisk plug-ins, allowing them to export methods upstream.
|
3
|
+
#
|
4
|
+
# Typically, VirtDisk plug-ins are linked in a chain - each plug-in communicating with
|
5
|
+
# the plug-in immediately upstream from it (where upstream is closer to the source of the data).
|
6
|
+
# The last downstream plug-in (the volume head) is the object accessed directly by the client.
|
7
|
+
#
|
8
|
+
# This module enables upstream plug-ins to export methods, so they can be called directly
|
9
|
+
# from the volume head.
|
10
|
+
#
|
11
|
+
# @note Every plug-in class must include this module, even if they don't export any methods.
|
12
|
+
module ExportMethods
|
13
|
+
module ClassMethods
|
14
|
+
# Export one or more methods, making them callable from the volume head.
|
15
|
+
#
|
16
|
+
# @param syms [Symbol] the names of one or more methods to be exported.
|
17
|
+
# @raise [RuntimeError] if any of the methods aren't defined in the class.
|
18
|
+
def export(*syms)
|
19
|
+
syms.each do |s|
|
20
|
+
sym = s.to_sym
|
21
|
+
raise "Method not defined in class: #{sym}" unless method_defined?(sym)
|
22
|
+
return nil if exports.include?(sym)
|
23
|
+
exports << sym
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Array<Symbol>] array of exported methods.
|
29
|
+
def exports
|
30
|
+
@__exported_methods ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param sym [Symbol]
|
34
|
+
# @return [Boolean] - true if sym is exported by this class, false otherwise.
|
35
|
+
def exported?(sym)
|
36
|
+
exports.include?(sym.to_sym)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.included(host_class)
|
41
|
+
host_class.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Set the module immediately upstream from this one.
|
45
|
+
#
|
46
|
+
# @param obj [Object] the upstream module.
|
47
|
+
def delegate=(obj)
|
48
|
+
@__delegate = obj
|
49
|
+
end
|
50
|
+
|
51
|
+
# The module immediately upstream from this one.
|
52
|
+
#
|
53
|
+
# @return [Object] the module immediately upstream from this one.
|
54
|
+
def delegate
|
55
|
+
@__delegate
|
56
|
+
end
|
57
|
+
|
58
|
+
# @param sym [Symbol]
|
59
|
+
# @return [Boolean] - true if sym is exported by this module's class, false otherwise.
|
60
|
+
def exported?(sym)
|
61
|
+
self.class.exported?(sym)
|
62
|
+
end
|
63
|
+
|
64
|
+
def respond_to_missing?(sym, include_all = false)
|
65
|
+
return false unless @__delegate
|
66
|
+
@__delegate.exported?(sym) || @__delegate.send(:respond_to_missing?, sym, include_all)
|
67
|
+
end
|
68
|
+
|
69
|
+
def method_missing(sym, *args)
|
70
|
+
super unless respond_to_missing?(sym)
|
71
|
+
@__delegate.send(sym, *args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
class FileIo
|
3
|
+
attr_accessor :path
|
4
|
+
alias_method :file_name, :path
|
5
|
+
|
6
|
+
include LogDecorator::Logging
|
7
|
+
include ExportMethods
|
8
|
+
|
9
|
+
export :path, :file_name
|
10
|
+
|
11
|
+
def initialize(path, *args)
|
12
|
+
@path = path
|
13
|
+
@file_lock = Mutex.new
|
14
|
+
|
15
|
+
_log.debug "Opening file - #{path}"
|
16
|
+
@file = File.open(path, *args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def size
|
20
|
+
@file.size
|
21
|
+
end
|
22
|
+
export :size
|
23
|
+
|
24
|
+
def close
|
25
|
+
@file.close
|
26
|
+
end
|
27
|
+
|
28
|
+
def mod_read(start, len)
|
29
|
+
@file_lock.synchronize do
|
30
|
+
@file.seek start
|
31
|
+
@file.read len
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def mod_write(buf, start, len)
|
36
|
+
@file_lock.synchronize do
|
37
|
+
@file.seek start
|
38
|
+
@file.write buf, len
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "binary_struct"
|
2
|
+
|
3
|
+
module VirtDisk
|
4
|
+
class Partition < ClientHead
|
5
|
+
attr_reader :start_lba, :end_lba, :ptype, :pnum
|
6
|
+
|
7
|
+
MBR_SIZE = 512
|
8
|
+
DOS_SIG = "55aa"
|
9
|
+
GPT_SIG = 238
|
10
|
+
|
11
|
+
DOS_PARTITION_ENTRY = BinaryStruct.new([
|
12
|
+
'C', :bootable,
|
13
|
+
'C', :startCHS0,
|
14
|
+
'C', :startCHS1,
|
15
|
+
'C', :startCHS2,
|
16
|
+
'C', :ptype,
|
17
|
+
'C', :endCHS0,
|
18
|
+
'C', :endCHS1,
|
19
|
+
'C', :endCHS1,
|
20
|
+
'L', :start_lba,
|
21
|
+
'L', :part_size
|
22
|
+
])
|
23
|
+
PTE_LEN = DOS_PARTITION_ENTRY.size
|
24
|
+
DOS_PT_START = 446
|
25
|
+
|
26
|
+
def initialize(disk, ptype, pnum, start_lba, end_lba)
|
27
|
+
super(disk)
|
28
|
+
|
29
|
+
@start_lba = start_lba
|
30
|
+
@end_lba = end_lba
|
31
|
+
@ptype = ptype
|
32
|
+
@pnum = pnum
|
33
|
+
@start_byte_addr = @start_lba * block_size
|
34
|
+
@end_byte_addr = @end_lba * block_size
|
35
|
+
@seek_pos = @start_byte_addr
|
36
|
+
@size = @end_byte_addr - @start_byte_addr
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
module PartitionType
|
3
|
+
def self.partition_probe(disk)
|
4
|
+
partition_types.each do |partition_type|
|
5
|
+
partitions = partition_type.discover_partitions(disk)
|
6
|
+
return partitions unless partitions.empty?
|
7
|
+
end
|
8
|
+
[]
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.partition_types
|
12
|
+
constants.collect { |sym| const_get(sym) }
|
13
|
+
.find_all { |obj| obj.is_a?(Class) && obj.respond_to?(:discover_partitions) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module VirtDisk
|
2
|
+
module PartitionType
|
3
|
+
class DosPartition < Partition
|
4
|
+
DOS_NPTE = 4
|
5
|
+
PTYPE_EXT_CHS = 0x05
|
6
|
+
PTYPE_EXT_LBA = 0x0f
|
7
|
+
PTYPE_LDM = 0x42
|
8
|
+
|
9
|
+
include LogDecorator::Logging
|
10
|
+
include ExportMethods
|
11
|
+
|
12
|
+
def initialize(disk, ptype, pnum, start_lba, size_in_blocks)
|
13
|
+
# Convert partition size to partition end LBA.
|
14
|
+
super(disk, ptype, pnum, start_lba, start_lba + size_in_blocks)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.discover_partitions(disk) # rubocop:disable AbcSize
|
18
|
+
_log.debug "<#{disk.object_id}> disk file: #{disk.file_name}" if disk.respond_to? :file_name
|
19
|
+
mbr = disk.mod_read(0, MBR_SIZE)
|
20
|
+
|
21
|
+
if mbr.length < MBR_SIZE
|
22
|
+
_log.info "<#{disk.object_id}> disk does not contain a master boot record"
|
23
|
+
return []
|
24
|
+
end
|
25
|
+
|
26
|
+
sig = mbr[510..511].unpack('H4')
|
27
|
+
|
28
|
+
pt_entry = DOS_PARTITION_ENTRY.decode(mbr[DOS_PT_START, PTE_LEN])
|
29
|
+
ptype = pt_entry[:ptype]
|
30
|
+
|
31
|
+
return [] if sig[0] != DOS_SIG || ptype == GPT_SIG
|
32
|
+
discover_dos_pri_partitions(disk, mbr)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.discover_dos_pri_partitions(disk, mbr) # rubocop:disable AbcSize
|
36
|
+
pte = DOS_PT_START
|
37
|
+
partitions = []
|
38
|
+
(1..DOS_NPTE).each do |n|
|
39
|
+
pt_entry = DOS_PARTITION_ENTRY.decode(mbr[pte, PTE_LEN])
|
40
|
+
pte += PTE_LEN
|
41
|
+
ptype = pt_entry[:ptype]
|
42
|
+
|
43
|
+
#
|
44
|
+
# If this os an LDM (dynamic) disk, then ignore any partitions.
|
45
|
+
#
|
46
|
+
if ptype == PTYPE_LDM
|
47
|
+
_log.debug "<#{disk.object_id}> detected LDM (dynamic) disk"
|
48
|
+
return([])
|
49
|
+
end
|
50
|
+
|
51
|
+
if ptype == PTYPE_EXT_CHS || ptype == PTYPE_EXT_LBA
|
52
|
+
partitions.concat(
|
53
|
+
discover_dos_ext_partitions(
|
54
|
+
disk,
|
55
|
+
pt_entry[:start_lba],
|
56
|
+
pt_entry[:start_lba],
|
57
|
+
DOS_NPTE + 1
|
58
|
+
)
|
59
|
+
)
|
60
|
+
next
|
61
|
+
end
|
62
|
+
partitions.push(new(disk, ptype, n, pt_entry[:start_lba], pt_entry[:part_size])) if ptype != 0
|
63
|
+
end
|
64
|
+
partitions
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Discover secondary file system partitions within a primary extended partition.
|
69
|
+
#
|
70
|
+
# pri_base_lba is the LBA of the primary extended partition.
|
71
|
+
# All pointers to secondary extended partitions are relative to this base.
|
72
|
+
#
|
73
|
+
# ptBaseLBA is the LBA of the partition table within the current extended partition.
|
74
|
+
# All pointers to secondary file system partitions are relative to this base.
|
75
|
+
#
|
76
|
+
def self.discover_dos_ext_partitions(disk, pri_base_lba, ptBaseLBA, pnum) # rubocop:disable AbcSize
|
77
|
+
ra = []
|
78
|
+
seek(ptBaseLBA * @blockSize, IO::SEEK_SET)
|
79
|
+
mbr = read(MBR_SIZE)
|
80
|
+
|
81
|
+
#
|
82
|
+
# Create and add disk object for secondary file system partition.
|
83
|
+
# NOTE: the start of the partition is relative to ptBaseLBA.
|
84
|
+
#
|
85
|
+
pte = DOS_PT_START
|
86
|
+
pt_entry = DOS_PARTITION_ENTRY.decode(mbr[pte, PTE_LEN])
|
87
|
+
ra << new(
|
88
|
+
disk,
|
89
|
+
pt_entry[:ptype],
|
90
|
+
pnum,
|
91
|
+
pt_entry[:start_lba] + ptBaseLBA,
|
92
|
+
pt_entry[:part_size]
|
93
|
+
) if pt_entry[:ptype] != 0
|
94
|
+
|
95
|
+
#
|
96
|
+
# Follow the chain to the next secondary extended partition.
|
97
|
+
# NOTE: the start of the partition is relative to pri_base_lba.
|
98
|
+
#
|
99
|
+
pte += PTE_LEN
|
100
|
+
pt_entry = DOS_PARTITION_ENTRY.decode(mbr[pte, PTE_LEN])
|
101
|
+
ra.concat(
|
102
|
+
discover_dos_ext_partitions(
|
103
|
+
disk,
|
104
|
+
pri_base_lba,
|
105
|
+
pt_entry[:start_lba] + pri_base_lba,
|
106
|
+
pnum + 1
|
107
|
+
)
|
108
|
+
) if pt_entry[:start_lba] != 0
|
109
|
+
ra
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|