-
Notifications
You must be signed in to change notification settings - Fork 270
/
ByteBlockDevice.kt
112 lines (92 loc) · 4.11 KB
/
ByteBlockDevice.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package me.jahnen.libaums.core.driver
import java.io.IOException
import java.nio.ByteBuffer
/**
* Simple class which wraps around an existing [BlockDeviceDriver] to enable byte addressing
* of content. Uses byte offsets instead of device oddsets in [ByteBlockDevice.write]
* and [ByteBlockDevice.read]. Uses [BlockDeviceDriver.getBlockSize]
* to calculate device offsets.
*/
open class ByteBlockDevice @JvmOverloads constructor(private val targetBlockDevice: BlockDeviceDriver, private val logicalOffsetToAdd: Long = 0) : BlockDeviceDriver {
override val blockSize: Int
get() = targetBlockDevice.blockSize
override val blocks: Long
get() = targetBlockDevice.blocks
@Throws(IOException::class)
override fun init() {
targetBlockDevice.init()
}
@Throws(IOException::class)
override fun read(byteOffset: Long, dest: ByteBuffer) {
var devOffset = byteOffset / blockSize + logicalOffsetToAdd
// TODO try to make this more efficient by for example making tmp buffer
// global
if (byteOffset % blockSize != 0L) {
//Log.w(TAG, "device offset " + offset + " not a multiple of block size");
val tmp = ByteBuffer.allocate(blockSize)
targetBlockDevice.read(devOffset, tmp)
tmp.clear()
tmp.position((byteOffset % blockSize).toInt())
val limit = Math.min(dest.remaining(), tmp.remaining())
tmp.limit(tmp.position() + limit)
dest.put(tmp)
devOffset++
}
if (dest.remaining() > 0) {
val buffer: ByteBuffer
if (dest.remaining() % blockSize != 0) {
//Log.w(TAG, "we have to round up size to next block sector");
val rounded = blockSize - dest.remaining() % blockSize + dest.remaining()
buffer = ByteBuffer.allocate(rounded)
buffer.limit(rounded)
} else {
buffer = dest
}
targetBlockDevice.read(devOffset, buffer)
if (dest.remaining() % blockSize != 0) {
System.arraycopy(buffer.array(), 0, dest.array(), dest.position(), dest.remaining())
}
dest.position(dest.limit())
}
}
@Throws(IOException::class)
override fun write(byteOffset: Long, src: ByteBuffer) {
var devOffset = byteOffset / blockSize + logicalOffsetToAdd
// TODO try to make this more efficient by for example making tmp buffer
// global
if (byteOffset % blockSize != 0L) {
//Log.w(TAG, "device offset " + offset + " not a multiple of block size");
val tmp = ByteBuffer.allocate(blockSize)
targetBlockDevice.read(devOffset, tmp)
tmp.clear()
tmp.position((byteOffset % blockSize).toInt())
val remaining = Math.min(tmp.remaining(), src.remaining())
tmp.put(src.array(), src.position(), remaining)
src.position(src.position() + remaining)
tmp.clear()
targetBlockDevice.write(devOffset, tmp)
devOffset++
}
if (src.remaining() > 0) {
// TODO try to make this more efficient by for example only allocating
// blockSize and making it global
val buffer: ByteBuffer
if (src.remaining() % blockSize != 0) {
//Log.w(TAG, "we have to round up size to next block sector");
val rounded = blockSize - src.remaining() % blockSize + src.remaining()
buffer = ByteBuffer.allocate(rounded)
buffer.limit(rounded)
// TODO: instead of just writing 0s at the end of the buffer do we need to read what
// is currently on the disk and save that then?
System.arraycopy(src.array(), src.position(), buffer.array(), 0, src.remaining())
src.position(src.limit())
} else {
buffer = src
}
targetBlockDevice.write(devOffset, buffer)
}
}
companion object {
private val TAG = ByteBlockDevice::class.java.simpleName
}
}