This commit is contained in:
Tolik 2026-01-29 21:39:52 +10:00 committed by Tolik Trek
parent e881028ea0
commit 192559b49a
7 changed files with 681 additions and 23 deletions

BIN
FAT table calculate.pdf Normal file

Binary file not shown.

Binary file not shown.

BIN
Format FAT.pdf Normal file

Binary file not shown.

@ -1 +1 @@
Subproject commit a26f6ad2cf2eab977cab8baa0c83b0c2a91a5e53 Subproject commit b9c54c9a1e027b35fba71efa26378a555cfd75db

143
Tmp2.md Normal file
View File

@ -0,0 +1,143 @@
Вот подробный алгоритм и формулы для программы низкоуровневого форматирования в FAT. Это не просто вызов стандартных утилит, а именно создание структуры разделов "с нуля".
Общий порядок действий (Алгоритм)
Определение параметров носителя и выбор FAT:
Получить общий размер диска/раздела в секторах (total_sectors).
Получить размер сектора (обычно 512, 1024, 2048, 4096 байт). bytes_per_sector.
Ключевое решение: На основе total_sectors * bytes_per_sector выбрать тип FAT (12/16/32). Используй пороговые значения (см. ниже).
Вычисление основных геометрических параметров:
Рассчитать sectors_per_cluster. Это степень двойки (1, 2, 4, 8, ... 64). Зависит от размера тома.
Определить размер зарезервированной области (reserved_sectors), обычно 1 для дисков, больше для разделов. Для FAT32 минимум 32.
Определить количество копий FAT (num_fats). Обычно 2.
Рассчитать размер одной таблицы FAT (sectors_per_fat). Самый сложный расчет, зависит от всего.
Создание загрузочной записи (BPB - Bios Parameter Block):
Заполнить структуру BPB (для FAT12/16) или BPB32 (для FAT32) вычисленными значениями.
Для FAT32 дополнительно вычислить и заполнить структуру FSInfo.
Запись структур на диск:
Сектор 0: Записать MBR с таблицей разделов (если форматируем весь диск, а не раздел).
Первый сектор раздела (Logical Sector 0):
Записать BPB (и возможно, загрузочный код).
Для FAT32: записать FSInfo (обычно в сектор 1) и Backup Boot Sector (обычно в сектор 6).
Зарезервированная область: Пропустить reserved_sectors.
Таблицы FAT: Записать num_fats копий FAT, каждая размером sectors_per_fat.
Инициализировать первые кластеры:
FAT[0] = 0xF?? | media_type (например, 0xF8 для HDD).
FAT[1] = 0xFFF / 0xFFFF / 0x0FFFFFFF (конец цепочки).
Область данных: Заполнить корневой каталог (для FAT12/16) нулями. Для FAT32 корневой каталог находится в кластере 2.
Формулы и детали для каждой FAT
1. Выбор FAT (Пороговые значения)
FAT12: До 4084 кластеров в области данных. (Макс. объем зависит от размера кластера, но обычно до ~32 МБ).
FAT16: От 4085 до 65524 кластеров. (Обычно от ~32 МБ до ~2 ГБ с 32-килобайтными кластерами. Теоретически до 4 ГБ с 64К кластерами, но не поддерживается многими ОС).
FAT32: От 65525 кластеров и более. (От ~512 МБ до 2 ТБ. Официально до 32 ГБ в Windows, но работает и больше).
Важно: Это кластеры, а не байты!
2. Ключевые вычисляемые параметры
Общие переменные:
total_sectors - общее число секторов раздела.
bytes_per_sector - 512, 1024, 2048, 4096.
sectors_per_cluster (spc) - степень двойки. Подбирается для оптимального количества кластеров.
reserved_sectors (rsvd_sec_cnt) - обычно 1 (FAT12/16) или 32 (FAT32).
num_fats - почти всегда 2.
root_dir_entries (root_ent_cnt) - только для FAT12/16. Обычно 512 (для дискет 224). Для FAT32 = 0.
sectors_per_fat (fat_sz32 для FAT32) - самый важный и сложный параметр.
Алгоритм расчета sectors_per_fat (итеративный или прямой)
Для FAT12/16:
Рассчитать размер корневого каталога в секторах:
root_dir_sectors = ((root_dir_entries * 32) + (bytes_per_sector - 1)) / bytes_per_sector
Рассчитать размер области данных в секторах:
data_sectors = total_sectors - (reserved_sectors + (num_fats * fat_sz) + root_dir_sectors)
Здесь fat_sz (искомое) пока неизвестно.
Рассчитать общее число кластеров:
total_clusters = data_sectors / sectors_per_cluster
Теперь можно найти нужный размер FAT:
Для FAT16: Каждая запись FAT - 2 байта. fat_sz = (total_clusters * 2 + (bytes_per_sector - 1)) / bytes_per_sector
Для FAT12: Каждая запись - 1.5 байта. fat_sz = (total_clusters * 3 + 1) / (2 * bytes_per_sector) (с округлением вверх).
Но fat_sz влияет на data_sectors. Это цикл. На практике используют итерацию или таблицы. Простой способ:
Сначала грубо оцени data_sectors = total_sectors - reserved_sectors - root_dir_sectors.
Посчитай total_clusters, затем fat_sz.
Уточни data_sectors, вычтя num_fats * fat_sz.
Пересчитай total_clusters. Если изменился сильно - повтори.
Для FAT32:
Формула проще, т.к. корневой каталог в области данных.
data_sectors = total_sectors - reserved_sectors - (num_fats * fat_sz32)
total_clusters = data_sectors / sectors_per_cluster
Размер записи FAT32 - 4 байта. Поэтому:
fat_sz32 = (total_clusters * 4 + (bytes_per_sector - 1)) / bytes_per_sector
Опять цикл. Стартовое приближение: fat_sz32 = 0. Повторять расчет, пока fat_sz32 не стабилизируется (обычно 2-3 итерации).
Структуры данных (Упрощенно)
Общая структура BPB (смещения для сектора 512 байт):
0x00: JMP инструкция (3 байта)
0x03: OEM Name (8 байт)
0x0B: bytes_per_sector (WORD)
0x0D: sectors_per_cluster (BYTE)
0x0E: reserved_sectors (WORD)
0x10: num_fats (BYTE)
0x11: root_ent_cnt (WORD) ; 0 для FAT32
0x13: total_sectors_16 (WORD) ; если 0, см. 0x20
0x15: media (BYTE) ; 0xF8 для HDD
0x16: fat_sz_16 (WORD) ; 0 для FAT32
0x18: sectors_per_track (WORD)
0x1A: num_heads (WORD)
0x1C: hidden_sectors (DWORD) ; важно для разделов
0x20: total_sectors_32 (DWORD)
Дополнение для FAT12/16 (Extended BPB):
0x24: drive_number (BYTE)
0x25: reserved (BYTE)
0x26: boot_sig (BYTE) ; 0x29
0x27: volume_id (DWORD)
0x2B: volume_label (11 BYTE)
0x36: file_system_type (8 BYTE) ; "FAT12 ", "FAT16 "
0x3E: boot_code (448 BYTE)
0x1FE: signature (WORD) ; 0xAA55
Дополнение для FAT32 (Extended BPB):
0x24: fat_sz_32 (DWORD) ; sectors_per_fat
0x28: ext_flags (WORD)
0x2A: fs_version (WORD) ; 0
0x2C: root_cluster (DWORD) ; обычно 2
0x30: fs_info_sector (WORD) ; обычно 1
0x32: backup_boot_sector (WORD) ; обычно 6
0x34: reserved[12] (12 BYTE)
... (поля drive_number, boot_sig, volume_id, label, type аналогичны, но смещения другие)
0x1FE: signature (WORD) ; 0xAA55
Порядок записи для FAT32 (особое внимание!)
Сектор 0: Основная загрузочная запись (BPB32).
Сектор 1: Структура FSInfo (опционально, но рекомендуется).
Сектор 6: Резервная копия загрузочного сектора (Backup Boot Sector). Должна быть идентична сектору 0.
Сектор 7 и далее: Зарезервированная область.
FAT1: Начинается с сектора reserved_sectors (обычно 32).
FAT2: Начинается с сектора reserved_sectors + fat_sz32.
Область данных: Начинается с сектора reserved_sectors + num_fats * fat_sz32.
Кластер 2: Является началом корневого каталога (значение root_cluster в BPB).
На что обратить особое внимание
Выравнивание: Для производительности на современных SSD резервируй reserved_sectors так, чтобы FAT и данные начинались с границ больших блоков (например, 1 МБ).
Размер кластера: Большой кластер уменьшает размер FAT и ускоряет работу с большими файлами, но ведет к потере места на мелких файлах. Выбирай по таблицам Microsoft.
FAT32 и большие диски: При размерах >32 ГБ многие ОС (старые Windows) откажутся монтировать том. Это ограничение на уровне ОС, а не файловой системы.
hidden_sectors: Критически важный параметр при форматировании раздела, а не всего диска. Это смещение раздела от начала диска в секторах. Если установить неверно, диск не загрузится или данные будут потеряны.
Зеркалирование FAT: В FAT32 есть флаг ext_flags, который может отключать зеркалирование FAT (копию). По умолчанию зеркалирование включено, и FAT1 и FAT2 должны быть идентичны.
Тестирование: Всегда тестируй алгоритм на виртуальных дисках (файлах-образах) перед работой с реальными носителями. Используй hexdump или дисковые редакторы для проверки структур.
Рекомендация: Изучи исходный код утилит mkfs.fat (из пакета dosfstools в Linux) или fatformat. Там реализованы все эти алгоритмы с учетом множества крайних случаев.
Продолжить с DeepSeek

