diff --git a/FAT table calculate.pdf b/FAT table calculate.pdf new file mode 100644 index 0000000..961658a Binary files /dev/null and b/FAT table calculate.pdf differ diff --git a/Format FAT.docx b/Format FAT.docx index 51ab346..5447f9c 100644 Binary files a/Format FAT.docx and b/Format FAT.docx differ diff --git a/Format FAT.pdf b/Format FAT.pdf new file mode 100644 index 0000000..553d2f5 Binary files /dev/null and b/Format FAT.pdf differ diff --git a/Shared_Includes b/Shared_Includes index a26f6ad..b9c54c9 160000 --- a/Shared_Includes +++ b/Shared_Includes @@ -1 +1 @@ -Subproject commit a26f6ad2cf2eab977cab8baa0c83b0c2a91a5e53 +Subproject commit b9c54c9a1e027b35fba71efa26378a555cfd75db diff --git a/Tmp2.md b/Tmp2.md new file mode 100644 index 0000000..76bb5ac --- /dev/null +++ b/Tmp2.md @@ -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 diff --git a/format/format.asm b/format/format.asm index eb2be3e..07490cd 100755 --- a/format/format.asm +++ b/format/format.asm @@ -548,22 +548,22 @@ gen_serial: ld c,#21 ;!HARDCODE Dss.SysTime ParseCL: LD A,(HL) ;cmd line size - OR A ;0 = no params + OR A ;0 = no params JP Z,Usage ;goto help message INC HL - INC HL ;first param + INC HL ;first param LD A,(HL) LD C,A INC HL LD A,(HL) - CP ':' ;must be dsk: (like C:) - JP NZ,Usage ;if not, goto help message + CP ':' ;must be dsk: (like C:) + JP NZ,Usage ;if not, goto help message LD A,C CALL CapsLetter JP C,Usage ;drive letter is not a letter - LD (warn_Msg.dsk),A ;store it in messages - LD (Process_Msg.dsk),A ;* - LD (ProcessErr_Msg.dsk),A ;* + LD (warn_Msg.dsk),A ;store it in messages + LD (Process_Msg.dsk),A ;* + LD (ProcessErr_Msg.dsk),A ;* SUB 'A' ; .set_A: LD (FMTDISK),A @@ -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. .ID_NAME EQU #03 ; TEXT 8 BS_OEMName DOS NAME - DB "DSS_1.70" ; Block Parameters BIOS -.BytesPerSector DRV_GET_PAR (IX) EQU #0B ; WORD #200 BPB_BytsPerSec ᥪ +.BytesPerSector GenIOCTL.GetParams EQU #0B ; WORD #200 BPB_BytsPerSec ᥪ .SectorsPerCluster ;!TODO EQU #0D ; BYTE 2 BPB_SecPerClus ᥪ .RESERVED_SECTORS !RESERVED_SECTORS EQU #0E ; WORD 1 BPB_ResvdSecCnt ⥬ ( ᥪ) 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) -.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 ன⢠ .SectorsPerFAT16 0 EQU #16 ; WORD 2 BPB_FATSz16 FAT ᥪ (0 FAT32) .SectorsPerTrack GenIOCTL.GetParams EQU #18 ; WORD 9 BPB_SecPerTrk ஦ ᥪ @@ -817,14 +817,14 @@ BOOT_SECTOR EQU #00 .BPB_BIG_TOTAL_SECTORS_H EQU #22 ; WORD 0 BPB_TotSec32 BIG TOTAL SECTOR High word ; FAT 32 .SectorsPerFAT32 EQU #24 ; DWORD 4 BPB_FATSz32 FAT ᥪ -.MainFATnumber EQU #28 ; WORD 0 BPB_ExtFlags ⠡ FAT -.Version EQU #2A ; WORD 0 BPB_FSVer FAT32 (筮 0) -.RootDirStartCluster EQU #2C ; DWORD 2 BPB_RootClus ୥ ⠫ (筮 2) -.FSINFO_Sector EQU #30 ; WORD 1 BPB_FSInfo ᥪ FSINFO (筮 1) -.CopyBootSector EQU #32 ; WORD 6 BPB_BkBootSec ᥪ - 㧮筮 (筮 6) -.reserved_block: EQU #34 ; BLOCK 12 BPB_Reserved १ࢨ஢ -.FDD_Number EQU #40 ; BYTE 0 BS_DrvNum ᪮ 㭪権 BIOS -.reserved_2: EQU #41 ; BYTE 0 BS_Reserved1 १ࢨ஢ +.MainFATnumber 0 EQU #28 ; WORD 0 BPB_ExtFlags ⠡ FAT +.Version 0 EQU #2A ; WORD 0 BPB_FSVer FAT32 (筮 0) +.RootDirStartCluster 2 EQU #2C ; DWORD 2 BPB_RootClus ୥ ⠫ (筮 2) +.FSINFO_Sector 1 EQU #30 ; WORD 1 BPB_FSInfo ᥪ FSINFO (筮 1) +.CopyBootSector 6 EQU #32 ; WORD 6 BPB_BkBootSec ᥪ - 㧮筮 (筮 6) +.reserved_block: 0 EQU #34 ; BLOCK 12 BPB_Reserved १ࢨ஢ +.FDD_Number GenIOCTL.GetParams&#F0 EQU #40 ; BYTE 0 BS_DrvNum ᪮ 㭪権 BIOS +.reserved_2: 0 EQU #41 ; BYTE 0 BS_Reserved1 १ࢨ஢ .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.LABEL EQU #47 ; TEXT 11 BS_VolLab ⪠ ᪠ @@ -844,7 +844,45 @@ BOOT_SECTOR EQU #00 .FAT12_FDD EQU 1 .FAT12_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 祭: 1) tmp1 = ((.HIDDEN + min_last_sector) & #0F)>0 ) * #10 @@ -853,8 +891,179 @@ BOOT_SECTOR EQU #00 4) error = (tmp3 >= #1000'0000) ; LBA28 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 \ No newline at end of file diff --git a/tmp1.c b/tmp1.c new file mode 100644 index 0000000..6fb18a0 --- /dev/null +++ b/tmp1.c @@ -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, ¶ms)) { + 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, ¶ms, 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); +} \ No newline at end of file