4
4
"bytes"
5
5
"encoding/binary"
6
6
"fmt"
7
- "io"
8
7
"os"
8
+
9
+ "golang.org/x/sys/unix"
9
10
)
10
11
11
12
type blkInfo struct {
@@ -28,7 +29,7 @@ func readBlkInfo(path string) (*blkInfo, error) {
28
29
}
29
30
defer r .Close ()
30
31
31
- type probeFn func (r io. ReaderAt ) * blkInfo
32
+ type probeFn func (f * os. File ) * blkInfo
32
33
probes := []probeFn {probeGpt , probeMbr , probeLuks , probeExt4 , probeBtrfs , probeXfs , probeF2fs , probeLvmPv , probeMdraid }
33
34
for _ , fn := range probes {
34
35
blk := fn (r )
@@ -63,17 +64,25 @@ type gptData struct {
63
64
partitions []gptPart
64
65
}
65
66
66
- func probeGpt (r io. ReaderAt ) * blkInfo {
67
+ func probeGpt (f * os. File ) * blkInfo {
67
68
const (
68
69
// https://wiki.osdev.org/GPT
69
- lbaSize = 0x200
70
- tableHeaderOffset = 1 * lbaSize
71
- signatureOffset = 0x0
72
- guidOffset = 0x38
73
- partLocationOffset = 0x48
70
+ tableHeaderOffsetSector = 1
71
+ signatureOffset = 0x0
72
+ guidOffset = 0x38
73
+ partLocationOffset = 0x48
74
+
75
+ defaultSectorSize = 512
74
76
)
77
+
78
+ lbaSize , err := unix .IoctlGetInt (int (f .Fd ()), unix .BLKSSZGET )
79
+ if err != nil {
80
+ lbaSize = defaultSectorSize
81
+ }
82
+ tableHeaderOffset := tableHeaderOffsetSector * int64 (lbaSize )
83
+
75
84
signature := make ([]byte , 8 )
76
- if _ , err := r .ReadAt (signature , tableHeaderOffset + signatureOffset ); err != nil {
85
+ if _ , err := f .ReadAt (signature , tableHeaderOffset + signatureOffset ); err != nil {
77
86
return nil
78
87
}
79
88
if ! bytes .Equal (signature , []byte ("EFI PART" )) {
@@ -82,25 +91,25 @@ func probeGpt(r io.ReaderAt) *blkInfo {
82
91
83
92
buff := make ([]byte , 16 )
84
93
85
- if _ , err := r .ReadAt (buff , tableHeaderOffset + guidOffset ); err != nil {
94
+ if _ , err := f .ReadAt (buff , tableHeaderOffset + guidOffset ); err != nil {
86
95
return nil
87
96
}
88
97
uuid := convertGptUUID (buff )
89
98
90
- if _ , err := r .ReadAt (buff [:16 ], tableHeaderOffset + partLocationOffset ); err != nil {
99
+ if _ , err := f .ReadAt (buff [:16 ], tableHeaderOffset + partLocationOffset ); err != nil {
91
100
return nil
92
101
}
93
102
partLba := binary .LittleEndian .Uint64 (buff [0 :8 ])
94
103
partNum := binary .LittleEndian .Uint32 (buff [8 :12 ])
95
104
partSize := binary .LittleEndian .Uint32 (buff [12 :16 ])
96
- lbaOffset := partLba * lbaSize
105
+ lbaOffset := partLba * uint64 ( lbaSize )
97
106
98
107
var parts []gptPart
99
108
buf := make ([]byte , partSize )
100
109
zeroUUID := make ([]byte , 16 ) // zero UUID used as a marker for unused partitions
101
110
for i := uint32 (0 ); i < partNum ; i ++ {
102
111
start := lbaOffset + uint64 (i * partSize )
103
- if _ , err := r .ReadAt (buf , int64 (start )); err != nil {
112
+ if _ , err := f .ReadAt (buf , int64 (start )); err != nil {
104
113
return nil
105
114
}
106
115
typeGUID := convertGptUUID (buf [0 :0x10 ])
@@ -126,7 +135,7 @@ func convertGptUUID(d []byte) []byte {
126
135
d [10 ], d [11 ], d [12 ], d [13 ], d [14 ], d [15 ]}
127
136
}
128
137
129
- func probeMbr (r io. ReaderAt ) * blkInfo {
138
+ func probeMbr (f * os. File ) * blkInfo {
130
139
const (
131
140
// https://wiki.osdev.org/GPT
132
141
bootSignatureOffset = 0x1fe
@@ -135,51 +144,51 @@ func probeMbr(r io.ReaderAt) *blkInfo {
135
144
idOffset = 0x1b8
136
145
)
137
146
signature := make ([]byte , 2 )
138
- if _ , err := r .ReadAt (signature , bootSignatureOffset ); err != nil {
147
+ if _ , err := f .ReadAt (signature , bootSignatureOffset ); err != nil {
139
148
return nil
140
149
}
141
150
if string (signature ) != bootSignature {
142
151
return nil
143
152
}
144
153
145
- if _ , err := r .ReadAt (signature , diskSignatureOffset ); err != nil {
154
+ if _ , err := f .ReadAt (signature , diskSignatureOffset ); err != nil {
146
155
return nil
147
156
}
148
157
if string (signature ) != "\x00 \x00 " && string (signature ) != "\x5a \x5a " {
149
158
return nil
150
159
}
151
160
152
161
b := make ([]byte , 4 )
153
- if _ , err := r .ReadAt (b , idOffset ); err != nil {
162
+ if _ , err := f .ReadAt (b , idOffset ); err != nil {
154
163
return nil
155
164
}
156
165
id := []byte {b [3 ], b [2 ], b [1 ], b [0 ]} // little endian
157
166
return & blkInfo {format : "mbr" , uuid : id }
158
167
}
159
168
160
- func probeLuks (r io. ReaderAt ) * blkInfo {
169
+ func probeLuks (f * os. File ) * blkInfo {
161
170
// https://gitlab.com/cryptsetup/cryptsetup/-/wikis/LUKS-standard/on-disk-format.pdf
162
171
// both LUKS v1 and v2 have the same magic and UUID offset
163
172
const (
164
173
uuidOffset = 0xa8
165
174
labelV2Offset = 0x18
166
175
)
167
176
magic := make ([]byte , 6 )
168
- if _ , err := r .ReadAt (magic , 0x0 ); err != nil {
177
+ if _ , err := f .ReadAt (magic , 0x0 ); err != nil {
169
178
return nil
170
179
}
171
180
if ! bytes .Equal (magic , []byte ("LUKS\xba \xbe " )) {
172
181
return nil
173
182
}
174
183
175
184
buff := make ([]byte , 2 )
176
- if _ , err := r .ReadAt (buff , 6 ); err != nil {
185
+ if _ , err := f .ReadAt (buff , 6 ); err != nil {
177
186
return nil
178
187
}
179
188
version := int (buff [0 ])<< 8 + int (buff [1 ])
180
189
181
190
data := make ([]byte , 40 )
182
- if _ , err := r .ReadAt (data , uuidOffset ); err != nil {
191
+ if _ , err := f .ReadAt (data , uuidOffset ); err != nil {
183
192
return nil
184
193
}
185
194
uuidStr := string (data [:uuidLen ])
@@ -193,7 +202,7 @@ func probeLuks(r io.ReaderAt) *blkInfo {
193
202
if version == 2 {
194
203
// Only LUKS 2 has label support
195
204
buff := make ([]byte , 48 )
196
- if _ , err := r .ReadAt (buff , labelV2Offset ); err != nil {
205
+ if _ , err := f .ReadAt (buff , labelV2Offset ); err != nil {
197
206
return nil
198
207
}
199
208
label = fixedArrayToString (buff )
@@ -202,7 +211,7 @@ func probeLuks(r io.ReaderAt) *blkInfo {
202
211
return & blkInfo {format : "luks" , uuid : uuid , label : label }
203
212
}
204
213
205
- func probeExt4 (r io. ReaderAt ) * blkInfo {
214
+ func probeExt4 (f * os. File ) * blkInfo {
206
215
const (
207
216
// from fs/ext4/ext4.h
208
217
extSuperblockOffset = 0x400
@@ -213,24 +222,24 @@ func probeExt4(r io.ReaderAt) *blkInfo {
213
222
)
214
223
215
224
magic := make ([]byte , 2 )
216
- if _ , err := r .ReadAt (magic , extSuperblockOffset + extMagicOffset ); err != nil {
225
+ if _ , err := f .ReadAt (magic , extSuperblockOffset + extMagicOffset ); err != nil {
217
226
return nil
218
227
}
219
228
if string (magic ) != extMagic {
220
229
return nil
221
230
}
222
231
uuid := make ([]byte , 16 )
223
- if _ , err := r .ReadAt (uuid , extSuperblockOffset + extUUIDOffset ); err != nil {
232
+ if _ , err := f .ReadAt (uuid , extSuperblockOffset + extUUIDOffset ); err != nil {
224
233
return nil
225
234
}
226
235
label := make ([]byte , 16 )
227
- if _ , err := r .ReadAt (label , extSuperblockOffset + extLabelOffset ); err != nil {
236
+ if _ , err := f .ReadAt (label , extSuperblockOffset + extLabelOffset ); err != nil {
228
237
return nil
229
238
}
230
239
return & blkInfo {format : "ext4" , isFs : true , uuid : uuid , label : fixedArrayToString (label )}
231
240
}
232
241
233
- func probeBtrfs (r io. ReaderAt ) * blkInfo {
242
+ func probeBtrfs (f * os. File ) * blkInfo {
234
243
// https://btrfs.wiki.kernel.org/index.php/On-disk_Format
235
244
const (
236
245
btrfsSuperblockOffset = 0x10000
@@ -241,24 +250,24 @@ func probeBtrfs(r io.ReaderAt) *blkInfo {
241
250
)
242
251
243
252
magic := make ([]byte , 8 )
244
- if _ , err := r .ReadAt (magic , btrfsSuperblockOffset + btrfsMagicOffset ); err != nil {
253
+ if _ , err := f .ReadAt (magic , btrfsSuperblockOffset + btrfsMagicOffset ); err != nil {
245
254
return nil
246
255
}
247
256
if ! bytes .Equal (magic , []byte (btrfsMagic )) {
248
257
return nil
249
258
}
250
259
uuid := make ([]byte , 16 )
251
- if _ , err := r .ReadAt (uuid , btrfsSuperblockOffset + btrfsUUIDOffset ); err != nil {
260
+ if _ , err := f .ReadAt (uuid , btrfsSuperblockOffset + btrfsUUIDOffset ); err != nil {
252
261
return nil
253
262
}
254
263
label := make ([]byte , 256 )
255
- if _ , err := r .ReadAt (label , btrfsSuperblockOffset + btrfsLabelOffset ); err != nil {
264
+ if _ , err := f .ReadAt (label , btrfsSuperblockOffset + btrfsLabelOffset ); err != nil {
256
265
return nil
257
266
}
258
267
return & blkInfo {format : "btrfs" , isFs : true , uuid : uuid , label : fixedArrayToString (label )}
259
268
}
260
269
261
- func probeXfs (r io. ReaderAt ) * blkInfo {
270
+ func probeXfs (f * os. File ) * blkInfo {
262
271
// https://righteousit.wordpress.com/2018/05/21/xfs-part-1-superblock
263
272
const (
264
273
xfsSuperblockOffset = 0x0
@@ -269,24 +278,24 @@ func probeXfs(r io.ReaderAt) *blkInfo {
269
278
)
270
279
271
280
magic := make ([]byte , 4 )
272
- if _ , err := r .ReadAt (magic , xfsSuperblockOffset + xfsMagicOffset ); err != nil {
281
+ if _ , err := f .ReadAt (magic , xfsSuperblockOffset + xfsMagicOffset ); err != nil {
273
282
return nil
274
283
}
275
284
if ! bytes .Equal (magic , []byte (xfsMagic )) {
276
285
return nil
277
286
}
278
287
id := make ([]byte , 16 )
279
- if _ , err := r .ReadAt (id , xfsSuperblockOffset + xfsUUIDOffset ); err != nil {
288
+ if _ , err := f .ReadAt (id , xfsSuperblockOffset + xfsUUIDOffset ); err != nil {
280
289
return nil
281
290
}
282
291
label := make ([]byte , 12 )
283
- if _ , err := r .ReadAt (label , xfsSuperblockOffset + xfsLabelOffset ); err != nil {
292
+ if _ , err := f .ReadAt (label , xfsSuperblockOffset + xfsLabelOffset ); err != nil {
284
293
return nil
285
294
}
286
295
return & blkInfo {format : "xfs" , isFs : true , uuid : id , label : fixedArrayToString (label )}
287
296
}
288
297
289
- func probeF2fs (r io. ReaderAt ) * blkInfo {
298
+ func probeF2fs (f * os. File ) * blkInfo {
290
299
// https://github.com/torvalds/linux/blob/master/include/linux/f2fs_fs.h
291
300
const (
292
301
f2fsSuperblockOffset = 0x400
@@ -297,25 +306,25 @@ func probeF2fs(r io.ReaderAt) *blkInfo {
297
306
)
298
307
299
308
magic := make ([]byte , 4 )
300
- if _ , err := r .ReadAt (magic , f2fsSuperblockOffset + f2fsMagicOffset ); err != nil {
309
+ if _ , err := f .ReadAt (magic , f2fsSuperblockOffset + f2fsMagicOffset ); err != nil {
301
310
return nil
302
311
}
303
312
if ! bytes .Equal (magic , []byte (f2fsMagic )) {
304
313
return nil
305
314
}
306
315
uuid := make ([]byte , 16 )
307
- if _ , err := r .ReadAt (uuid , f2fsSuperblockOffset + f2fsUUIDOffset ); err != nil {
316
+ if _ , err := f .ReadAt (uuid , f2fsSuperblockOffset + f2fsUUIDOffset ); err != nil {
308
317
return nil
309
318
}
310
319
buf := make ([]byte , 512 )
311
- if _ , err := r .ReadAt (buf , f2fsSuperblockOffset + f2fsLabelOffset ); err != nil {
320
+ if _ , err := f .ReadAt (buf , f2fsSuperblockOffset + f2fsLabelOffset ); err != nil {
312
321
return nil
313
322
}
314
323
label := fromUnicode16 (buf , binary .LittleEndian )
315
324
return & blkInfo {format : "f2fs" , isFs : true , uuid : uuid , label : label }
316
325
}
317
326
318
- func probeLvmPv (r io. ReaderAt ) * blkInfo {
327
+ func probeLvmPv (f * os. File ) * blkInfo {
319
328
// https://github.com/libyal/libvslvm/blob/main/documentation/Logical%20Volume%20Manager%20(LVM)%20format.asciidoc
320
329
const (
321
330
lvmHeaderOffset = 0x200
@@ -328,27 +337,27 @@ func probeLvmPv(r io.ReaderAt) *blkInfo {
328
337
)
329
338
330
339
magic := make ([]byte , 8 )
331
- if _ , err := r .ReadAt (magic , lvmHeaderOffset + lvmMagicOffset ); err != nil {
340
+ if _ , err := f .ReadAt (magic , lvmHeaderOffset + lvmMagicOffset ); err != nil {
332
341
return nil
333
342
}
334
343
if ! bytes .Equal (magic , []byte (lvmMagic )) {
335
344
return nil
336
345
}
337
- if _ , err := r .ReadAt (magic , lvmHeaderOffset + lvmTypeMagicOffset ); err != nil {
346
+ if _ , err := f .ReadAt (magic , lvmHeaderOffset + lvmTypeMagicOffset ); err != nil {
338
347
return nil
339
348
}
340
349
if ! bytes .Equal (magic , []byte (lvmTypeMagic )) {
341
350
return nil
342
351
}
343
352
344
353
buf := make ([]byte , 4 )
345
- if _ , err := r .ReadAt (buf , lvmHeaderOffset + lvmHeaderSizeOffset ); err != nil {
354
+ if _ , err := f .ReadAt (buf , lvmHeaderOffset + lvmHeaderSizeOffset ); err != nil {
346
355
return nil
347
356
}
348
357
headerSize := binary .LittleEndian .Uint32 (buf )
349
358
350
359
uuid := make ([]byte , 32 )
351
- if _ , err := r .ReadAt (uuid , int64 (lvmHeaderOffset + headerSize + lvmUUIDOffset )); err != nil {
360
+ if _ , err := f .ReadAt (uuid , int64 (lvmHeaderOffset + headerSize + lvmUUIDOffset )); err != nil {
352
361
return nil
353
362
}
354
363
return & blkInfo {format : "lvm" , isFs : true , uuid : uuid }
@@ -369,7 +378,7 @@ type mdraidData struct {
369
378
level uint32
370
379
}
371
380
372
- func probeMdraid (r io. ReaderAt ) * blkInfo {
381
+ func probeMdraid (f * os. File ) * blkInfo {
373
382
// https://raid.wiki.kernel.org/index.php/RAID_superblock_formats
374
383
const (
375
384
mdraidHeaderOffset = 0x1000
@@ -381,28 +390,28 @@ func probeMdraid(r io.ReaderAt) *blkInfo {
381
390
)
382
391
383
392
magic := make ([]byte , 4 )
384
- if _ , err := r .ReadAt (magic , mdraidHeaderOffset + mdraidMagicOffset ); err != nil {
393
+ if _ , err := f .ReadAt (magic , mdraidHeaderOffset + mdraidMagicOffset ); err != nil {
385
394
return nil
386
395
}
387
396
if binary .LittleEndian .Uint32 (magic ) != mdraidMagic {
388
397
return nil
389
398
}
390
399
391
400
version := make ([]byte , 4 )
392
- if _ , err := r .ReadAt (version , mdraidHeaderOffset + mdraidVersioOffset ); err != nil {
401
+ if _ , err := f .ReadAt (version , mdraidHeaderOffset + mdraidVersioOffset ); err != nil {
393
402
return nil
394
403
}
395
404
if binary .LittleEndian .Uint32 (version ) != 1 {
396
405
return nil
397
406
}
398
407
399
408
uuid := make ([]byte , 16 )
400
- if _ , err := r .ReadAt (uuid , int64 (mdraidHeaderOffset + mdraidUUIDOffset )); err != nil {
409
+ if _ , err := f .ReadAt (uuid , int64 (mdraidHeaderOffset + mdraidUUIDOffset )); err != nil {
401
410
return nil
402
411
}
403
412
404
413
levelBuff := make ([]byte , 4 )
405
- if _ , err := r .ReadAt (levelBuff , int64 (mdraidHeaderOffset + mdraidLevelOffset )); err != nil {
414
+ if _ , err := f .ReadAt (levelBuff , int64 (mdraidHeaderOffset + mdraidLevelOffset )); err != nil {
406
415
return nil
407
416
}
408
417
level := binary .LittleEndian .Uint32 (levelBuff )
0 commit comments