View File

@ -802,12 +802,12 @@ BOOT_SECTOR EQU #00
.JMP EQU #00 ; BLOCK 3,0 BS_jmpBoot Jump to bootstrap (E.g. eb 3c 90; on i86: JMP 003E NOP. One finds either eb xx 90, or e9 xx xx. .JMP EQU #00 ; BLOCK 3,0 BS_jmpBoot Jump to bootstrap (E.g. eb 3c 90; on i86: JMP 003E NOP. One finds either eb xx 90, or e9 xx xx.
.ID_NAME EQU #03 ; TEXT 8 BS_OEMName DOS NAME - DB "DSS_1.70" .ID_NAME EQU #03 ; TEXT 8 BS_OEMName DOS NAME - DB "DSS_1.70"
; Block Parameters BIOS ; Block Parameters BIOS
.BytesPerSector DRV_GET_PAR (IX) EQU #0B ; WORD #200 BPB_BytsPerSec <09> §¬¥à ᥪâ®à  ¢ ¡ ©â å .BytesPerSector GenIOCTL.GetParams EQU #0B ; WORD #200 BPB_BytsPerSec <09> §¬¥à ᥪâ®à  ¢ ¡ ©â å
.SectorsPerCluster ;!TODO EQU #0D ; BYTE 2 BPB_SecPerClus <09> §¬¥à ª« áâ¥à  ¢ ᥪâ®à å .SectorsPerCluster ;!TODO EQU #0D ; BYTE 2 BPB_SecPerClus <09> §¬¥à ª« áâ¥à  ¢ ᥪâ®à å
.RESERVED_SECTORS !RESERVED_SECTORS EQU #0E ; WORD 1 BPB_ResvdSecCnt <09> §¬¥à á¨á⥬­®© ®¡« á⨠(¢ª«îç ï íâ®â ᥪâ®à) RESERVE SECTORS .RESERVED_SECTORS !RESERVED_SECTORS EQU #0E ; WORD 1 BPB_ResvdSecCnt <09> §¬¥à á¨á⥬­®© ®¡« á⨠(¢ª«îç ï íâ®â ᥪâ®à) RESERVE SECTORS
.Number_of_FATs ;!TODO EQU #10 ; BYTE 2 BPB_NumFATs Š®«¨ç¥á⢮ â ¡«¨æ FAT .Number_of_FATs 2 EQU #10 ; BYTE 2 BPB_NumFATs Š®«¨ç¥á⢮ â ¡«¨æ FAT
.FilesInRootDIR 0 EQU #11 ; WORD 112 BPB_RootEntCnt —¨á«® ®¯¨á â¥«¥© ä ©«®¢ ¢ ª®à­¥¢®¬ ª â «®£¥ (¢ FAT32 - 0) .FilesInRootDIR 0 EQU #11 ; WORD 112 BPB_RootEntCnt —¨á«® ®¯¨á â¥«¥© ä ©«®¢ ¢ ª®à­¥¢®¬ ª â «®£¥ (¢ FAT32 - 0)
.SectorsPerDrive ;!TODO EQU #13 ; WORD 1440 BPB_TotSec16 ޡ饥 ç¨á«® ᥪâ®à®¢ ­  ¤¨áª¥ (¥á«¨ 0, â® à §¬¥à - ¢ .BPB_BIG_TOTAL_SECTORS) .SectorsPerDrive 0 EQU #13 ; WORD 1440 BPB_TotSec16 ޡ饥 ç¨á«® ᥪâ®à®¢ ­  ¤¨áª¥ (¥á«¨ 0, â® à §¬¥à - ¢ .BPB_BIG_TOTAL_SECTORS)
.DRIVE_TYPE !DRV_TYPE EQU #15 ; BYTE #F0 BPB_Media ’¨¯ ãáâனá⢠ .DRIVE_TYPE !DRV_TYPE EQU #15 ; BYTE #F0 BPB_Media ’¨¯ ãáâனá⢠
.SectorsPerFAT16 0 EQU #16 ; WORD 2 BPB_FATSz16 <09> §¬¥à ®¤­®© FAT ¢ ᥪâ®à å (0 ¢ FAT32) .SectorsPerFAT16 0 EQU #16 ; WORD 2 BPB_FATSz16 <09> §¬¥à ®¤­®© FAT ¢ ᥪâ®à å (0 ¢ FAT32)
.SectorsPerTrack GenIOCTL.GetParams EQU #18 ; WORD 9 BPB_SecPerTrk <09> §¬¥à ¤®à®¦ª¨ ¢ ᥪâ®à å .SectorsPerTrack GenIOCTL.GetParams EQU #18 ; WORD 9 BPB_SecPerTrk <09> §¬¥à ¤®à®¦ª¨ ¢ ᥪâ®à å
@ -817,14 +817,14 @@ BOOT_SECTOR EQU #00
.BPB_BIG_TOTAL_SECTORS_H EQU #22 ; WORD 0 BPB_TotSec32 BIG TOTAL SECTOR High word .BPB_BIG_TOTAL_SECTORS_H EQU #22 ; WORD 0 BPB_TotSec32 BIG TOTAL SECTOR High word
; FAT 32 ; FAT 32
.SectorsPerFAT32 EQU #24 ; DWORD 4 BPB_FATSz32 <09> §¬¥à ®¤­®© FAT ¢ ᥪâ®à å .SectorsPerFAT32 EQU #24 ; DWORD 4 BPB_FATSz32 <09> §¬¥à ®¤­®© FAT ¢ ᥪâ®à å
.MainFATnumber EQU #28 ; WORD 0 BPB_ExtFlags <09>®¬¥à £« ¢­®© â ¡«¨æë FAT .MainFATnumber 0 EQU #28 ; WORD 0 BPB_ExtFlags <09>®¬¥à £« ¢­®© â ¡«¨æë FAT
.Version EQU #2A ; WORD 0 BPB_FSVer ‚¥àá¨ï FAT32 (®¡ëç­® 0) .Version 0 EQU #2A ; WORD 0 BPB_FSVer ‚¥àá¨ï FAT32 (®¡ëç­® 0)
.RootDirStartCluster EQU #2C ; DWORD 2 BPB_RootClus <09>¥à¢ë© ª« áâ¥à ª®à­¥¢®£® ª â «®£  (®¡ëç­® 2) .RootDirStartCluster 2 EQU #2C ; DWORD 2 BPB_RootClus <09>¥à¢ë© ª« áâ¥à ª®à­¥¢®£® ª â «®£  (®¡ëç­® 2)
.FSINFO_Sector EQU #30 ; WORD 1 BPB_FSInfo <09>®¬¥à ᥪâ®à  áâàãªâãàë FSINFO (®¡ëç­® 1) .FSINFO_Sector 1 EQU #30 ; WORD 1 BPB_FSInfo <09>®¬¥à ᥪâ®à  áâàãªâãàë FSINFO (®¡ëç­® 1)
.CopyBootSector EQU #32 ; WORD 6 BPB_BkBootSec <09>®¬¥à ᥪâ®à  - ª®¯¨¨ § £à㧮筮£® (®¡ëç­® 6) .CopyBootSector 6 EQU #32 ; WORD 6 BPB_BkBootSec <09>®¬¥à ᥪâ®à  - ª®¯¨¨ § £à㧮筮£® (®¡ëç­® 6)
.reserved_block: EQU #34 ; BLOCK 12 BPB_Reserved ‡ à¥§¥à¢¨à®¢ ­® .reserved_block: 0 EQU #34 ; BLOCK 12 BPB_Reserved ‡ à¥§¥à¢¨à®¢ ­®
.FDD_Number EQU #40 ; BYTE 0 BS_DrvNum <09>®¬¥à ¤¨áª®¢®¤  ¤«ï ä㭪権 BIOS .FDD_Number GenIOCTL.GetParams&#F0 EQU #40 ; BYTE 0 BS_DrvNum <09>®¬¥à ¤¨áª®¢®¤  ¤«ï ä㭪権 BIOS
.reserved_2: EQU #41 ; BYTE 0 BS_Reserved1 ‡ à¥§¥à¢¨à®¢ ­® .reserved_2: 0 EQU #41 ; BYTE 0 BS_Reserved1 ‡ à¥§¥à¢¨à®¢ ­®
.FAT32.EXT_BOOT_REC_SIGNATURE EQU #42 ; BYTE #29 BS_BootSig ‘¨£­ âãà  - #29 .FAT32.EXT_BOOT_REC_SIGNATURE EQU #42 ; BYTE #29 BS_BootSig ‘¨£­ âãà  - #29
.FAT32.SERIAL_NUMBER EQU #43 ; DWORD 0 BS_VolID VOLUME SERIAL NUMBER .FAT32.SERIAL_NUMBER EQU #43 ; DWORD 0 BS_VolID VOLUME SERIAL NUMBER
.FAT32.LABEL EQU #47 ; TEXT 11 BS_VolLab Œ¥âª  ¤¨áª  .FAT32.LABEL EQU #47 ; TEXT 11 BS_VolLab Œ¥âª  ¤¨áª 
@ -844,7 +844,45 @@ BOOT_SECTOR EQU #00
.FAT12_FDD EQU 1 .FAT12_FDD EQU 1
.FAT12_HDD .FAT12_HDD
.FAT16_HDD .FAT16_HDD
.FAT32_HDD EQU .FAT32_HDD EQU 32
CALCULATED_FAT_PARAMETERS:
.FAT_TYPE BYTE TABLES.FAT12 ; [x]
.BytesPerSector: WORD #200 ; predefined ; [x]
.SectorsPerCluster: BYTE 32 ; predefined ; [x]
.RESERVED_SECTORS: WORD 0 ; [x]
.Number_of_FATs: BYTE 2 ; predefined ;
.FilesInRootDIR: WORD 0 ; FAT32 constant ; [ ] FAT ; [x] FAT32
.SectorsPerDrive: WORD 0 ; FAT32 constant ; [x] +-
.DRIVE_TYPE: WORD 0 ; ;
.SectorsPerFAT16: WORD 0 ; FAT32 constant ;
.HEADS WORD 0 ;
.HIDDEN WORD 0 ; ®â ­ ç «  MBR, extMBR ;
.BPB_BIG_TOTAL_SECTORS_L WORD 0 ; [x] +-
.BPB_BIG_TOTAL_SECTORS_H WORD 0 ; [x] +-
; FAT 12, FAT 16
.BPB_PHISICAL_DRIVE_NUMBER BYTE #80 ; [x]
.reserved_1 BYTE 0 ;
.FAT.EXT_BOOT_REC_SIGNATURE BYTE #29 ;
.FAT.SERIAL_NUMBER DWORD 0 ;
.FAT.LABEL TEXT 11 ;
.ID_FAT TEXT 8 ;
; FAT32
.SectorsPerFAT32 DWORD 0 ;
.MainFATnumber WORD 0 ; BPB_ExtFlags ;
.Version WORD 0 ; constant ;
.RootDirStartCluster DWORD 2 ;
.FSINFO_Sector WORD 1 ; constant ;
.CopyBootSector WORD 6 ; constant ;
.reserved_block: BLOCK 12 ; constant ;
.FDD_Number BYTE 0 ;
.reserved_2: BYTE 0 ; constant ;
.FAT32.EXT_BOOT_REC_SIGNATURE BYTE #29 ; constant ;
.FAT32.SERIAL_NUMBER DWORD 0 ;
.FAT32.LABEL TEXT 11 ;
.ID_FAT32 TEXT 8 ; constant ;
; #5A ;
¤«ï ᬥ饭¨ï FAT ¤® ªà â­®£® 4096 §­ ç¥­¨ï: ¤«ï ᬥ饭¨ï FAT ¤® ªà â­®£® 4096 §­ ç¥­¨ï:
1) tmp1 = ((.HIDDEN + min_last_sector) & #0F)>0 ) * #10 1) tmp1 = ((.HIDDEN + min_last_sector) & #0F)>0 ) * #10
@ -853,8 +891,179 @@ BOOT_SECTOR EQU #00
4) error = (tmp3 >= #1000'0000) ; LBA28 4) error = (tmp3 >= #1000'0000) ; LBA28
reserved_sectors = ( ((.HIDDEN + min_last_sector) & #0F)>0 ) * #10) - .HIDDEN reserved_sectors = ( ((.HIDDEN + min_last_sector) & #0F)>0 ) * #10) - .HIDDEN
;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;
*/ */
FORMAT_FAT32:
; Ž¯à¥¤¥«¥­¨¥ ¯ à ¬¥â஢ ­®á¨â¥«ï ¨ ¢ë¡®à FAT
.STEP1: ; íâ  ¤®«¦­  ¡ëâì ®¡é¥© ¤«ï § ¯®«­¥­¨ï £¥®¬¥âਨ ¤¨áª 
LD A,VARIABLES.CurrentDrive
LD BC,Dss.DRV.GenIOCTL.GetParams
RST ToDSS.DRV
;
;!TODO CHECK ERROR
;
EX AF,AF'
AND #F0
LD (CALCULATED_FAT_PARAMETERS.BPB_PHISICAL_DRIVE_NUMBER),A
; !FIXIT ¢ à¨ ­â ¤«ï ¢¨­â 
LD A,H
OR L
JR NZ,.BPB_BIG_TOTAL_SECTORS
;
LD (CALCULATED_FAT_PARAMETERS.SectorsPerDrive),DE
;!TODO ãáâ ­®¢¨âì ä« £, çâ® ¬¥«ª¨© ¤¨áª ­¥ ¤«ï FAT32 ¯à¨ €¢â®¬ â¥
JR .STEP1_2
;
.BPB_BIG_TOTAL_SECTORS:
LD (CALCULATED_FAT_PARAMETERS.BPB_BIG_TOTAL_SECTORS_L),DE
LD (CALCULATED_FAT_PARAMETERS.BPB_BIG_TOTAL_SECTORS_H),HL
.STEP1_2: ; à §¬¥à ᥪâ®à 
XOR A
SRL B
RRA
LD C,A
LD (CALCULATED_FAT_PARAMETERS.BytesPerSector),BC
; à §¬¥à ¤¨áª  ¢ ¡ ©â å
CALL MUL32_POWER2
LD (VOLUME_SIZE_BYTES),DE
LD (VOLUME_SIZE_BYTES + 2),HL
LD (VOLUME_SIZE_BYTES + 4),A
LD E,H
LD D,A
CALL AUTO_CHOOSE_FAT_PARAMS
;!FIXIT
; RET C
;
LD A,C
LD (CALCULATED_FAT_PARAMETERS.FAT_TYPE),A
CP TABLES.FAT32
LD A,(RESERVED_SECTORS.FAT32)
JR Z,.set_reserved_s
;
LD A,(RESERVED_SECTORS.FAT)
.set_reserved_s:
LD (CALCULATED_FAT_PARAMETERS.RESERVED_SECTORS),A
LD HL,(CALCULATED_FAT_PARAMETERS.BytesPerSector)
DEC HL
SBC HL,DE
LD HL,(CALCULATED_FAT_PARAMETERS.BytesPerSector)
EX DE,HL
JR C,.BPS_OK
; ­  á«ãç ©, ¥á«¨ â ¡«¨ç­ë© ª« áâ¥à ¬¥­ìè¥ á¥ªâ®à 
LD A,1
.BPS_OK: CALL C,DIV16_POWER2
;!FIXIT
; RET C
;
LD (CALCULATED_FAT_PARAMETERS.SectorsPerCluster),A
; -> DE - 4 ¨ 5 ¡ ©âë à §¬¥à  à §¤¥« .
; ¤®«¦­® ¡ëâì ãáâ ­®¢«¥­® §­ ç¥­¨¥ VOLUME_SIZE_BYTES.
; <- DE - CLUSTER SIZE.
; C - FAT TYPE.
AUTO_CHOOSE_FAT_PARAMS:
LD IX,TABLES.FAT_TYPES
LD A,TABLES.FAT_TYPES.Records
LD BC,TABLES.FAT_TYPES.LineSize
.loop: LD L,(IX)
LD H,(IX+1)
SBC HL,DE
JR C,.found
;
ADD IX,BC
DEC A
JR NZ,.loop
; ã ­ á FAT12 c ª« áâ¥à®¬ ¢ 512
; ­ ¤® ¯à®¢¥à¨âì à §¤¥« ­  ¬¨­¨¬ «ì­ë© à §¬¥à ¤«ï FAT
; sec_bpb + sec_fat + sec_root_dir + sec_for_data
LD A,D
OR E
JR NZ,.found
;
LD HL,(VOLUME_SIZE_BYTES + 1)
LD DE,8
SBC HL,DE
RET C ; à §¤¥« ᫨誮¬ ¬ « ¤«ï FAT12 (<2048)
.found: ; ¤®áâ ñ¬ ¯ à ¬¥âàë ¨§ â ¡«¨æë
DI
LD (.restore_SP),SP
LD SP,IX
POP HL ; 宫®á⮥
POP DE ; CLUSTER SIZE
POP BC ; C - FAT TYPE
LD A,C
.restore_SP+1: LD SP,0
EI
RET
; -> HLDE * BC. BC = á⥯¥­ì ¤¢®©ª¨
; <- AHLDE
; CF=1 - error
MUL32_POWER2: XOR A
.loop: EX DE,HL
ADD HL,HL
EX DE,HL
ADC HL,HL
ADC A,0
RET C
;
SRL B
RR C
JR NC,.loop
;
EX DE,HL
AND A
RET
; -> HL / DE. DE = á⥯¥­ì ¤¢®©ª¨
; <- A = HL / DE
; CF=1 - error
DIV16_POWER2: XOR A
.loop: INC A
SBC HL,DE
JR NC,.loop
DEC A
RET Z ; error: ¤¥«¨¬®¥ < ¤¥«¨â¥«ï
CCF
RET
MACRO FAT_TYPES_LINE (vol_size, clu_size, fat_type)
WORD vol_size, clu_size : BYTE fat_type
ENDM
MODULE TABLES
FAT12 EQU 0
FAT16 EQU 1
FAT32 EQU 2
; VOL SIZE CLUSTER SIZE FAT TYPE
FAT_TYPES: FAT_TYPES_LINE (#0800, 32768, FAT32) ; > 32768
FAT_TYPES_LINE (#0400, 16384, FAT32) ; 16384..32768 Mb
FAT_TYPES_LINE (#0200, 8192, FAT32) ; 8192..16384 Mb
FAT_TYPES_LINE (#0100, 4096, FAT32) ; 4096..8192 Mb
FAT_TYPES_LINE (#0080, 32768, FAT16) ; 2048..4096 Mb
FAT_TYPES_LINE (#0040, 16384, FAT16) ; 1023..2048 Mb
FAT_TYPES_LINE (#0020, 8192, FAT16) ; 511..1023 Mb
FAT_TYPES_LINE (#0010, 4096, FAT16) ; 256..511 Mb
FAT_TYPES_LINE (#0008, 2048, FAT16) ; 128..256 Mb
FAT_TYPES_LINE (#0004, 1024, FAT16) ; 64..128 Mb
FAT_TYPES_LINE (#0002, 512, FAT16) ; 32..64 Mb
; ¥á«¨ ¬¥­ìè¥, â® FAT12
.LineSize EQU 5
.Records EQU ($ - .FAT_TYPES)/.LineSize
ENDMODULE
;
;
ENDIF ENDIF

306
tmp1.c Normal file
View File

@ -0,0 +1,306 @@
#include "../include/fttf.h"
#pragma pack(push, 1)
typedef struct {
BYTE jmpBoot[3];
BYTE OEMName[8];
WORD bytesPerSector;
BYTE sectorsPerCluster;
WORD reservedSectorCount;
BYTE numFATs;
WORD rootEntryCount;
WORD totalSectors16;
BYTE media;
WORD FATSize16;
WORD sectorsPerTrack;
WORD numberHeads;
DWORD hiddenSectors;
DWORD totalSectors32;
DWORD FATSize32;
WORD extFlags;
WORD FSVersion;
DWORD rootCluster;
WORD FSInfoSector;
WORD backupBootSector;
BYTE reserved[12];
BYTE driveNumber;
BYTE reserved1;
BYTE bootSignature;
DWORD volumeID;
BYTE volumeLabel[11];
BYTE fileSystemType[8];
} FAT32BootSector;
typedef struct {
DWORD leadSignature;
BYTE reserved1[480];
DWORD structSignature;
DWORD freeCount;
DWORD nextFree;
BYTE reserved2[12];
DWORD trailSignature;
} FSInfoSector;
#pragma pack(pop)
BOOL FormatDrive(WCHAR driveLetter, HWND hwnd) {
WCHAR volumePath[MAX_PATH];
swprintf(volumePath, MAX_PATH, L"\\\\.\\%c:", driveLetter);
LogMessage(hwnd, L"Opening drive %c:...\r\n", driveLetter);
HANDLE hDrive = CreateFileW(
volumePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hDrive == INVALID_HANDLE_VALUE) {
LogMessage(hwnd, L"Failed to open drive (error %lu)\r\n", GetLastError());
return FALSE;
}
LogMessage(hwnd, L"Locking volume...\r\n");
if (!LockVolume(hDrive)) {
LogMessage(hwnd, L"Failed to lock volume\r\n");
CloseHandle(hDrive);
return FALSE;
}
LogMessage(hwnd, L"Dismounting volume...\r\n");
if (!DismountVolume(hDrive)) {
LogMessage(hwnd, L"Warning: Could not dismount volume\r\n");
}
DISK_GEOMETRY diskGeometry;
DWORD bytesReturned;
if (!DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
&diskGeometry, sizeof(diskGeometry), &bytesReturned, NULL)) {
LogMessage(hwnd, L"Failed to get disk geometry\r\n");
CloseHandle(hDrive);
return FALSE;
}
ULONGLONG diskSize = (ULONGLONG)diskGeometry.Cylinders.QuadPart *
diskGeometry.TracksPerCylinder *
diskGeometry.SectorsPerTrack *
diskGeometry.BytesPerSector;
LogMessage(hwnd, L"Disk size: %.2f GB\r\n", (double)diskSize / (1024.0 * 1024.0 * 1024.0));
LogMessage(hwnd, L"Bytes per sector: %lu\r\n", diskGeometry.BytesPerSector);
FAT32Params params;
if (!CalculateFAT32Parameters(diskSize, diskGeometry.BytesPerSector, &params)) {
LogMessage(hwnd, L"Couldn't calculate FAT32 params\r\n");
CloseHandle(hDrive);
return FALSE;
}
LogMessage(hwnd, L"Sectors per cluster: %lu\r\n", params.sectorsPerCluster);
LogMessage(hwnd, L"Total sectors: %lu\r\n", params.totalSectors);
LogMessage(hwnd, L"Sectors per FAT: %lu\r\n", params.sectorsPerFAT);
if (!WriteFAT32Structures(hDrive, &params, hwnd)) {
LogMessage(hwnd, L"Failed to write FAT32 structures\r\n");
CloseHandle(hDrive);
return FALSE;
}
CloseHandle(hDrive);
LogMessage(hwnd, L"Refreshing drive...\r\n");
WCHAR driveRoot[4] = {driveLetter, L':', L'\\', 0};
SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, driveRoot, NULL);
return TRUE;
}
BOOL CalculateFAT32Parameters(ULONGLONG diskSize, DWORD bytesPerSector, FAT32Params* params) {
params->bytesPerSector = bytesPerSector;
params->totalSectors = (DWORD)(diskSize / bytesPerSector);
params->reservedSectors = 32;
params->numberOfFATs = 2;
params->rootDirFirstCluster = 2;
if (diskSize < 512ULL * 1024 * 1024) {
params->sectorsPerCluster = 1;
} else if (diskSize < 8ULL * 1024 * 1024 * 1024) {
params->sectorsPerCluster = 8;
} else if (diskSize < 16ULL * 1024 * 1024 * 1024) {
params->sectorsPerCluster = 16;
} else if (diskSize < 32ULL * 1024 * 1024 * 1024) {
params->sectorsPerCluster = 32;
} else {
params->sectorsPerCluster = 64;
}
DWORD tmpVal1 = params->totalSectors - params->reservedSectors;
DWORD tmpVal2 = (256 * params->sectorsPerCluster) + params->numberOfFATs;
tmpVal2 = tmpVal2 / 2;
params->sectorsPerFAT = (tmpVal1 + tmpVal2 - 1) / tmpVal2;
return TRUE;
}
BOOL WriteFAT32Structures(HANDLE hDrive, FAT32Params* params, HWND hwnd) {
LARGE_INTEGER pos;
pos.QuadPart = 0;
if (!SetFilePointerEx(hDrive, pos, NULL, FILE_BEGIN)) {
return FALSE;
}
LogMessage(hwnd, L"Writing boot sector...\r\n");
FAT32BootSector bootSector;
memset(&bootSector, 0, sizeof(bootSector));
bootSector.jmpBoot[0] = 0xEB;
bootSector.jmpBoot[1] = 0x58;
bootSector.jmpBoot[2] = 0x90;
memcpy(bootSector.OEMName, "MSWIN4.1", 8);
bootSector.bytesPerSector = (WORD)params->bytesPerSector;
bootSector.sectorsPerCluster = (BYTE)params->sectorsPerCluster;
bootSector.reservedSectorCount = (WORD)params->reservedSectors;
bootSector.numFATs = params->numberOfFATs;
bootSector.rootEntryCount = 0;
bootSector.totalSectors16 = 0;
bootSector.media = 0xF8;
bootSector.FATSize16 = 0;
bootSector.sectorsPerTrack = 63;
bootSector.numberHeads = 255;
bootSector.hiddenSectors = 0;
bootSector.totalSectors32 = params->totalSectors;
bootSector.FATSize32 = params->sectorsPerFAT;
bootSector.extFlags = 0;
bootSector.FSVersion = 0;
bootSector.rootCluster = params->rootDirFirstCluster;
bootSector.FSInfoSector = 1;
bootSector.backupBootSector = 6;
bootSector.driveNumber = 0x80;
bootSector.bootSignature = 0x29;
bootSector.volumeID = GetTickCount();
memcpy(bootSector.volumeLabel, "NO NAME ", 11);
memcpy(bootSector.fileSystemType, "FAT32 ", 8);
BYTE* sector = (BYTE*)malloc(params->bytesPerSector);
if (!sector) {
return FALSE;
}
memset(sector, 0, params->bytesPerSector);
memcpy(sector, &bootSector, sizeof(bootSector));
sector[510] = 0x55;
sector[511] = 0xAA;
DWORD written;
if (!WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL)) {
free(sector);
return FALSE;
}
LogMessage(hwnd, L"Writing FSInfo sector...\r\n");
FSInfoSector fsInfo;
memset(&fsInfo, 0, sizeof(fsInfo));
fsInfo.leadSignature = 0x41615252;
fsInfo.structSignature = 0x61417272;
fsInfo.freeCount = 0xFFFFFFFF;
fsInfo.nextFree = 0xFFFFFFFF;
fsInfo.trailSignature = 0xAA550000;
memset(sector, 0, params->bytesPerSector);
memcpy(sector, &fsInfo, sizeof(fsInfo));
if (!WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL)) {
free(sector);
return FALSE;
}
pos.QuadPart = 2 * params->bytesPerSector;
SetFilePointerEx(hDrive, pos, NULL, FILE_BEGIN);
memset(sector, 0, params->bytesPerSector);
for (int i = 0; i < 4; i++) {
WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL);
}
LogMessage(hwnd, L"Writing backup boot sector...\r\n");
pos.QuadPart = 6 * params->bytesPerSector;
SetFilePointerEx(hDrive, pos, NULL, FILE_BEGIN);
memset(sector, 0, params->bytesPerSector);
memcpy(sector, &bootSector, sizeof(bootSector));
sector[510] = 0x55;
sector[511] = 0xAA;
WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL);
memset(sector, 0, params->bytesPerSector);
memcpy(sector, &fsInfo, sizeof(fsInfo));
WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL);
LogMessage(hwnd, L"Writing FAT tables...\r\n");
pos.QuadPart = params->reservedSectors * params->bytesPerSector;
SetFilePointerEx(hDrive, pos, NULL, FILE_BEGIN);
for (int fat = 0; fat < params->numberOfFATs; fat++) {
memset(sector, 0, params->bytesPerSector);
DWORD* fatEntries = (DWORD*)sector;
fatEntries[0] = 0x0FFFFFF8;
fatEntries[1] = 0x0FFFFFFF;
fatEntries[2] = 0x0FFFFFFF;
WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL);
memset(sector, 0, params->bytesPerSector);
for (DWORD i = 1; i < params->sectorsPerFAT; i++) {
WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL);
}
}
LogMessage(hwnd, L"Clearing root directory...\r\n");
DWORD rootDirSector = params->reservedSectors +
(params->numberOfFATs * params->sectorsPerFAT) +
((params->rootDirFirstCluster - 2) * params->sectorsPerCluster);
pos.QuadPart = rootDirSector * params->bytesPerSector;
SetFilePointerEx(hDrive, pos, NULL, FILE_BEGIN);
memset(sector, 0, params->bytesPerSector);
for (DWORD i = 0; i < params->sectorsPerCluster; i++) {
WriteFile(hDrive, sector, params->bytesPerSector, &written, NULL);
}
free(sector);
FlushFileBuffers(hDrive);
return TRUE;
}
BOOL LockVolume(HANDLE hDrive) {
DWORD bytesReturned;
for (int i = 0; i < 10; i++) {
if (DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL)) {
return TRUE;
}
Sleep(500);
}
return FALSE;
}
BOOL UnmountVolume(HANDLE hDrive) {
DWORD bytesReturned;
return DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL);
}
BOOL DismountVolume(HANDLE hDrive) {
return UnmountVolume(hDrive);
}