@@ -142,7 +142,10 @@ func (bs *bootsector) SetSectorsPerCluster(spclus uint16) {
142
142
}
143
143
144
144
// ReservedSectors returns the number of reserved sectors at the beginning of the volume.
145
- // Should be at least 1.
145
+ // Should be at least 1. Reserved sectors include the boot sector, FS information sector and
146
+ // redundant sectors with these first two. The number of reserved sectors is usually
147
+ // 32 for FAT32 systems (~16k for 512 byte sectors).
148
+ // Sectors 6 and 7 are usually the backup boot sector and the FS information sector, respectively.
146
149
func (bs * bootsector ) ReservedSectors () uint16 {
147
150
return binary .LittleEndian .Uint16 (bs .data [bpbRsvdSecCnt :])
148
151
}
@@ -272,21 +275,35 @@ func (bs *bootsector) String() string {
272
275
return string (bs .Appendf (nil , '\n' ))
273
276
}
274
277
278
+ func labelAppend (dst []byte , label string , data []byte , sep byte ) []byte {
279
+ if len (data ) == 0 {
280
+ return dst
281
+ }
282
+ dst = append (dst , label ... )
283
+ dst = append (dst , ':' )
284
+ dst = append (dst , data ... )
285
+ dst = append (dst , sep )
286
+ return dst
287
+ }
288
+
289
+ func labelAppendUint (label string , dst []byte , data uint64 , sep byte ) []byte {
290
+ dst = append (dst , label ... )
291
+ dst = append (dst , ':' )
292
+ dst = strconv .AppendUint (dst , data , 10 )
293
+ dst = append (dst , sep )
294
+ return dst
295
+ }
296
+
297
+ func labelAppendUint32 (label string , dst []byte , data uint32 , sep byte ) []byte {
298
+ return labelAppendUint (label , dst , uint64 (data ), sep )
299
+ }
300
+
275
301
func (bs * bootsector ) Appendf (dst []byte , separator byte ) []byte {
276
302
appendData := func (name string , data []byte , sep byte ) {
277
- if len (data ) == 0 {
278
- return
279
- }
280
- dst = append (dst , name ... )
281
- dst = append (dst , ':' )
282
- dst = append (dst , data ... )
283
- dst = append (dst , sep )
303
+ dst = labelAppend (dst , name , data , sep )
284
304
}
285
305
appendInt := func (name string , data uint32 , sep byte ) {
286
- dst = append (dst , name ... )
287
- dst = append (dst , ':' )
288
- dst = strconv .AppendUint (dst , uint64 (data ), 10 )
289
- dst = append (dst , sep )
306
+ dst = labelAppendUint32 (name , dst , data , sep )
290
307
}
291
308
oem := bs .OEMName ()
292
309
appendData ("OEM" , clipname (oem [:]), separator )
@@ -314,7 +331,128 @@ func (bs *bootsector) Appendf(dst []byte, separator byte) []byte {
314
331
return dst
315
332
}
316
333
317
- // BootCode returns the boot code at the end of the boot sector.
318
- func (bs * bootsector ) BootCode () []byte {
334
+ // bootcode returns the boot code at the end of the boot sector.
335
+ func (bs * bootsector ) bootcode () []byte {
319
336
return bs .data [bsBootCode32 :bs55AA ]
320
337
}
338
+
339
+ // fsinfoSector is the FS Information Sector for FAT32 volumes.
340
+ type fsinfoSector struct {
341
+ data []byte
342
+ }
343
+
344
+ // Signatures returns the 3 signatures at the beginning, middle and end of the sector.
345
+ // Expect them to be 0x41615252, 0x61417272, 0xAA550000 respectively.
346
+ func (fsi * fsinfoSector ) Signatures () (sigStart , sigMid , sigEnd uint32 ) {
347
+ return binary .LittleEndian .Uint32 (fsi .data [0 :]),
348
+ binary .LittleEndian .Uint32 (fsi .data [0x1e4 :]),
349
+ binary .LittleEndian .Uint32 (fsi .data [0x1fc :])
350
+ }
351
+
352
+ // SetSignatures sets the 3 signatures at the beginning, middle and end of the sector.
353
+ // Should be called as follows to set valid signatures expected by most implementations:
354
+ //
355
+ // fsi.SetSignatures(0x41615252, 0x61417272, 0xAA550000)
356
+ func (fsi * fsinfoSector ) SetSignatures (sigStart , sigMid , sigEnd uint32 ) {
357
+ binary .LittleEndian .PutUint32 (fsi .data [0 :], sigStart )
358
+ binary .LittleEndian .PutUint32 (fsi .data [0x1e4 :], sigMid )
359
+ binary .LittleEndian .PutUint32 (fsi .data [0x1fc :], sigEnd )
360
+ }
361
+
362
+ // FreeClusterCount is the last known number of free data clusters on the volume,
363
+ // or 0xFFFFFFFF if unknown. Should be set to 0xFFFFFFFF during format and updated by
364
+ // the operating system later on. Must not be absolutely relied upon to be correct in all scenarios.
365
+ // Before using this value, the operating system should sanity check this value to
366
+ // be less than or equal to the volume's count of clusters.
367
+ func (fsi * fsinfoSector ) FreeClusterCount () uint32 {
368
+ return binary .LittleEndian .Uint32 (fsi .data [0x1e8 :])
369
+ }
370
+
371
+ // SetFreeClusterCount sets the last known number of free data clusters on the volume.
372
+ func (fsi * fsinfoSector ) SetFreeClusterCount (count uint32 ) {
373
+ binary .LittleEndian .PutUint32 (fsi .data [0x1e8 :], count )
374
+ }
375
+
376
+ // LastAllocatedCluster is the number of the most recently known to be allocated data cluster.
377
+ // Should be set to 0xFFFFFFFF during format and updated by the operating system later on.
378
+ // With 0xFFFFFFFF the system should start at cluster 0x00000002. Must not be absolutely
379
+ // relied upon to be correct in all scenarios. Before using this value, the operating system
380
+ // should sanity check this value to be a valid cluster number on the volume.
381
+ func (fsi * fsinfoSector ) LastAllocatedCluster () uint32 {
382
+ return binary .LittleEndian .Uint32 (fsi .data [0x1ec :])
383
+ }
384
+
385
+ // SetLastAllocatedCluster sets the number of the most recently known to be allocated data cluster.
386
+ func (fsi * fsinfoSector ) SetLastAllocatedCluster (cluster uint32 ) {
387
+ binary .LittleEndian .PutUint32 (fsi .data [0x1ec :], cluster )
388
+ }
389
+
390
+ func (fsi * fsinfoSector ) String () string {
391
+ return string (fsi .Appendf (nil , '\n' ))
392
+ }
393
+
394
+ func (fsi * fsinfoSector ) Appendf (dst []byte , separator byte ) []byte {
395
+ lo , mid , hi := fsi .Signatures ()
396
+ if lo != 0x41615252 || mid != 0x61417272 || hi != 0xAA550000 {
397
+ dst = append (dst , "invalid fsi signatures" ... )
398
+ dst = append (dst , separator )
399
+ }
400
+ dst = labelAppendUint32 ("FreeClusterCount" , dst , fsi .FreeClusterCount (), separator )
401
+ dst = labelAppendUint32 ("LastAllocatedCluster" , dst , fsi .LastAllocatedCluster (), separator )
402
+ return dst
403
+ }
404
+
405
+ // fatSector is a File Allocation Table sector.
406
+ type fat32Sector struct {
407
+ data []byte
408
+ }
409
+
410
+ type entry uint32
411
+
412
+ func (fs * fat32Sector ) Entry (idx int ) entry {
413
+ return entry (binary .LittleEndian .Uint32 (fs .data [idx * 4 :]))
414
+ }
415
+
416
+ func (fs * fat32Sector ) SetEntry (idx int , ent entry ) {
417
+ binary .LittleEndian .PutUint32 (fs .data [idx * 4 :], uint32 (ent ))
418
+ }
419
+
420
+ func (fs entry ) Cluster () uint32 {
421
+ return uint32 (fs ) & 0x0FFF_FFFF
422
+ }
423
+
424
+ func (e entry ) Appendf (dst []byte , separator byte ) []byte {
425
+ if e .IsEOF () {
426
+ dst = labelAppendUint32 ("entry" , dst , e .Cluster (), ' ' )
427
+ return append (dst , "EOF" ... )
428
+ }
429
+ return labelAppendUint32 ("entry" , dst , e .Cluster (), separator )
430
+ }
431
+
432
+ func (e entry ) IsEOF () bool {
433
+ return e & 0x0FFF_FFFF >= 0x0FFF_FFF8
434
+ }
435
+
436
+ func (fs * fat32Sector ) String () string {
437
+ return string (fs .AppendfEntries (nil , " -> " , '\n' ))
438
+ }
439
+
440
+ func (fs * fat32Sector ) AppendfEntries (dst []byte , entrySep string , chainSep byte ) []byte {
441
+ var inChain bool
442
+ for i := 0 ; i < len (fs .data )/ 4 ; i ++ {
443
+ entry := fs .Entry (i )
444
+ if entry == 0 {
445
+ break
446
+ }
447
+ dst = entry .Appendf (dst , chainSep )
448
+ if entry .IsEOF () {
449
+ dst = append (dst , chainSep )
450
+ inChain = false
451
+ } else if inChain {
452
+ dst = append (dst , entrySep ... )
453
+ } else {
454
+ inChain = true
455
+ }
456
+ }
457
+ return dst
458
+ }
0 commit comments