Skip to content

Commit

Permalink
MBR supports 4K sectors
Browse files Browse the repository at this point in the history
Fixed code that prevented 4K sectors in MBR partitions up to 16 TB
  • Loading branch information
maxpat78 committed Jun 20, 2023
1 parent 3f93fb4 commit 3cf4bce
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 22 deletions.
4 changes: 2 additions & 2 deletions FATtools/Volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def vopen(path, mode='rb', what='auto'):
if what == 'disk':
return d
# Tries to access a partition
mbr = MBR(d.read(PHYS_SECTOR), disksize=d.size)
mbr = MBR(d.read(PHYS_SECTOR), disksize=d.size, sector=PHYS_SECTOR)
if DEBUG&2: log("Opened MBR: %s", mbr)
valid_mbr=1
n = mbr.partitions[0].size()
Expand Down Expand Up @@ -114,7 +114,7 @@ def vopen(path, mode='rb', what='auto'):
extpart = part
while wanted <=partition:
bs = extpart.read(PHYS_SECTOR)
ebr = MBR(bs, disksize=d.size) # reads Extended Boot Record
ebr = MBR(bs, disksize=d.size, sector=PHYS_SECTOR) # reads Extended Boot Record
if DEBUG&2: log("Opened EBR: %s", ebr)
if ebr.wBootSignature != 0xAA55:
if DEBUG&2: log("Invalid Extended Boot Record")
Expand Down
5 changes: 3 additions & 2 deletions FATtools/mkfat.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
cluster size wanted by user, from 2^9 to 2^16 bytes. If sector size is 4096
bytes, size is up to 2^18 (256K). If not specified, the best value is
selected automatically.
selected automatically. Windows 11 seems able to read/write a FAT32 volume
formatted with a 512K cluster, the maximum size a boot sector can record.
fat_no_64K_cluster
Expand Down Expand Up @@ -130,7 +131,7 @@ def fat_mkfs(stream, size, sector=512, params={}):
# Calculate possible combinations for each FAT and cluster size
for fat_slot_size in fat_slot_sizes:
allowed = {} # {cluster_size : fsinfo}
for i in range(9, max_cluster): # cluster sizes 0.5K...32K (64K)
for i in range(9, max_cluster): # cluster sizes 0.5K...32K (64K) or 128K-256K with 4Kn sectors
fsinfo = {}
root_entries = params.get('root_entries', {12:224,16:512,32:0}[fat_slot_size])
root_entries_size = (root_entries*32)+(sector-1)//sector # translate into sectors
Expand Down
6 changes: 3 additions & 3 deletions FATtools/partutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def __init__ (self, s=None, offset=0, stream=None, disksize=0, sector=512):
for k, v in list(self._kv.items()):
self._vk[v[0]] = k
for i in range(4):
self.partitions += [MBR_Partition(self._buf, index=i)]
self.partitions += [MBR_Partition(self._buf, index=i, sector=sector)]
# try to detect disk geometry
ret = self.partitions[-1].geometry()
if ret == -1: continue
Expand Down Expand Up @@ -232,7 +232,7 @@ def mkpart(self, offset, size):
c = size // self._sector // (h*s)
if DEBUG&1: log("mkpart: CHS geometry %d-%d-%d (disk based)",c,h,s)
if c > 1024 or not self.heads_per_cyl:
c, h, s = get_geometry(size)
c, h, s = get_geometry(size, self._sector)
self.heads_per_cyl = h
self.sectors_per_cyl = s
if DEBUG&1: log("mkpart: CHS geometry %d-%d-%d (calculated)",c,h,s)
Expand Down Expand Up @@ -275,7 +275,7 @@ def partition(disk, fmt='gpt', options={}):
if options.get('lba_mode',0):
mbr.setpart(0, 1<<20, part_size-(1<<20)-33*SECTOR)
else:
mbr.setpart(0, mbr.sectors_per_cyl*512, part_size-mbr.sectors_per_cyl*SECTOR)
mbr.setpart(0, mbr.sectors_per_cyl*SECTOR, part_size-mbr.sectors_per_cyl*SECTOR)
if options.get('mbr_type'):
mbr.partitions[0].bType = options.get('mbr_type')
else:
Expand Down
25 changes: 12 additions & 13 deletions FATtools/scripts/mkfat.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ def create_parser(parser_create_fn=argparse.ArgumentParser,parser_create_args=No
par.add_argument('fs',help="The image file or disk device to write to",metavar="FS")
par.add_argument("-t", "--fstype", dest="fs_type", help="try to apply the specified File System between FAT12, FAT16, FAT32 or EXFAT. Default: based on medium size.", metavar="FSTYPE")
par.add_argument("-c", "--cluster", dest="cluster_size", help="force a specified cluster size between 512, 1024, 2048, 4096, 8192, 16384, 32768 (since DOS) or 65536 bytes (Windows NT+; 128K and 256K clusters are allowed with 4K sectors) for FAT. exFAT permits clusters up to 32M. Default: based on medium size. Accepts 'k' and 'm' postfix for Kibibytes and Mebibytes.", metavar="CLUSTER")
par.add_argument("-p", "--partition", dest="part_type", help="create a single partition from all disk space before formatting. Accepts MBR, GPT or MBR_OLD (2 GB max, MS-DOS <7.1 compatible)", metavar="PARTTYPE")
par.add_argument("-p", "--partition", dest="part_type", help="create a single partition from all disk space before formatting. Accepts MBR (up to 2 TB; 16 TB with 4K sectors), GPT or MBR_OLD (2 GB max, MS-DOS <7.1 compatible)", metavar="PARTTYPE")
par.add_argument("--fat32compat", action="store_true", dest="fat32_compat", help="FAT32 is applied in Windows XP compatibility mode, i.e. only if 65525 < clusters < 4177918 (otherwise: 2^28-11 clusters allowed)")
par.add_argument("--no-fat12", action="store_true", dest="fat12_disable", help="FAT12 is never applied to small hard disks (~127/254M on DOS/NT systems)")
par.add_argument("--no-64k-cluster", action="store_true", dest="disable_64k", help="do not use 64K clusters (DOS compatibility)")
par.add_argument("--no-64k-cluster", action="store_true", dest="disable_64k", help="cluster size is limited to 32K (DOS compatibility)")
return par

def call(args):
Expand All @@ -26,6 +26,7 @@ def call(args):

SECTOR = 512
if dsk.type() == 'VHDX' and dsk.metadata.physical_sector_size == 4096: SECTOR = 4096
opts={'phys_sector':SECTOR}

# Windows 10 Shell (or START command) happily auto-mounts a VHD ONLY IF partitioned and formatted
# However, a valid VHD is always mounted and can be handled with Diskpart (GUI/CUI)
Expand All @@ -37,24 +38,23 @@ def call(args):
print("Creating a %s partition with all disk space..."%t.upper())
if t in ('mbr', 'mbr_old'):
if dsk.size > (2<<40):
print('You MUST use GPT partition scheme with disks >2TB!')
if SECTOR==512:
print('You MUST use GPT partition scheme with disks >2TB!')
sys.exit(1)
opts['lba_mode'] = 1
if dsk.size > (16<<40) and SECTOR==4096:
print('You MUST use GPT partition scheme with 4K sectored disks >16TB!')
sys.exit(1)
#~ if dsk.size > (2<<40) and SECTOR==512:
#~ print('You MUST use GPT partition scheme with disks >2TB!')
#~ sys.exit(1)
#~ if dsk.size > (16<<40) and SECTOR==4096:
#~ print('You MUST use GPT partition scheme with 4K sectored disks >16TB!')
#~ sys.exit(1)
if t == 'mbr_old':
if dsk.size > (2<<30): print('Warning: old DOS does not like primary partitions >2GB, size reduced automatically!')
partutils.partition(dsk, 'mbr', {'compatibility':0})
if args.fs_type and args.fs_type.lower() == 'fat32':
args.fs_type = 'fat16'
print('Warning: old DOS does not know FAT32, switching to FAT16.')
else:
partutils.partition(dsk, 'mbr', options={'phys_sector':SECTOR})
partutils.partition(dsk, 'mbr', options=opts)
else:
partutils.partition(dsk, 'gpt', options={'phys_sector':SECTOR})
partutils.partition(dsk, 'gpt', options=opts)
dsk.close()
dsk = vopen(args.fs, 'r+b', 'partition0')
if type(dsk) == type(''):
Expand All @@ -63,7 +63,6 @@ def call(args):
else:
print("Disk was correctly partitioned with %s scheme."%t.upper())


params = {}

if args.fs_type:
Expand Down Expand Up @@ -119,7 +118,7 @@ def call(args):
else:
if params['fat_bits'] == 32:
dsk.mbr.partitions[0].bType = 0xB
if dsk.size > 1024*255*63*512: dsk.mbr.partitions[0].bType = 0xC
if dsk.size > 1024*255*63*SECTOR: dsk.mbr.partitions[0].bType = 0xC
elif params['fat_bits'] == 16:
dsk.mbr.partitions[0].bType = 6
if dsk.size < (32<<20): dsk.mbr.partitions[0].bType = 4
Expand Down
2 changes: 1 addition & 1 deletion FATtools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def get_geometry(size, sector=512):
s = 63
h = 255
c = sectors // (h*s)
if DEBUG&1: log("%d cylinders with %d heads and %d sectors (CxHxSx512=%d bytes)",c,h,s,c*h*s*sector)
if DEBUG&1: log("%d cylinders with %d heads and %d sectors (CxHxSx%d=%d bytes)",c,h,s,sector,c*h*s*sector)
return c, h, s

def chs2lba(c, h, s, hpc, spc):
Expand Down
2 changes: 1 addition & 1 deletion FATtools/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.0.20'
__version__ = '1.0.21'

0 comments on commit 3cf4bce

Please sign in to comment.