disk 0.7.1 → 0.8.8
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.
- package/{LICENSE.md → LICENSE} +10 -9
- package/README.md +111 -78
- package/dist/cli.js +573 -0
- package/dist/index.cjs +421 -0
- package/dist/index.d.cts +1144 -0
- package/dist/index.d.ts +1144 -0
- package/dist/index.js +372 -0
- package/package.json +41 -37
- package/lib/disk.js +0 -379
- package/lib/partition.js +0 -117
package/lib/disk.js
DELETED
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
var debug = require( 'debug' )( 'disk' )
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Disk
|
|
5
|
-
* @class
|
|
6
|
-
* @param {BlockDevice} device
|
|
7
|
-
* @return {Disk}
|
|
8
|
-
*/
|
|
9
|
-
function Disk( device ) {
|
|
10
|
-
|
|
11
|
-
if( !(this instanceof Disk) )
|
|
12
|
-
return new Disk( device )
|
|
13
|
-
|
|
14
|
-
/** @type {BlockDevice} Device */
|
|
15
|
-
this.device = device
|
|
16
|
-
/** @type {MBR} Master Boot Record */
|
|
17
|
-
this.mbr = null
|
|
18
|
-
/** @type {GPT} GUID Partition Table */
|
|
19
|
-
this.gpt = null
|
|
20
|
-
/** @type {BlockDevice.Partition[]} Partitions */
|
|
21
|
-
this.partitions = []
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Master Boot Record
|
|
27
|
-
* @see https://github.com/jhermsmeier/node-mbr
|
|
28
|
-
* @constructor
|
|
29
|
-
*/
|
|
30
|
-
Disk.MBR = require( 'mbr' )
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* GUID Partition Table
|
|
34
|
-
* @see https://github.com/jhermsmeier/node-gpt
|
|
35
|
-
* @constructor
|
|
36
|
-
*/
|
|
37
|
-
Disk.GPT = require( 'gpt' )
|
|
38
|
-
|
|
39
|
-
Disk.Partition = require( './partition' )
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Disk prototype
|
|
43
|
-
* @type {Object}
|
|
44
|
-
*/
|
|
45
|
-
Disk.prototype = {
|
|
46
|
-
|
|
47
|
-
constructor: Disk,
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Opens a device handle and attempts
|
|
51
|
-
* to read structures from disk
|
|
52
|
-
* @param {Function} callback
|
|
53
|
-
*/
|
|
54
|
-
open: function( callback ) {
|
|
55
|
-
|
|
56
|
-
var done = callback.bind( this )
|
|
57
|
-
|
|
58
|
-
this.mbr = null
|
|
59
|
-
this.gpt = null
|
|
60
|
-
this.partitions.length = 0
|
|
61
|
-
|
|
62
|
-
debug( 'open' )
|
|
63
|
-
|
|
64
|
-
var tasks = [
|
|
65
|
-
// Step 1: Open handle
|
|
66
|
-
( next ) => {
|
|
67
|
-
debug( 'open:device' )
|
|
68
|
-
this.device.open( next )
|
|
69
|
-
},
|
|
70
|
-
// Step 2: Read Master Boot Record
|
|
71
|
-
( next ) => {
|
|
72
|
-
debug( 'open:read_mbr' )
|
|
73
|
-
this.readMBR( next )
|
|
74
|
-
},
|
|
75
|
-
// Step 3: Read GUID Partition Table Header
|
|
76
|
-
// Step 4: Read GUID Partition Table
|
|
77
|
-
( next ) => {
|
|
78
|
-
debug( 'open:read_gpt' )
|
|
79
|
-
this.readGPT(( error, gpt ) => {
|
|
80
|
-
this.gpt = gpt
|
|
81
|
-
next( error )
|
|
82
|
-
})
|
|
83
|
-
},
|
|
84
|
-
// Step 5: Partitions
|
|
85
|
-
( next ) => {
|
|
86
|
-
|
|
87
|
-
debug( 'open:init_partitions' )
|
|
88
|
-
|
|
89
|
-
var addPartition = ( partition ) => {
|
|
90
|
-
if( partition.firstLBA === 0 && partition.lastLBA === 0 )
|
|
91
|
-
return void 0
|
|
92
|
-
var part = this.partition( partition.firstLBA, partition.lastLBA )
|
|
93
|
-
this.partitions.push( part )
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if( this.gpt ) {
|
|
97
|
-
this.gpt.partitions.forEach( addPartition )
|
|
98
|
-
} else if( this.mbr ) {
|
|
99
|
-
this.mbr.partitions.forEach( addPartition )
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
next()
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
]
|
|
106
|
-
|
|
107
|
-
var run = ( error ) => {
|
|
108
|
-
if( error ) return callback.call( this, error )
|
|
109
|
-
var task = tasks.shift()
|
|
110
|
-
task ? task( run ) : callback.call( this )
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
run()
|
|
114
|
-
|
|
115
|
-
return this
|
|
116
|
-
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Closes the device handle
|
|
121
|
-
* @param {Function} callback
|
|
122
|
-
*/
|
|
123
|
-
close: function( callback ) {
|
|
124
|
-
var done = callback.bind( this )
|
|
125
|
-
debug( 'close' )
|
|
126
|
-
this.device.close( done )
|
|
127
|
-
return this
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Create a bound-checked slice of the disk
|
|
132
|
-
* @param {Number} fromLBA
|
|
133
|
-
* @param {Number} toLBA
|
|
134
|
-
* @return {Disk.Partition}
|
|
135
|
-
*/
|
|
136
|
-
partition: function( fromLBA, toLBA ) {
|
|
137
|
-
return new Disk.Partition( this.device, {
|
|
138
|
-
firstLBA: fromLBA,
|
|
139
|
-
lastLBA: toLBA,
|
|
140
|
-
})
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Returns the EFI System Partition entry, if available
|
|
145
|
-
* @return {MBR.Partition}
|
|
146
|
-
*/
|
|
147
|
-
getEFIPart: function() {
|
|
148
|
-
return this.mbr && this.mbr.getEFIPart()
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Reads the Master Boot Record from disk
|
|
153
|
-
* @param {Function} callback
|
|
154
|
-
*/
|
|
155
|
-
readMBR: function( callback ) {
|
|
156
|
-
|
|
157
|
-
var self = this
|
|
158
|
-
var done = callback.bind( this )
|
|
159
|
-
|
|
160
|
-
this.device.readBlocks( 0, 1, function( error, buffer ) {
|
|
161
|
-
|
|
162
|
-
if( error != null ) {
|
|
163
|
-
return done( error, null )
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
self.mbr = Disk.MBR.parse( buffer )
|
|
168
|
-
} catch( e ) {
|
|
169
|
-
// TODO: Use flags to communicate
|
|
170
|
-
// what should be notices / warnings
|
|
171
|
-
return done( null, null )
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
done( null, self.mbr )
|
|
175
|
-
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
return this
|
|
179
|
-
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Writes the Master Boot Record to disk
|
|
184
|
-
* @param {Function} callback
|
|
185
|
-
*/
|
|
186
|
-
writeMBR: function( callback ) {
|
|
187
|
-
|
|
188
|
-
var done = callback.bind( this )
|
|
189
|
-
var buffer = this.mbr.buffer
|
|
190
|
-
|
|
191
|
-
this.device.writeBlocks( 0, buffer, done )
|
|
192
|
-
|
|
193
|
-
return this
|
|
194
|
-
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Reads the GUID Partition Table from disk
|
|
199
|
-
* @param {Function} callback
|
|
200
|
-
*/
|
|
201
|
-
readGPT: function( lba, callback ) {
|
|
202
|
-
|
|
203
|
-
var argv = Array.prototype.slice.call( arguments )
|
|
204
|
-
|
|
205
|
-
callback = argv.pop()
|
|
206
|
-
lba = argv.pop()
|
|
207
|
-
|
|
208
|
-
var self = this
|
|
209
|
-
var done = callback.bind( this )
|
|
210
|
-
var gpt = null
|
|
211
|
-
|
|
212
|
-
if( this.mbr == null ) {
|
|
213
|
-
// TODO: Use flags to communicate what should be notices / warnings
|
|
214
|
-
// new Error( 'Missing Master Boot Record' )
|
|
215
|
-
return done( null, null )
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if( lba == null ) {
|
|
219
|
-
var efiPart = this.getEFIPart()
|
|
220
|
-
if( efiPart ) {
|
|
221
|
-
lba = efiPart.firstLBA
|
|
222
|
-
} else {
|
|
223
|
-
return done( null, null )
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
debug( 'read_gpt', lba )
|
|
228
|
-
|
|
229
|
-
// Step 1: Read GUID Partition Table Header
|
|
230
|
-
this.device.readBlocks( lba, lba + 1, function( error, buffer ) {
|
|
231
|
-
|
|
232
|
-
if( error != null ) {
|
|
233
|
-
debug( 'read_gpt:error', e.message )
|
|
234
|
-
return done( error, null )
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// TODO: Use flags to communicate
|
|
238
|
-
// what should be notices / warnings
|
|
239
|
-
try {
|
|
240
|
-
gpt = new Disk.GPT()
|
|
241
|
-
gpt.parseHeader( buffer )
|
|
242
|
-
} catch( e ) {
|
|
243
|
-
debug( 'read_gpt:header:error', e.message )
|
|
244
|
-
return done( null, null )
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
debug( 'read_gpt:header', gpt )
|
|
248
|
-
|
|
249
|
-
// Step 2: Read GUID Partition Table
|
|
250
|
-
self.device.readBlocks(
|
|
251
|
-
gpt.tableOffset,
|
|
252
|
-
gpt.tableOffset + ( gpt.tableSize / self.device.blockSize ),
|
|
253
|
-
function( error, buffer ) {
|
|
254
|
-
|
|
255
|
-
if( error != null ) {
|
|
256
|
-
return done( error, null )
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
gpt.parseTable( buffer )
|
|
261
|
-
} catch( e ) {
|
|
262
|
-
// TODO: Use flags to communicate
|
|
263
|
-
// what should be notices / warnings
|
|
264
|
-
debug( 'read_gpt:table:error', e.message )
|
|
265
|
-
return done( e, null )
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
debug( 'read_gpt:table', gpt.partitions )
|
|
269
|
-
|
|
270
|
-
return done( null, gpt )
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
return this
|
|
278
|
-
|
|
279
|
-
},
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Writes the GUID Partition Table to disk
|
|
283
|
-
* @param {Function} callback
|
|
284
|
-
*/
|
|
285
|
-
writeGPT: function( callback ) {
|
|
286
|
-
|
|
287
|
-
var done = callback.bind( this )
|
|
288
|
-
|
|
289
|
-
if( this.gpt == null || !(this.gpt instanceof Disk.GPT) ) {
|
|
290
|
-
return done( new Error( 'Invalid or missing GPT' ) )
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
var headerBuffer = this.gpt.toBuffer( true, false )
|
|
294
|
-
var tableBuffer = this.gpt.toBuffer( false, true )
|
|
295
|
-
|
|
296
|
-
var header = Buffer.alloc( this.device.blockSize, 0 )
|
|
297
|
-
var tableHeader = Buffer.alloc( this.device.blockSize, 0 )
|
|
298
|
-
var table = Buffer.alloc( this.device.blockSize * 31, 0 )
|
|
299
|
-
|
|
300
|
-
headerBuffer.copy( header )
|
|
301
|
-
tableBuffer.slice( 0, this.gpt.entrySize * 4 ).copy( tableHeader )
|
|
302
|
-
tableBuffer.slice( this.gpt.entrySize * 4 ).copy( table )
|
|
303
|
-
|
|
304
|
-
// Last LBA of device (not user-space!)
|
|
305
|
-
var lastLBA = ( this.device.size / this.device.blockSize ) - 1
|
|
306
|
-
|
|
307
|
-
var tasks = [
|
|
308
|
-
// Write the GPT header
|
|
309
|
-
( next ) => {
|
|
310
|
-
var address = 1
|
|
311
|
-
this.device.writeBlocks( address, header, next )
|
|
312
|
-
},
|
|
313
|
-
// Write the first 4 partition table entries
|
|
314
|
-
( next ) => {
|
|
315
|
-
var address = 2
|
|
316
|
-
this.device.writeBlocks( address, tableHeader, next )
|
|
317
|
-
},
|
|
318
|
-
// Write partition table entries 5-128
|
|
319
|
-
( next ) => {
|
|
320
|
-
var address = 3
|
|
321
|
-
this.device.writeBlocks( address, table, next )
|
|
322
|
-
},
|
|
323
|
-
// Write the backup GPT header
|
|
324
|
-
( next ) => {
|
|
325
|
-
var address = this.gpt.backupLBA || lastLBA - 1
|
|
326
|
-
this.device.writeBlocks( address, header, next )
|
|
327
|
-
},
|
|
328
|
-
// Write the first 4 backup partition table entries
|
|
329
|
-
( next ) => {
|
|
330
|
-
var address = this.gpt.backupLBA ?
|
|
331
|
-
this.gpt.backupLBA - 34 : lastLBA - 34
|
|
332
|
-
this.device.writeBlocks( address, tableHeader, next )
|
|
333
|
-
},
|
|
334
|
-
// Write backup partition table entries 5-128
|
|
335
|
-
( next ) => {
|
|
336
|
-
var address = this.gpt.backupLBA ?
|
|
337
|
-
this.gpt.backupLBA - 33 : lastLBA - 33
|
|
338
|
-
this.device.writeBlocks( address, table, next )
|
|
339
|
-
},
|
|
340
|
-
]
|
|
341
|
-
|
|
342
|
-
var run = ( error ) => {
|
|
343
|
-
if( error ) return callback.call( this, error )
|
|
344
|
-
var task = tasks.shift()
|
|
345
|
-
task ? task( run ) : callback.call( this )
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
run()
|
|
349
|
-
|
|
350
|
-
return this
|
|
351
|
-
},
|
|
352
|
-
|
|
353
|
-
verifyGPT: function( callback ) {
|
|
354
|
-
|
|
355
|
-
var self = this
|
|
356
|
-
var done = callback.bind( this )
|
|
357
|
-
|
|
358
|
-
if( this.gpt == null ) {
|
|
359
|
-
debug( 'verify_gpt:missing' )
|
|
360
|
-
done( new Error( 'Missing GPT' ) )
|
|
361
|
-
return this
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
debug( 'verify_gpt', this.gpt.backupLBA )
|
|
365
|
-
|
|
366
|
-
this.readGPT( this.gpt.backupLBA, function( error, backupGPT ) {
|
|
367
|
-
error = error || self.gpt.verify( backupGPT )
|
|
368
|
-
debug( 'verify_gpt:error', error.message )
|
|
369
|
-
done( error, backupGPT )
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
return this
|
|
373
|
-
|
|
374
|
-
},
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Exports
|
|
379
|
-
module.exports = Disk
|
package/lib/partition.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
var debug = require( 'debug' )( 'disk:partition' )
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Disk Partition
|
|
5
|
-
* @constructor
|
|
6
|
-
* @memberOf Disk
|
|
7
|
-
* @return {Partition}
|
|
8
|
-
*/
|
|
9
|
-
function Partition( device, options ) {
|
|
10
|
-
|
|
11
|
-
if( !(this instanceof Partition) )
|
|
12
|
-
return new Partition( device, options )
|
|
13
|
-
|
|
14
|
-
this.device = device
|
|
15
|
-
|
|
16
|
-
this.firstLBA = options.firstLBA || 0
|
|
17
|
-
this.lastLBA = options.lastLBA || -1
|
|
18
|
-
|
|
19
|
-
debug( 'new', this.firstLBA, this.lastLBA )
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Partition Prototype
|
|
25
|
-
* @type {Object}
|
|
26
|
-
* @ignore
|
|
27
|
-
*/
|
|
28
|
-
Partition.prototype = {
|
|
29
|
-
|
|
30
|
-
constructor: Partition,
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Determine whether a LBA is within the partition's bounds
|
|
34
|
-
* @internal
|
|
35
|
-
* @param {Number} lba
|
|
36
|
-
* @return {Boolean}
|
|
37
|
-
*/
|
|
38
|
-
__OOB: function( lba ) {
|
|
39
|
-
return lba < this.firstLBA ||
|
|
40
|
-
lba > this.lastLBA
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
get blockSize() {
|
|
44
|
-
return this.device.blockSize
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
get sectors() {
|
|
48
|
-
return this.lastLBA - this.firstLBA
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
get size() {
|
|
52
|
-
return this.sectors * this.blockSize
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Read from a LBA to another LBA
|
|
57
|
-
* @param {Number} from
|
|
58
|
-
* @param {Number} to
|
|
59
|
-
* @param {Buffer} [buffer]
|
|
60
|
-
* @param {Function} callback
|
|
61
|
-
* @return {Partition}
|
|
62
|
-
*/
|
|
63
|
-
readBlocks: function( from, to, buffer, callback ) {
|
|
64
|
-
|
|
65
|
-
if( typeof buffer === 'function' ) {
|
|
66
|
-
callback = buffer
|
|
67
|
-
buffer = null
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
callback = callback.bind( this )
|
|
71
|
-
|
|
72
|
-
from = from + this.firstLBA
|
|
73
|
-
to = to + this.firstLBA
|
|
74
|
-
|
|
75
|
-
if( this.__OOB( from ) || this.__OOB( to ) ) {
|
|
76
|
-
var msg = 'Block address out of bounds: ' +
|
|
77
|
-
'[' + from + ',' + to + '] not in range ' +
|
|
78
|
-
'[' + this.firstLBA + ',' + this.lastLBA + ']'
|
|
79
|
-
return callback( new Error( msg ) )
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
this.device.readBlocks( from, to, buffer, callback )
|
|
83
|
-
|
|
84
|
-
return this
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Write a buffer to a given LBA
|
|
90
|
-
* @param {Number} from
|
|
91
|
-
* @param {Buffer} [buffer]
|
|
92
|
-
* @param {Function} callback
|
|
93
|
-
* @return {Partition}
|
|
94
|
-
*/
|
|
95
|
-
writeBlocks: function( from, buffer, callback ) {
|
|
96
|
-
|
|
97
|
-
callback = callback.bind( this )
|
|
98
|
-
|
|
99
|
-
from = from + this.firstLBA
|
|
100
|
-
|
|
101
|
-
if( this.__OOB( from ) ) {
|
|
102
|
-
var msg = 'Block address out of bounds: ' +
|
|
103
|
-
'[' + from + ',' + to + '] not in range ' +
|
|
104
|
-
'[' + this.firstLBA + ',' + this.lastLBA + ']'
|
|
105
|
-
return callback( new Error( msg ) )
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.device.writeBlocks( from, buffer, callback )
|
|
109
|
-
|
|
110
|
-
return this
|
|
111
|
-
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Exports
|
|
117
|
-
module.exports = Partition
|