/
volume_serial_number.go
168 lines (153 loc) · 3.87 KB
/
volume_serial_number.go
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package volumeSerialNumber
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
const (
FILE_SYSTEM_NTFS = iota
FILE_SYSTEM_FAT12 = FAT_TYPE_FAT12
FILE_SYSTEM_FAT16 = FAT_TYPE_FAT16
FILE_SYSTEM_FAT32 = FAT_TYPE_FAT32
FILE_SYSTEM_EXFAT = FAT_TYPE_EXFAT
)
func GetFileSystem(firstDiskSector []byte) (file_system int, err error) {
if len(firstDiskSector) < 512 {
err = fmt.Errorf(
"disk sector too small: %d, min size is 512",
len(firstDiskSector),
)
return
}
fat_type := getFATType(firstDiskSector)
if fat_type == FAT_TYPE_UNKNOWN {
if isNTFS(firstDiskSector[:]) {
file_system = FILE_SYSTEM_NTFS
} else {
err = fmt.Errorf("unknown file system")
}
} else {
file_system = fat_type
}
return
}
func GetVolumeSerialNumberSize(firstDiskSector []byte) (size int64, err error) {
sizes := map[int]int64{
FILE_SYSTEM_NTFS: 8,
FAT_TYPE_FAT12: 4,
FAT_TYPE_FAT16: 4,
FAT_TYPE_FAT32: 4,
FAT_TYPE_EXFAT: 4,
}
if file_system, err := GetFileSystem(firstDiskSector); err == nil {
size = sizes[file_system]
}
return
}
func GetVolumeSerialNumberAddr(firstDiskSector []byte) (addr int64, err error) {
addrs := map[int]int64{
FILE_SYSTEM_NTFS: 0x48,
FAT_TYPE_FAT12: 0x27,
FAT_TYPE_FAT16: 0x27,
FAT_TYPE_FAT32: 0x43,
FAT_TYPE_EXFAT: 0x64,
}
if file_system, err := GetFileSystem(firstDiskSector); err == nil {
addr = addrs[file_system]
}
return
}
func getVolumeSerialNumberAddrAndSize(
firstDiskSector []byte,
) (addr, size int64, err error) {
if addr, err = GetVolumeSerialNumberAddr(firstDiskSector); err != nil {
return
}
size, err = GetVolumeSerialNumberSize(firstDiskSector)
return
}
func GetVolumeSerialNumber(drive string) (volume_sn uint64, err error) {
var firstSector []byte
if firstSector, err = ReadDriveSector(drive, 0, 512); err != nil {
return
}
addr, size, err := getVolumeSerialNumberAddrAndSize(firstSector)
if err != nil {
return
}
reader := bytes.NewReader(firstSector[:])
reader.Seek(addr, io.SeekStart)
if size == 4 {
var volume_sn32 uint32
binary.Read(reader, binary.LittleEndian, &volume_sn32)
volume_sn = uint64(volume_sn32)
} else {
binary.Read(reader, binary.LittleEndian, &volume_sn)
}
return
}
func fillExFATAdditionalSectors(drive string, sector_size uint64) (err error) {
var sectors []byte
sectors, err = ReadDriveSector(drive, 0, uint64(sector_size*11))
if err != nil {
return
}
var checksum uint32
checksum, err = exFatChecksum(sectors, uint16(sector_size))
if err != nil {
return
}
checksum_sector := make([]byte, sector_size)
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, checksum)
var checksum_bytes = buf.Bytes()
for i := uint64(0); i < sector_size; i++ {
checksum_sector[i] = checksum_bytes[i%4]
}
WriteDriveSector(drive, int64(sector_size)*12, sectors)
WriteDriveSector(drive, int64(sector_size)*11, checksum_sector)
WriteDriveSector(drive, int64(sector_size)*23, checksum_sector)
return
}
func SetVolumeSerialNumber(drive string, volume_sn uint64) (err error) {
var firstSector []byte
if firstSector, err = ReadDriveSector(drive, 0, 512); err != nil {
return
}
addr, size, err := getVolumeSerialNumberAddrAndSize(firstSector)
if err != nil {
return
}
var buf bytes.Buffer
if size == 4 {
binary.Write(&buf, binary.LittleEndian, uint32(volume_sn))
} else {
binary.Write(&buf, binary.LittleEndian, volume_sn)
}
for i := addr; i < addr+size; i++ {
firstSector[i] = buf.Bytes()[i-addr]
}
file_system, err := GetFileSystem(firstSector)
if err != nil {
return
}
err = WriteDriveSector(drive, 0, firstSector)
if file_system == FAT_TYPE_EXFAT {
sectorSize := uint64(1) << firstSector[108]
err = WriteDriveSector(
drive,
int64(sectorSize)*12,
firstSector,
) // Backup Boot Sector
if err != nil {
return
}
// Change checksum and backups
err = fillExFATAdditionalSectors(drive, sectorSize)
if err != nil {
return
}
}
return
}