-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathfdisk.py
160 lines (135 loc) · 4.51 KB
/
fdisk.py
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
#!/usr/bin/env python
import argparse
import sys
from pathlib import Path
import cstruct
UNITS = ['B', 'K', 'M', 'G', 'T']
SECTOR_SIZE = 512
TYPES = {
0x00: "Empty",
0x01: "FAT12",
0x05: "Extended",
0x06: "FAT16",
0x07: "HPFS/NTFS/exFAT",
0x0B: "W95 FAT32",
0x0C: "W95 FAT32 (LBA)",
0x0E: "W95 FAT16 (LBA)",
0x0F: "W95 extended (LBA)",
0x11: "Hidden FAT12",
0x14: "Hidden FAT16 <32M",
0x16: "Hidden FAT16",
0x17: "Hidden HPFS/NTFS",
0x1B: "Hidden W95 FAT32",
0x1C: "Hidden W95 FAT32 (LBA)",
0x1E: "Hidden W95 FAT16 (LBA)",
0x27: "Hidden NTFS WinRE",
0x81: "Minix / old Linux",
0x82: "Linux swap / Solaris",
0x83: "Linux",
0x85: "Linux extended",
0x86: "NTFS volume set",
0x87: "NTFS volume set",
0x88: "Linux plaintext",
0x8E: "Linux LVM",
0x9F: "BSD/OS",
0xA5: "FreeBSD",
0xA6: "OpenBSD",
0xAF: "HFS / HFS+",
0xEA: "Linux extended boot",
0xEE: "GPT",
0xEF: "EFI (FAT-12/16/32)",
0xF2: "DOS secondary",
0xFB: "VMware VMFS",
0xFC: "VMware VMKCORE",
0xFD: "Linux raid autodetect",
}
class Position(cstruct.MemCStruct):
__byte_order__ = cstruct.LITTLE_ENDIAN
__def__ = """
struct {
unsigned char head;
unsigned char sector;
unsigned char cyl;
}
"""
class Partition(cstruct.MemCStruct):
__byte_order__ = cstruct.LITTLE_ENDIAN
__def__ = """
#define ACTIVE_FLAG 0x80
typedef struct Position Position;
struct {
unsigned char status; /* 0x80 - active */
Position start;
unsigned char partition_type;
Position end;
unsigned int start_sect; /* starting sector counting from 0 */
unsigned int sectors; /* nr of sectors in partition */
}
"""
@property
def bootable_str(self):
return "*" if (self.status & cstruct.getdef("ACTIVE_FLAG")) else " "
@property
def end_sect(self):
return self.start_sect + self.sectors - 1
@property
def part_size_str(self):
val = self.sectors * SECTOR_SIZE
for unit in UNITS:
if val < 1000:
break
val = int(val / 1000)
return f"{val}{unit}"
@property
def part_type_str(self):
return TYPES.get(self.partition_type, "")
def __str__(self):
return f"{self.bootable_str} {self.start_sect:>10} {self.end_sect:>8} {self.sectors:>8} {self.part_size_str:>4} {self.partition_type:02x} {self.part_type_str}"
class MBR(cstruct.MemCStruct):
__byte_order__ = cstruct.LITTLE_ENDIAN
__def__ = """
#define MBR_SIZE 512
#define MBR_DISK_SIGNATURE_SIZE 4
#define MBR_USUALY_NULLS_SIZE 2
#define MBR_SIGNATURE_SIZE 2
#define MBR_BOOT_SIGNATURE 0xaa55
#define MBR_PARTITIONS_NUM 4
#define MBR_PARTITIONS_SIZE (sizeof(Partition) * MBR_PARTITIONS_NUM)
#define MBR_UNUSED_SIZE (MBR_SIZE - MBR_DISK_SIGNATURE_SIZE - MBR_USUALY_NULLS_SIZE - MBR_PARTITIONS_SIZE - MBR_SIGNATURE_SIZE)
typedef struct Partition Partition;
struct {
char unused[MBR_UNUSED_SIZE];
unsigned char disk_signature[MBR_DISK_SIGNATURE_SIZE];
unsigned char usualy_nulls[MBR_USUALY_NULLS_SIZE];
Partition partitions[MBR_PARTITIONS_NUM];
uint16 signature;
}
"""
@property
def disk_signature_str(self):
return "".join(reversed([f"{x:02x}" for x in self.disk_signature]))
def print_info(self):
print(f"Sector size: {cstruct.getdef('MBR_SIZE')}")
if self.signature != cstruct.getdef('MBR_BOOT_SIGNATURE'):
print("Invalid MBR signature")
print(f"Disk identifier: 0x{self.disk_signature_str}")
print()
print("Device Boot Start End Sectors Size Id Type")
for i, partition in enumerate(self.partitions):
if partition.sectors:
print(f"part{i:<2} {partition}")
def main():
parser = argparse.ArgumentParser(description="Display or manipulate a disk partition table.")
parser.add_argument("disk")
args = parser.parse_args()
try:
with Path(args.disk).open("rb") as f:
mbr = MBR()
data = f.read(len(mbr))
mbr.unpack(data)
mbr.print_info()
except (IOError, OSError) as ex:
print(ex)
sys.exit(1)
if __name__ == "__main__":
main()