Главная arrow Материалы arrow Спецификация файловых систем FAT12/16/32
- - - - - - -
- - - - - - -
Каталог ссылок
Ленты новостей
Ча.Во. (FAQ)
Java программы
Доска заказов программ
Лицензия Dllpiton
Кто на сайте?
Спецификация файловых систем FAT12/16/32 Печать E-mail

Hardware White Paper

Designing Hardware for Microsoft® Operating Systems

Microsoft Extensible Firmware Initiative Спецификация файловой системы FAT32

FAT: Описание формата данных на диске

Версия 1.03, 6 декабря 2000г.
Microsoft Corporation

Файловая система FAT (File Allocation Table) создавалась в конце 1970 - начале 1980 годов, и поддерживалась операционной системой Microsoft® MS-DOS®. Изначально она была создана для гибких дисков размером меньше чем 500K, но со временем развивалась для поддержки дисков всё больших и больших размеров. Сейчас уже существуют три типа FAT: FAT12, FAT16 и FAT32. Основные различия в типах FAT отражены в их названии - это размер (в битах) значений таблицы FAT. 12 бит в FAT12, 16 бит в FAT16, и 32 бит в FAT32.


Microsoft, MS_DOS, Windows, and Windows NT are trademarks or registered trademarks of Microsoft Corporation in the United States and/or other countries. Other product and company names mentioned herein may be the trademarks of their respective owners.

© 2000 Microsoft Corporation. All rights reserved.

Microsoft Extensible Firmware Initiative FAT32 File System Specification

IMPORTANT-READ CAREFULLY: This Microsoft Agreement (“Agreement”) is a legal agreement between you (either an individual or a single entity) and Microsoft Corporation (“Microsoft”) for the version of the Microsoft specification identified above which you are about to download (“Specification”). BY DOWNLOADING, COPYING OR OTHERWISE USING THE SPECIFICATION, YOU AGREE TO BE BOUND BY THE TERMS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO THE TERMS OF THIS AGREEMENT, DO NOT DOWNLOAD, COPY, OR USE THE SPECIFICATION.

The Specification is owned by Microsoft or its suppliers and is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties.


(a) Provided that you comply with all terms and conditions of this Agreement and subject to the limitations in Sections 1(c) - (f) below, Microsoft grants to you the following non-exclusive, worldwide, royalty-free, non-transferable, non-sublicenseable license under any copyrights owned or licensable by Microsoft without payment of consideration to unaffiliated third parties, to reproduce the Specification solely for the purposes of creating portions of products which comply with the Specification in unmodified form.

(b) Provided that you comply with all terms and conditions of this Agreement and subject to the limitations in Sections 1(c) - (f) below, Microsoft grants to you the following non-exclusive, worldwide, royalty-free, non-transferable, non-sublicenseable, reciprocal limited covenant not to sue under its Necessary Claims solely to make, have made, use, import, and directly and indirectly, offer to sell, sell and otherwise distribute and dispose of portions of products which comply with the Specification in unmodified form.

For purposes of sections (a) and (b) above, the Specification is “unmodified” if there are no changes, additions or extensions to the Specification, and “Necessary Claims” means claims of a patent or patent application which are (1) owned or licenseable by Microsoft without payment of consideration to an unaffiliated third party; and (2) have an effective filing date on or before December 31, 2010, that must be infringed in order to make a portion(s) of a product that complies with the Specification. Necessary Claims does not include claims relating to semiconductor manufacturing technology or microprocessor circuits or claims not required to be infringed in complying with the Specification (even if in the same patent as Necessary Claims).

(c) The foregoing covenant not to sue shall not extend to any part or function of a product which (i) is not required to comply with the Specification in unmodified form, or (ii) to which there was a commercially reasonable alternative to infringing a Necessary Claim.

(d) Each of the license and the covenant not to sue described above shall be unavailable to you and shall terminate immediately if you or any of your Affiliates (collectively “Covenantee Party”) “Initiates” any action for patent infringement against: (x) Microsoft or any of its Affiliates (collectively “Granting Party”), (y) any customers or distributors of the Granting Party, or other recipients of a covenant not to sue with respect to the Specification from the Granting Party (“Covenantees”); or (z) any customers or distributors of Covenantees (all parties identified in (y) and (z) collectively referred to as “Customers”), which action is based on a conformant implementation of the Specification. As used herein, “Affiliate” means any entity which directly or indirectly controls, is controlled by, or is under common control with a party; and control shall mean the power, whether direct or indirect, to direct or cause the direction of the management or policies of any entity whether through the ownership of voting securities, by contract or otherwise. “Initiates” means that a Covenantee Party is the first (as between the Granting Party and the Covenantee Party) to file or institute any legal or administrative claim or action for patent infringement against the Granting Party or any of the Customers. “Initiates” includes any situation in which a Covenantee Party files or initiates a legal or administrative claim or action for patent infringement solely as a counterclaim or equivalent in response to a Granting Party first filing or instituting a legal or administrative patent infringement claim against such Covenantee Party.

(e) Each of the license and the covenant not to sue described above shall not extend to your use of any portion of the Specification for any purpose other than (a) to create portions of an operating system (i) only as necessary to adapt such operating system so that it can directly interact with a firmware implementation of the Extensible Firmware Initiative Specification v. 1.0 (“EFI Specification”); (ii) only as necessary to emulate an implementation of the EFI Specification; and (b) to create firmware, applications, utilities and/or drivers that will be used and/or licensed for only the following purposes: (i) to install, repair and maintain hardware, firmware and portions of operating system software which are utilized in the boot process; (ii) to provide to an operating system runtime services that are specified in the EFI Specification; (iii) to diagnose and correct failures in the hardware, firmware or operating system software; (iv) to query for identification of a computer system (whether by serial numbers, asset tags, user or otherwise); (v) to perform inventory of a computer system; and (vi) to manufacture, install and setup any hardware, firmware or operating system software.

(f) Microsoft reserves all other rights it may have in the Specification and any intellectual property therein. The furnishing of this document does not give you any license or covenant not to sue with respect to any other Microsoft patents, trademarks, copyrights or other intellectual property rights.


(a)The foregoing license and covenant not to sue is applicable only to the version of the Specification which you are about to download. It does not apply to any additional versions of or extensions to the Specification.

(b)Without prejudice to any other rights, Microsoft may terminate this Agreement if you fail to comply with the terms and conditions of this Agreement. In such event you must destroy all copies of the Specification.

3. INTELLECTUAL PROPERTY RIGHTS. All ownership, title and intellectual property rights in and to the Specification are owned by Microsoft or its suppliers.

4. U.S. GOVERNMENT RIGHTS. Any Specification provided to the U.S. Government pursuant to solicitations issued on or after December 1, 1995 is provided with the commercial rights and restrictions described elsewhere herein. Any Specification provided to the U.S. Government pursuant to solicitations issued prior to December 1, 1995 is provided with RESTRICTED RIGHTS as provided for in FAR, 48 CFR 52.227-14 (JUNE 1987) or DFAR, 48 CFR 252.227-7013 (OCT 1988), as applicable.

5. EXPORT RESTRICTIONS. Export of the Specification, any part thereof, or any process or service that is the direct product of the Specification (the foregoing collectively referred to as the “Restricted Components”) from the United States is regulated by the Export Administration Regulations (EAR, 15 CFR 730-744) of the U.S. Commerce Department, Bureau of Export Administration (“BXA”). You agree to comply with the EAR in the export or re-export of the Restricted Components (i) to any country to which the U.S. has embargoed or restricted the export of goods or services, which currently include, but are not necessarily limited to Cuba, Iran, Iraq, Libya, North Korea, Sudan, Syria and the Federal Republic of Yugoslavia (including Serbia, but not Montenegro), or to any national of any such country, wherever located, who intends to transmit or transport the Restricted Components back to such country; (ii) to any person or entity who you know or have reason to know will utilize the Restricted Components in the design, development or production of nuclear, chemical or biological weapons; or (iii) to any person or entity who has been prohibited from participating in U.S. export transactions by any federal agency of the U.S. government. You warrant and represent that neither the BXA nor any other U.S. federal agency has suspended, revoked or denied your export privileges. For additional information see http://www.microsoft.com/exporting.

6. DISCLAIMER OF WARRANTIES. To the maximum extent permitted by applicable law, Microsoft and its suppliers provide the Specification (and all intellectual property therein) and any (if any) support services related to the Specification (“Support Services”) AS IS AND WITH ALL FAULTS, and hereby disclaim all warranties and conditions, either express, implied or statutory, including, but not limited to, any (if any) implied warranties or conditions of merchantability, of fitness for a particular purpose, of lack of viruses, of accuracy or completeness of responses, of results, and of lack of negligence or lack of workmanlike effort, all with regard to the Specification, any intellectual property therein and the provision of or failure to provide Support Services. ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT, QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT, WITH REGARD TO THE SPECIFICATION AND ANY INTELLECTUAL PROPERTY THEREIN. THE ENTIRE RISK AS TO THE QUALITY OF OR ARISING OUT OF USE OR PERFORMANCE OF THE SPECIFICATION, ANY INTELLECTUAL PROPERTY THEREIN, AND SUPPORT SERVICES, IF ANY, REMAINS WITH YOU.

7. EXCLUSION OF INCIDENTAL, CONSEQUENTIAL AND CERTAIN OTHER DAMAGES. To the maximum extent permitted by applicable law, in no event shall Microsoft or its suppliers be liable for any special, incidental, indirect, or consequential damages whatsoever (including, but not limited to, damages for loss of profits or confidential or other information, for business interruption, for personal injury, for loss of privacy, for failure to meet any duty including of good faith or of reasonable care, for negligence, and for any other pecuniary or other loss whatsoever) arising out of or in any way related to the use of or inability to use the SPECIFICATION, ANY INTELLECTUAL PROPERTY THEREIN, the provision of or failure to provide Support Services, or otherwise under or in connection with any provision of this AGREEMENT, even in the event of the fault, tort (including negligence), strict liability, breach of contract or breach of warranty of Microsoft or any supplier, and even if Microsoft or any supplier has been advised of the possibility of such damages.

8. LIMITATION OF LIABILITY AND REMEDIES. Notwithstanding any damages that you might incur for any reason whatsoever (including, without limitation, all damages referenced above and all direct or general damages), the entire liability of Microsoft and any of its suppliers under any provision of this Agreement and your exclusive remedy for all of the foregoing shall be limited to the greater of the amount actually paid by you for the Specification or U.S.$5.00. The foregoing limitations, exclusions and disclaimers shall apply to the maximum extent permitted by applicable law, even if any remedy fails its essential purpose.

9. APPLICABLE LAW. If you acquired this Specification in the United States, this Agreement is governed by the laws of the State of Washington. If you acquired this Specification in Canada, unless expressly prohibited by local law, this Agreement is governed by the laws in force in the Province of Ontario, Canada; and, in respect of any dispute which may arise hereunder, you consent to the jurisdiction of the federal and provincial courts sitting in Toronto, Ontario. If this Specification was acquired outside the United States, then local law may apply.

10.QUESTIONS. Should you have any questions concerning this Agreement, or if you desire to contact Microsoft for any reason, please contact the Microsoft subsidiary serving your country, or write: Microsoft Sales Information Center/One Microsoft Way/Redmond, WA 98052-6399.

11.ENTIRE AGREEMENT. This Agreement is the entire agreement between you and Microsoft relating to the Specification and the Support Services (if any) and they supersede all prior or contemporaneous oral or written communications, proposals and representations with respect to the Specification or any other subject matter covered by this Agreement. To the extent the terms of any Microsoft policies or programs for Support Services conflict with the terms of this Agreement, the terms of this Agreement shall control.

Si vous avez acquis votre produit Microsoft au CANADA, la garantie limitйe suivante vous concerne :

RENONCIATION AUX GARANTIES. Dans toute la mesure permise par la lйgislation en vigueur, Microsoft et ses fournisseurs fournissent la Specification (et а toute propriйtй intellectuelle dans celle-ci) et tous (selon le cas) les services d’assistance liйs а la Specification (“Services d’assistance”) TELS QUELS ET AVEC TOUS LEURS DЙFAUTS, et par les prйsentes excluent toute garantie ou condition, expresse ou implicite, lйgale ou conventionnelle, йcrite ou verbale, y compris, mais sans limitation, toute (selon le cas) garantie ou condition implicite ou lйgale de qualitй marchande, de conformitй а un usage particulier, d’absence de virus, d’exactitude et d’intйgralitй des rйponses, de rйsultats, d’efforts techniques et professionnels et d’absence de nйgligence, le tout relativement а la Specification, а toute propriйtй intellectuelle dans celle-ci et а la prestation ou а la non-prestation des Services d’assistance. DE PLUS, IL N’Y A AUCUNE GARANTIE ET CONDITION DE TITRE, DE JOUISSANCE PAISIBLE, DE POSSESSION PAISIBLE, DE SIMILARITЙ А LA DESCRIPTION ET D’ABSENCE DE CONTREFAЗON RELATIVEMENT А LA SPЙCIFICATION ET А TOUTE PROPRIЙTЙ INTELLECTUELLE DANS CELLE-CI. VOUS SUPPORTEZ TOUS LES RISQUES DЙCOULANT DE L’UTILISATION ET DE LA PERFORMANCE DE LA SPЙCIFICATION ET DE TOUTE PROPRIЙTЙ INTELLECTUELLE DANS CELLE-CI ET CEUX DЙCOULANT DES SERVICES D’ASSISTANCE (S’IL Y A LIEU).

EXCLUSION DES DOMMAGES INDIRECTS, ACCESSOIRES ET AUTRES. Dans toute la mesure permise par la lйgislation en vigueur, Microsoft et ses fournisseurs ne sont en aucun cas responsables de tout dommage spйcial, indirect, accessoire, moral ou exemplaire quel qu’il soit (y compris, mais sans limitation, les dommages entraоnйs par la perte de bйnйfices ou la perte d’information confidentielle ou autre, l’interruption des affaires, les prйjudices corporels, la perte de confidentialitй, le dйfaut de remplir toute obligation y compris les obligations de bonne foi et de diligence raisonnable, la nйgligence et toute autre perte pйcuniaire ou autre perte de quelque nature que ce soit) dйcoulant de, ou de toute autre maniиre liй а, l’utilisation ou l’impossibilitй d’utiliser la Spйcification, toute propriйtй intellectuelle dans celle-ci, la prestation ou la non-prestation des Services d’assistance ou autrement en vertu de ou relativement а toute disposition de cette convention, que ce soit en cas de faute, de dйlit (y compris la nйgligence), de responsabilitй stricte, de manquement а un contrat ou de manquement а une garantie de Microsoft ou de l’un de ses fournisseurs, et ce, mкme si Microsoft ou l’un de ses fournisseurs a йtй avisй de la possibilitй de tels dommages.

LIMITATION DE RESPONSABILITЙ ET RECOURS. Malgrй tout dommage que vous pourriez encourir pour quelque raison que ce soit (y compris, mais sans limitation, tous les dommages mentionnйs ci-dessus et tous les dommages directs et gйnйraux), la seule responsabilitй de Microsoft et de ses fournisseurs en vertu de toute disposition de cette convention et votre unique recours en regard de tout ce qui prйcиde sont limitйs au plus йlevй des montants suivants: soit (a) le montant que vous avez payй pour la Spйcification, soit (b) un montant йquivalant а cinq dollars U.S. (5,00 $ U.S.). Les limitations, exclusions et renonciations ci-dessus s’appliquent dans toute la mesure permise par la lйgislation en vigueur, et ce mкme si leur application a pour effet de priver un recours de son essence.


Tout Produit Logiciel fourni au gouvernement amйricain conformйment а des demandes йmises le ou aprиs le 1er dйcembre 1995 est offert avec les restrictions et droits commerciaux dйcrits ailleurs dans la prйsente convention. Tout Produit Logiciel fourni au gouvernement amйricain conformйment а des demandes йmises avant le 1er dйcembre 1995 est offert avec des DROITS LIMITЙS tels que prйvus dans le FAR, 48CFR 52.227-14 (juin 1987) ou dans le FAR, 48CFR 252.227-7013 (octobre 1988), tels qu’applicables.

Sauf lorsqu’expressйment prohibй par la lйgislation locale, la prйsente convention est rйgie par les lois en vigueur dans la province d’Ontario, Canada. Pour tout diffйrend qui pourrait dйcouler des prйsentes, vous acceptez la compйtence des tribunaux fйdйraux et provinciaux siйgeant а Toronto, Ontario.

Si vous avez des questions concernant cette convention ou si vous dйsirez communiquer avec Microsoft pour quelque raison que ce soit, veuillez contacter la succursale Microsoft desservant votre pays, ou йcrire а: Microsoft Sales Information Center, One Microsoft Way, Redmond, Washington 98052-6399.

Правила, принятые в этом документе

Числа, которые начинаются с “0x” являются шестнадцатеричными.

Числа без “0x” в начале, являются десятичными.

Фрагменты кода представленные в документе, написаны на языке программирования ‘C’. Нет строгой типизации и строгого синтаксиса.

Присутствуют несколько фрагментов кода, в которых используются одновременно 16 и 32 битные переменные. Предполагается, что вы программист, и понимаете, какие данные не потеряются при преобразовании из 32 в 16 битные значения. Также имейте в виду, что все переменные беззнаковые (UNSIGNED). Не производите вычислений FAT со знаковыми типами переменных, т.к. в некоторых случаях это даст неправильный результат.

Основные особенности (всех типов FAT)

Все файловые системы FAT изначально созданы для компьютеров архитектуры IBM PC. Поэтому особенностью FAT является то, что порядок бит в данных – от старших к младшим (little endian). Посмотрим на 32-битное значение FAT расположенное на диске, как серию из 4-х 8-битных байт—первым будет byte[0] и последним byte[4]— все 32 бита пронумерованы от 00 до 31 (00 самый младший разряд):

byte[3] 3 3 2 2 2 2 2 2

1 0 9 8 7 6 5 4

byte[2] 2 2 2 2 1 1 1 1

3 2 1 0 9 8 7 6

byte[1] 1 1 1 1 1 1 0 0

5 4 3 2 1 0 9 8

byte[0] 0 0 0 0 0 0 0 0

7 6 5 4 3 2 1 0

Это имеет значение, потому что когда FAT используется на компьютере с обратным порядком бит (big endian), то данные придётся транслировать между little endian и big endian при каждом чтении и записи на диск.

Файловая система FAT состоит из четырёх основных регионов, расположенных в данном порядке:

0 – Reserved Region

1 – FAT Region

2 – Root Directory Region (doesn’t exist on FAT32 volumes)

3 – File and Directory Data Region

Boot сектор и BPB

Первая важная структура на FAT диске называется BPB (BIOS Parameter Block), которая расположена в первом секторе диска, в Reserved Region. Этот сектор ещё иногда называют “boot сектор”, “reserved sector” или “0th sector,” но главное лишь то, что это первый сектор диска.

Первая вещь, которая часто вызывает вопросы. В MS-DOS версии 1.x, не было BPB. В этой первой версии было только два разных формата дисков: первый – односторонний, и второй – двухсторонний 360K 5.25-дюймовый гибкий диск. Определение типа диска происходило по значению из таблицы FAT (младшие 8 бит в FAT[0]).

Этот метод определения типа диска был заменён в MS-DOS версии 2.x путём внесения в boot сектор BPB, а старый метод определения (по первому байту FAT) больше не поддерживается. Все FAT диски должны иметь в boot секторе BPB.

Теперь возникает второй вопрос: Как точно выглядит BPB? BPB boot сектора для MS-DOS 2.x допускает только меньше 65,536 секторов (32 MB делённые на 512-байтные сектора). Это ограничение связано с тем, что поле “total sectors” является 16-битным. Данное ограничение относится и к MS-DOS 3.x, где BPB было модифицировано включением нового 32-битного поля.

Следующее изменение BPB было в операционной системе Microsoft Windows 95 OEM Service Release 2 (OSR2), где была представлена FAT32. FAT16 ограничен размером FAT и максимальным количеством кластеров, максимальным размером диска 2 GB на диске с 512-байтными секторами. FAT32 снимает ограничение на максимальный размер диска (раздела) 2 GB.

FAT32 BPB целиком соответствует FAT12/FAT16 BPB, и дополнен полем BPB_TotSec32. Они отличаются, начиная со смещения 36, где уже зависит от типа FAT12/FAT16 или FAT32 (описание определения типа FAT будет ниже). Главное, что BPB в boot секторе FAT диска всегда содержит все поля для FAT12/FAT16 or FAT32 BPB типов. Таким образом, обеспечена максимальная совместимость FAT дисков, драйверы файловых систем FAT будут правильно определять и поддерживать структуру, потому что она содержит все предопределённые поля.

ЗАМЕТКА: В дальнейшем описании, все поля, начинающиеся с BPB_, являются частью BPB. Все поля, начинающиеся с BS_, являются частью boot сектора (к BPB не принадлежат). Далее показано начало сектора 0 на FAT диске, содержащего BPB:

Boot сектор и BPB структура




Размер (байт)





Jump инструкция на boot code. Это поле имеет две формы:

jmpBoot[0] = 0xEB, jmpBoot[1] = 0x??, jmpBoot[2] = 0x90


jmpBoot[0] = 0xE9, jmpBoot[1] = 0x??, jmpBoot[2] = 0x??

0x?? значит что допустимо любое 8-битное значение.

Это трёхбайтное поле для Intel x86 команды перехода (jump) на начало загрузочного кода операционной системы. Этот код обычно находится в секторе 0 сразу после BPB, и возможно в других секторах. Допустима любая из приведённых форм. Наиболее часто используется JmpBoot[0] = 0xEB.




MSWIN4.1” Существует много мнений об этом поле. Но это только строка имени. Microsoft ОС не строит ни каких выводов из содержания этого поля. Но некоторые драйверы FAT делают, поэтому есть резон указывать “MSWIN4.1”, для совместимости. Эта строка ещё является косвенным признаком того, что диск форматирован.




Количество байтов в секторе. Допустимы только эти значения: 512, 1024, 2048 or 4096. Если нужна максимальная совместимость со старыми программами, то должно использоваться только 512. В мире существует много программ, которые жёстко рассчитаны на значение 512. Microsoft ОС корректно поддерживают все допустимые значения.

Note: Не ошибитесь в понимании максимальной совместимости. Если диск отформатирован с физическим размером секторов N, вы должны использовать именно значение N, вплоть до значения 4096. Максимальная совместимость достигается использованием дисков с обычным размером сектора.




Количество секторов в кластере. Значение должно быть числом в степени 2, и больше 0. Разрешённые значения: 1, 2, 4, 8, 16, 32, 64 и 128. Учтите при этом, что произведение “байтов в кластере” (BPB_BytsPerSec * BPB_SecPerClus) должно быть не больше 32K (32 * 1024). Неправильно считать, что большее значение допустимо. Значения, дающие размер кластера больше 32K не будут правильно работать; не пробуйте их использовать. Некоторые системы допускают размер кластера 64K, но многие установочные программы будут работать не правильно.




Количество секторов в Reserved region (начинается с первого сектора диска). Должно быть больше 0. Для FAT12 и FAT16 дисков, это значение должно быть только 1. Для FAT32 дисков, обычное значение 32. В мире есть много программ для FAT12 и FAT16, в которые жёстко настроены на значение 1, не проверяя фактическое значение этого поля. Microsoft ОС корректно обрабатывает любое значение.




Количество таблиц FAT на диске. Должно быть 2 для любой FAT. Хотя и допустимы и другие значения, многие программы и системы не будут корректно работать. Все Microsoft системы корректно работают с любым значением, тем не менее, рекомендуемое значение 2.

Значение 2 даёт избыточность FAT структуры, при этом в случае потери сектора, данные не потеряются, потому что они дублированы. На не-дисковых носителях, например карта памяти FLASH, где избыточность не требуется, для экономии памяти может использоваться значение 1, но некоторые драйверы FAT могут работать неправильно.




Для FAT12 и FAT16 дисков, это поле содержит число 32-байтных элементов корневой директории. Для FAT32 дисков, это поле должно быть 0. Для FAT12 и FAT16 дисков, значение этого поля, умноженное на 32 должно быть кратно BPB_BytsPerSec. Для максимальной совместимости, FAT16 диски должны содержать значение 512.




Старое 16-битное поле: общее количество секторов на диске. Это количество включает в себя все четыре региона диска. Значение не 0; но если равно 0, то BPB_TotSec32 должно быть не 0. Для FAT32 дисков, значение всегда 0. Для FAT12 и FAT16 дисков это поле содержит количество секторов, а BPB_TotSec32 равно 0, если значение «умещается» (меньше 0x10000).




0xF8 стандартное значение для “жёстких” (не сменных) дисков. Для сменных дисков, обычное значение 0xF0. Разрешённые значения: 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE и 0xFF. Важно, чтобы это же значение было записано в байт таблицы FAT[0]. Это старое правило появилось MS-DOS 1.x для определения типа диска (как рассказано в начале), но сейчас не имеет практического применения.




Для FAT12/FAT16 это количество секторов одной FAT. Для FAT32 это значение равно 0, а количество секторов одной FAT содержится в BPB_FATSz32.




Секторов на дорожке, для interrupt 0x13. Это поле имеет отношение к дискам, имеющим геометрию (состоит из треков, головок и цилиндров) и доступным через interrupt 0x13. Поле содержит геометрическое значение “sectors per track”.




Количество головок, для interrupt 0x13. Это имеет такое же значение, как и BPB_SecPerTrk. Поле содержит геометрическое значение “count of heads”. Например, у 1.44 MB 3.5-дюймового гибкого диска оно равно 2.




Количество скрытых секторов, перед началом данного раздела диска. Это поле имеет отношение только к дискам, доступным по interrupt 0x13. Поле должно содержать 0, если носитель не разбит на разделы. Это поле только для операционной системы.




Новое 32-битное поле: общее количество секторов на диске. Это количество включает в себя все четыре региона диска. Может быть 0; если 0, то BPB_TotSec16 должно быть не 0. Для FAT32 дисков, значение всегда не 0. Для FAT12/FAT16 дисков, поле содержит количество секторов, когда BPB_TotSec16 равно 0 (количество равно или больше 0x10000).

С этой отметки, BPB/boot сектор для FAT12 и FAT16 отличаются от BPB/boot сектора для FAT32. Первая таблица показывает структуру FAT12 и FAT16 со смещения 36 boot сектора.

Структура Fat12 и Fat16 со смещения 36




Размер (байт)





Int 0x13 номер устройства (например 0x80). Это поле для загрузчика MS-DOS, и устанавливает для INT 0x13 номер диска (0x00 для гибких дисков, 0x80 для жёстких дисков).
ЗАМЕТКА: Это поле только для операционной системы.




Зарезервировано (используется Windows NT). Форматирующие программы FAT дисков, всегда должны устанавливать 0.




Дополнительная сигнатура (0x29). Байт является индикатором того, что нижеследующие 3 поля присутствуют.




Серийный номер диска. Это поле вместе с BS_VolLab позволяет отслеживать смену диска, и отслеживать моменты, когда вставлен другой диск. Этот номер обычно генерируется путём комбинации текущей даты и времени в 32-битное число.




Имя диска. Это имя совпадает с 11-байтным именем, прописанным в корневой директории.
ЗАМЕТКА: Драйверы FAT должны не забывать обновлять это поле, при изменении имени в корневой директории. Когда имя не задано, поле содержит строкуNO NAME ”.




Одна из строкFAT12 ”, “FAT16 илиFAT ”. ЗАМЕТКА: Многие люди считают, что эта строка для определения типа FATFAT12, FAT16 или FAT32—на диске. Это не так. Заметьте, что это поле вообще не является частью BPB. Это строка только для общей информации, и программы Microsoft вообще не используют это поле для определения типа FAT, потому что оно часто не корректное, или даже отсутствует. Смотрите в этом документе главу Определение типа FAT. Эту строку нужно устанавливать в соответствии с типом FAT, потому что некоторые не-Microsoft драйверы FAT используют это поле.

Структура для FAT32, начиная со смещения 36 boot сектора.

Структура FAT32 со смещения 36




Размер (байт)





Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16. Это 32-битное поле FAT32 содержит количество секторов одной FAT. При этом BPB_FATSz16 должно быть 0.




Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16.

Bits 0-3 -- Номер активной FAT, начиная с 0. Актуально, только если выключено зеркалирование.

Bits 4-6 -- Зарезервировано.

Bit 7 -- 0 значит FAT зеркалируется на все остальные.

-- 1 означает, что активна только одна FAT; её номер указывается в битах 0-3.

Bits 8-15 -- Зарезервировано.




Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16. В старшем байте: номер версии. Младший байт: номер промежуточной версии. Это версия FAT32. Это даёт расширять в будущем систему FAT32, и возможность корректно обрабатывать каждую старую версию. Этот документ описывает версию 0:0. Если в этом поле не 0, то предыдущие версии Windows не подключат этот диск.

ЗАМЕТКА: Дисковые утилиты должны внимательно ориентироваться на версию, и не работать с версией, с которой не совместимы.




Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16. Номер первого кластера корневой директории. Обычно 2, но может быть и другим.

ЗАМЕТКА: Дисковые утилиты, которые изменяют положение корневой директории, должны стараться в качестве первого кластера использовать не повреждённый кластер. Специально для того, чтобы в случае аварийного обнуления поля, утилита исправления диска смогла легко найти начало директории.




Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16. Номер сектора со структурой FSINFO в зарезервированной части FAT32. Обычно 1.

ЗАМЕТКА: Резервная копия структуры FSINFO располагается в BackupBoot, но только копия, на которую указывается это поле, обновляется постоянно (можно считать основной и этот резервный сектор как один и тот же).




Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16. Если не ноль, то это номер сектора в резервной области диска, где хранится копия boot сектора. Обычно 6. Другие значения не рекомендуются.




Это поле есть только в FAT32, и отсутствует в FAT12 и FAT16. Reserved for future expansion. Code that formats FAT32 volumes should always set all of the bytes of this field to 0.




Это поле такое же, как в FAT12 и FAT16. Отличие только в том, что у него другое смещение.




Это поле такое же, как в FAT12 и FAT16. Отличие только в том, что у него другое смещение.




Это поле такое же, как в FAT12 и FAT16. Отличие только в том, что у него другое смещение.




Это поле такое же, как в FAT12 и FAT16. Отличие только в том, что у него другое смещение.




Это поле такое же, как в FAT12 и FAT16. Отличие только в том, что у него другое смещение.




В этой строке всегда FAT32 ”. Смотрите описание этого поля в FAT12/FAT16. Это поле не используется для определения типа FAT.

Нет ни чего специфичного в Секторе 0 диска FAT. Рассматривая сектор как массив байт, sector[510] содержит 0x55, а sector[511] содержит 0xAA.

ЗАМЕТКА: Во многих описаниях FAT ошибочно говорится, что сигнатура 0xAA55 расположена в “последних 2 байтах boot сектора”. Это верно, если — и только если — BPB_BytsPerSec равняется 512. Если BPB_BytsPerSec больше чем 512, смещение этой сигнатуры не изменяется (хотя допустимо, что и в конце сектора эта сигнатура тоже будет присутствовать).

Обратите внимание на поле BPB_TotSec16/32. Предположим, мы имеем диск или раздел с количеством секторов DskSz. Если поле BPB TotSec (BPB_TotSec16 или BPB_TotSec32 — которое не нулевое) меньше или равно DskSz, то ни какой ошибки в FAT нет. Ни чего страшного, если значение BPB_TotSec16/32 немного меньше DskSz. Так же, совершенно нормально, если BPB_TotSec16/32 будет значительно меньше DskSz.

Это означает лишь, что часть дискового пространства не используется. Это не означает, что диск FAT повреждён. Однако, если BPB_TotSec16/32 больше чем DskSz, то диск серьёзно повреждён или искажён, потому что он расширен за границу носителя, или перекрывает данные следующего раздела. Использование диска, у которого BPB_TotSec16/32 “слишком большое” для носителя или данного раздела, может повлечь катастрофичную потерю данных.

Структура FAT

Теперь рассмотрим саму структуру FAT. Структура содержит однонаправленные списки “блоков” (кластеров) файлов. Директория (или контейнер файлов) FAT представляет собой не что иное, а обычный файл, со специальным атрибутом «директория». Особенностью директории является то, что хранимые данные (файлы) представляют собой массив 32-байтных структур (их описание ниже). Во всём остальном, директория ни чем не отличается от файла. FAT распределяет данные по номерам кластеров. Номер самого первого кластера 2.

Первый сектор кластера 2 (в регионе данных) вычисляется через поля BPB как описано ниже. Сначала определяем количество секторов, занятых корневой директорией:

RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec;

Заметьте, что в FAT32 поле BPB_RootEntCnt всегда содержит 0, поэтому для FAT32 RootDirSectors всегда 0. Здесь число 32 это размер одного элемента директории FAT (в байтах). Также заметьте, что округление производится вверх.

Начало региона данных, первый сектор кластера 2, вычисляется так:

If(BPB_FATSz16 != 0)




FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors;

ЗАМЕТКА: Этот номер сектора является относительным номеру сектора, содержащим BPB (считаем номер сектора BPB равным 0). Не считайте, что это номер от начала носителя, потому что сектор 0 диска не обязательно является сектором 0 носителя, делённого на разделы.

Имея номер кластера N, номер первого сектора этого кластера (опять же относительно сектора 0 диска) вычисляется так:

FirstSectorofCluster = ((N – 2) * BPB_SecPerClus) + FirstDataSector;

ЗАМЕТКА: Поскольку значение BPB_SecPerClus ограничено степенью 2 (1,2,4,8,16,32….), значит, умножения и деления над BPB_SecPerClus можно производить операцией двоичного сдвига SHIFT на процессорах, где эта операция быстрей операций MULT и DIV. На современных Intel X86 процессорах, это не имеет большого смысла, поскольку машинные инструкции MULT и DIV сильно оптимизированы для операций над значениями в степени 2.

Определение типа FAT

Существует много ошибочных мнений, как именно это производится, и возникают погрешности “на 1”, “на 2”, “на 10” и “очень большие”. На самом деле принцип простой. Тип FAT—один из FAT12, FAT16 или FAT32—определяется по количеству кластеров на диске, и ни чем иным.

Читайте внимательно, здесь много тонких моментов. Например, “число кластеров”. Это не то же самое, что и “максимальный номер кластера”, потому что кластеры начинают считаться с 2, а не 0 или 1.

Для начала, давайте посмотрим, как именно определяется “число кластеров”. Это определяется из полей BPB диска. Сначала, определяем количество секторов, занимаемых корневой директорией, как было показано выше.

RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec;

Заметьте, что в FAT32 поле BPB_RootEntCnt всегда содержит 0, поэтому для FAT32 RootDirSectors всегда 0.

Затем, определяем количество секторов в регионе данных диска:

If(BPB_FATSz16 != 0)




If(BPB_TotSec16 != 0)

TotSec = BPB_TotSec16;


TotSec = BPB_TotSec32;

DataSec = TotSec – (BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors);

Теперь определяем количество кластеров:

CountofClusters = DataSec / BPB_SecPerClus;

Заметьте, что это вычисление округляет вниз.

Теперь мы можем определить тип FAT. Пожалуйста, читайте внимательно, чтобы не получить ошибку погрешности на 1!

К примеру, когда мы говорим <, это не означает <=. Также будьте уверены, что все числа правильные. Первое число для FAT12 это 4085; второе число для FAT16 это 65525. Эти номера и знак ‘<’ не ошибочны.

If(CountofClusters < 4085) {

/* Volume is FAT12 */

} else if(CountofClusters < 65525) {

/* Volume is FAT16 */

} else {

/* Volume is FAT32 */


Это один и единственный способ определения типа FAT. Не бывает дисков FAT12, у которых кластеров больше 4 084. Не бывает дисков FAT16, у которых кластеров меньше 4 085 или больше 65 524. Не бывает дисков FAT32, у которых кластеров меньше 65 525. Если вы создадите диск FAT, который не соответствует этим правилам, то Microsoft системы будут с ними работать не правильно, т.к. станут считать что это FAT другого типа, чем считаете Вы.

ЗАМЕТКА: Как уже несколько раз было сказано, мир наполнен большим количеством ошибочного кода для FAT. Много кода с погрешностью 1, 2, 8, 10 или 16. Поэтому очень рекомендуется форматировать диски FAT с учетом максимальной совместимости с существующим кодом, и стараться избегать создания дисков с количеством кластеров, близким к 4 085 или 65 525. Используйте значения кластеров на 16 больше или меньше от этих граничных чисел.

Заметьте также, что значение CountofClusters—именно количество кластеров данных, которые начинаются с номера 2. Максимальный номер кластера на диске равен CountofClusters + 1, а “количество кластеров, включая 2 резервных” равно CountofClusters + 2.

Покажем ещё одно важное вычисление. Имея номер кластера N, как найти входную точку в таблице FAT? Из всех типов FAT, только FAT12 представляет сложность. Для FAT16 и FAT32 вычисления простые:

If(BPB_FATSz16 != 0)




If(FATType == FAT16)

FATOffset = N * 2;

Else if (FATType == FAT32)

FATOffset = N * 4;

ThisFATSecNum = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);

ThisFATEntOffset = REM(FATOffset / BPB_BytsPerSec);

REM(…) это оператор остатка от деления. Так получаем остаток от деления FATOffset на BPB_BytsPerSec. ThisFATSecNum это номер сектора, содержащий входную точку кластера N в первой таблице FAT. Если вы хотите получить номер сектора во второй FAT, вам нужно прибавить FATSz к ThisFATSecNum; для третьей FAT, вы прибавите 2*FATSz, и так далее.

Выполните чтение сектора номер ThisFATSecNum (помните, что это номер относительно сектора 0 диска). Считаем, что прочитали в массив 8-битных байтов SecBuff. Также считаем, что WORD является 16-битным беззнаковым, а DWORD 32-битным беззнаковым.

If(FATType == FAT16)

FAT16ClusEntryVal = *((WORD *) &SecBuff[ThisFATEntOffset]);


FAT32ClusEntryVal = (*((DWORD *) &SecBuff[ThisFATEntOffset])) & 0x0FFFFFFF;

Прочитали значение кластера. Запись значения в тот же кластер делается так:

If(FATType == FAT16)

*((WORD *) &SecBuff[ThisFATEntOffset]) = FAT16ClusEntryVal;

Else {

FAT32ClusEntryVal = FAT32ClusEntryVal & 0x0FFFFFFF;

*((DWORD *) &SecBuff[ThisFATEntOffset]) =

(*((DWORD *) &SecBuff[ThisFATEntOffset])) & 0xF0000000;

*((DWORD *) &SecBuff[ThisFATEntOffset]) =

(*((DWORD *) &SecBuff[ThisFATEntOffset])) | FAT32ClusEntryVal;


Поясним работу кода для FAT32. У FAT32, значения FAT занимают только 28 бит, а старшие 4 бита зарезервированы. Данные в старшие 4 бита FAT32 значений FAT записываются только при форматировании диска, при этом все биты просто обнуляются.

Здесь дадим ещё немного пояснений о значениях FAT для FAT32. В общем, 32-битные FAT значения содержат не совсем 32-битные значения; из них используются только 28 бит. К примеру, все эти 32-битные номера кластеров: 0x10000000, 0xF0000000 и 0x00000000 являются свободными (FREE), потому что старшие 4 бита должны игнорироваться. Если 32-битный свободный кластер содержит значение 0x30000000, и Вы хотите пометить его как «BAD CLUSTER» значением 0x0FFFFFF7, то в результате 32-битное значение получится 0x3FFFFFF7, потому что Вы должны оставить неизменным значение в старших 4 битах, записывая значение 0x0FFFFFF7 «BAD CLUSTER».

Заметим, что поскольку значение BPB_BytsPerSec всегда кратно 2 и 4, то для FAT16 и FAT32 значений FAT можно не беспокоиться об их расположении на границе между секторами (но не для FAT12).

Код для FAT12 более сложный, потому что здесь 1,5 байт (12-бит) на каждое значение FAT.

if (FATType == FAT12)

FATOffset = N + (N / 2);

/* Multiply by 1.5 without using floating point, the divide by 2 rounds DOWN */

ThisFATSecNum = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);

ThisFATEntOffset = REM(FATOffset / BPB_BytsPerSec);

Теперь нужно проверить пересечение значением границы сектора:

If(ThisFATEntOffset == (BPB_BytsPerSec – 1)) {

/* This cluster access spans a sector boundary in the FAT */

/* There are a number of strategies to handling this. The */

/* easiest is to always load FAT sectors into memory */

/* in pairs if the volume is FAT12 (if you want to load */

/* FAT sector N, you also load FAT sector N+1 immediately */

/* following it in memory unless sector N is the last FAT */

/* sector). It is assumed that this is the strategy used here */

/* which makes this if test for a sector boundary span */

/* unnecessary. */


Обращаемся к значению FAT как к WORD (также как в FAT16), но если номер кластера ЧЁТНЫЙ, мы используем только младшие 12 бит из 16-битного прочитанного значения; и если номер кластера НЕЧЁТНЫЙ, мы используем только старшие 12 бит.

FAT12ClusEntryVal = *((WORD *) &SecBuff[ThisFATEntOffset]);

If(N & 0x0001)

FAT12ClusEntryVal = FAT12ClusEntryVal >> 4; /* Cluster number is ODD */


FAT12ClusEntryVal = FAT12ClusEntryVal & 0x0FFF; /* Cluster number is EVEN */

Прочитали значение кластера. Запись значения в тот же кластер делается так:

If(N & 0x0001) {

FAT12ClusEntryVal = FAT12ClusEntryVal << 4; /* Cluster number is ODD */

*((WORD *) &SecBuff[ThisFATEntOffset]) =

(*((WORD *) &SecBuff[ThisFATEntOffset])) & 0x000F;

} Else {

FAT12ClusEntryVal = FAT12ClusEntryVal & 0x0FFF; /* Cluster number is EVEN */

*((WORD *) &SecBuff[ThisFATEntOffset]) =

(*((WORD *) &SecBuff[ThisFATEntOffset])) & 0xF000;


*((WORD *) &SecBuff[ThisFATEntOffset]) =

(*((WORD *) &SecBuff[ThisFATEntOffset])) | FAT12ClusEntryVal;

ЗАМЕТКА: Полагаем, что оператор >> заполнит значением 0 старшие 4 бита, а оператор << заполнит значением 0 младшие 4 бита.

Данные файла ассоциируются с файлом следующим образом. В директории содержится номер первого кластера, в котором располагаются данные файла. Данные первого кластера ассоциированы с номером первого кластера, и расположение данных вычисляется из номера первого кластера, как было показано выше (вычисление FirstSectorofCluster).

Файлы нулевой длинны (файлы, не содержащие данных) имеют в директории номер первого кластера 0. Кластер, расположенный в FAT (смотри вычисление ThisFATSecNum и ThisFATEntOffset) может содержать значение EOC (End Of Clusterchain – конец цепочки кластеров) или номер следующего кластера файла. Значение EOC зависит от типа FAT (здесь FATContent является значением кластера прочитанного из FAT, для проверки на значение EOC):


If(FATType == FAT12) {

If(FATContent >= 0x0FF8)


} else if(FATType == FAT16) {

If(FATContent >= 0xFFF8)


} else if (FATType == FAT32) {

If(FATContent >= 0x0FFFFFF8)



Номер кластера, по которому в таблице FAT содержится значение EOC, содержит данные файла, и является последним кластером файла. Microsoft системные драйвера FAT используют такие EOC значения: 0x0FFF для FAT12, 0xFFFF для FAT16, 0x0FFFFFFF для FAT32. Однако существуют дисковые утилиты для Microsoft ОС, которые используют другие значения.

Опишем специальное значение “BAD CLUSTER”. Все кластеры, содержащие значение “BAD CLUSTER” в FAT, не должны присутствовать в списке свободных кластеров, т.к. это вызовет ошибку работы с диском. Значения “BAD CLUSTER”: 0x0FF7 для FAT12, 0xFFF7 для FAT16, 0x0FFFFFF7 для FAT32. Эти “BAD CLUSTER” похожи на потерянные кластеры, и выглядят как распределённые, потому что содержат ненулевые данные. Дисковые утилиты должны считать потерянные кластеры со специальным значением “BAD CLUSTER” не доступными, и не должны изменять их данные.

ЗАМЕТКА: Значение “BAD CLUSTER” не может входить в диапазон доступных кластеров на дисках FAT12 и FAT16, но значение 0x0FFFFFF7 может быть доступным кластером на дисках FAT32. Для исключения конфликтов с дисковыми утилитами, на дисках FAT32 кластер 0x0FFFFFF7 использоваться не должен.

Список свободных кластеров FAT это просто все кластеры, которые содержат значение 0 в таблице FAT. Эти значения считываются точно так же, было описано выше для ненулевых значений. Список свободных кластеров ни где отдельно не хранится; он должен вычисляться каждый раз при подключении диска к системе, путём сканирования в таблице FAT всех значений 0. На дисках FAT32, в секторе BPB_FSInfo может содержаться актуальное количество свободных кластеров. Смотрите документацию на сектор FAT32 FSInfo.

Что содержат первые два зарезервированные кластера в таблице FAT? Первый зарезервированный кластер, FAT[0], содержит значение BPB_Media в младших 8 битах, а все остальные биты содержат 1. К примеру, если BPB_Media значение 0xF8, то для FAT12 FAT[0] = 0x0FF8, для FAT16 FAT[0] = 0xFFF8, а для FAT32 FAT[0] = 0x0FFFFFF8. Во второй зарезервированный кластер, FAT[1], FORMAT устанавливает значение EOC. На дисках FAT12 он не используется, потому что содержит только лишь значение EOC. На дисках FAT16 и FAT32, драйвер файловой системы может использовать старшие два бита в FAT[1] для индикаторов «корректности» (остальные биты содержат 1). Заметьте, что расположение битов для FAT16 и FAT32 разное, потому что они занимают старшие 2 бита.

Для FAT16:

ClnShutBitMask = 0x8000;

HrdErrBitMask = 0x4000;

Для FAT32:

ClnShutBitMask = 0x08000000;

HrdErrBitMask = 0x04000000;

Бит ClnShutBitMaskЕсли 1, дискчист”.
Если 0, дискгрязен”. Это признак того, что диск не был корректно отключен (Dismount) после последнего подключения. Это хороший повод для запуска для него утилиты проверки и исправления Chkdsk/Scandisk, потому что он возможно повреждён.

Бит HrdErrBitMaskЕсли 1, ошибок чтения/записи не было.
Если 0, в драйвере файловой системы произошла ошибка чтения/записи диска, что является индикатором того, что некоторые секторы испортились. Это хороший повод для запуска утилиты Chkdsk/Scandisk для проверки поверхности диска и поиска испорченных секторов.

Два важных замечания о регионе FAT на диске:

  1. Последний сектор FAT не обязательно весь занят таблицей FAT. В последнем секторе, FAT заканчивается на номере последнего кластера FAT, который равен CountofClusters + 1 (смотри вычисление CountofClusters выше), и это значение FAT не обязательно расположено в конце последнего сектора таблицы FAT. FAT драйвер не должен предполагать, что остаток последнего FAT сектора, после кластера CountofClusters + 1 заполнен определёнными значениями. Программа FAT format остаток сектора должна обнулять.

  2. BPB_FATSz16 (BPB_FATSz32 для FAT32) значение может быть больше, чем требуется. Другими словами, здесь могут быть полностью неиспользуемые секторы FAT в конце каждой таблицы FAT в регионе FAT диска. Поэтому, последний сектор таблицы FAT всегда вычисляется от значения CountofClusters + 1, а не от BPB_FATSz16/32. FAT драйвер не должен предполагать, что «лишние» FAT сектора заполнены определёнными значениями. Программа FAT format «лишние» сектора должна обнулять.

Разметка нового FAT диска

К этому моменту, у внимательного читателя возникнет интересный вопрос. Тип FAT (FAT12, FAT16, or FAT32) зависит от количества кластеров — а количество секторов региона данных зависит от размера таблицы FAT — когда имеется неформатированный диск без BPB, как всё это вычислить, и записать правильные значения в BPB_SecPerClus, BPB_FATSz16 (или BPB_FATSz32)? Microsoft ОС делает вычисления, используя фиксированные значения, некоторые таблицы, и немного арифметики.

Microsoft ОС делает FAT12 только на гибких дисках. Поскольку форматов гибких дисков существует ограниченное количество, и они имеют фиксированный размер, то считается так:

Если гибкий диск такого типа, то BPB выглядит так.”

Не делается динамических вычислений FAT12. Для FAT12, все вычисления для BPB_SecPerClus и BPB_FATSz16 делаются на бумаге, и вносятся в таблицы (внимательно следя, чтобы количество кластеров было меньше 4085). Если носитель размером больше 4 MB, не используйте FAT12. Используйте меньшие значения BPB_SecPerClus, чтобы получился FAT16.

Остаток этой главы целиком специфичен для дисков с размером сектора 512 байт. Вы не можете использовать эти таблицы и вычисления для дисков, имеющих другой размер сектора. “Фиксированные значения” это просто размеры дисков “разделяющие FAT16 и FAT32”. Все значения, которые меньше, являются дисками FAT16, и все значения равные или больше, являются дисками FAT32. В Windows, это значение 512 MB. Любые FAT диски меньше 512 MB являются FAT16, и любые FAT диски размером of 512 MB или больше, являются FAT32.

Пожалуйста, не сделайте ложных выводов.

Многие диски FAT16 имеют размер больше 512 MB. Есть возможность использования формата FAT16 вместо FAT32, программы могут не использовать этот лимит. В данном случае речь идёт о формате по умолчанию для MS-DOS и Windows дисков, которые ещё не форматированы. Здесь две таблицы — одна для FAT16 и другая для FAT32. Значениями в этих таблицах являются размеры дисков в 512 байтных секторах (значения для полей BPB_TotSec16 или BPB_TotSec32), а производные значения являются BPB_SecPerClus.


DWORD DiskSize;

BYTE SecPerClusVal;



*This is the table for FAT16 drives. NOTE that this table includes

* entries for disk sizes larger than 512 MB even though typically

* only the entries for disks < 512 MB in size are used.

* The way this table is accessed is to look for the first entry

* in the table for which the disk size is less than or equal

* to the DiskSize field in that table entry. For this table to

* work properly BPB_RsvdSecCnt must be 1, BPB_NumFATs

* must be 2, and BPB_RootEntCnt must be 512. Any of these values

* being different may require the first table entries DiskSize value

* to be changed otherwise the cluster count may be to low for FAT16.



{ 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal trips an error */

{ 32680, 2}, /* disks up to 16 MB, 1k cluster */

{ 262144, 4}, /* disks up to 128 MB, 2k cluster */

{ 524288, 8}, /* disks up to 256 MB, 4k cluster */

{ 1048576, 16}, /* disks up to 512 MB, 8k cluster */

/* The entries after this point are not used unless FAT16 is forced */

{ 2097152, 32}, /* disks up to 1 GB, 16k cluster */

{ 4194304, 64}, /* disks up to 2 GB, 32k cluster */

{ 0xFFFFFFFF, 0} /* any disk greater than 2GB, 0 value for SecPerClusVal trips an error */



* This is the table for FAT32 drives. NOTE that this table includes

* entries for disk sizes smaller than 512 MB even though typically

* only the entries for disks >= 512 MB in size are used.

* The way this table is accessed is to look for the first entry

* in the table for which the disk size is less than or equal

* to the DiskSize field in that table entry. For this table to

* work properly BPB_RsvdSecCnt must be 32, and BPB_NumFATs

* must be 2. Any of these values being different may require the first

* table entries DiskSize value to be changed otherwise the cluster count

* may be to low for FAT32.



{ 66600, 0}, /* disks up to 32.5 MB, the 0 value for SecPerClusVal trips an error */

{ 532480, 1}, /* disks up to 260 MB, .5k cluster */

{ 16777216, 8}, /* disks up to 8 GB, 4k cluster */

{ 33554432, 16}, /* disks up to 16 GB, 8k cluster */

{ 67108864, 32}, /* disks up to 32 GB, 16k cluster */

{ 0xFFFFFFFF, 64}/* disks greater than 32GB, 32k cluster */


Так для данного размера диска FAT (FAT16 или FAT32), мы теперь имеем значение BPB_SecPerClus. Только одну вещь нам осталось вычислить – количество секторов для таблицы FAT (BPB_FATSz16 или BPB_FATSz32). Считаем, что поля BPB_RootEntCnt, BPB_RsvdSecCnt и BPB_NumFATs уже корректно установлены. Так же считаем, что DskSize содержит размер диска, который будем записывать в BPB_TotSec32 или BPB_TotSec16.

RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec;

TmpVal1 = DskSize – (BPB_ResvdSecCnt + RootDirSectors);

TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;

If(FATType == FAT32)

TmpVal2 = TmpVal2 / 2;

FATSz = (TMPVal1 + (TmpVal2 – 1)) / TmpVal2;

If(FATType == FAT32) {

BPB_FATSz16 = 0;


} else {


/* there is no BPB_FATSz32 in a FAT16 BPB */


Не тратьте много времени на разбор данного кода. Базис этих вычислений сложен; мы просто показали, как это делает Microsoft ОС, и как это работает. Однако заметим, что в приведённом коде имеются недостатки. В некоторых случаях для FAT16 FATSz получается на 2 сектора больше чем нужно, а также для FAT32 иногда получается на 8 секторов больше необходимого. Главное, что FATSz не бывает меньше необходимого. Поскольку допустимо иметь FATSz больше необходимого, то ценой потери нескольких секторов мы получаем запас, который в некоторых случаях может пригодиться.

Структура сектора FAT32 FSInfo и сектора Backup Boot

На диске FAT32, таблица FAT может иметь значительный размер, в отличие от FAT16 ограниченного размером 128K, и FAT12 ограниченного размером 6K. Поэтому есть резон хранить “последнее известное” количество свободных кластеров диска FAT32, чтобы не вычислять его каждый раз, когда функции API запрашивают размер свободного места на диске (например, в конце вывода содержимого директории). Номер сектора FSInfo хранится в поле BPB_FSInfo; в Microsoft ОС оно всегда равно 1. Это структура сектора FSInfo:

FAT32 FSInfo Sector Structure and Backup Boot сектор




Размер (байт)





Значение 0x41615252. Это начальная сигнатура для точного определения сектора FSInfo.




Зарезервировано на будущее. Программа FAT32 format должна заполнять его 0. Байты этого поля сейчас не используются.




Значение 0x61417272. Эта сигнатура для точного определения положения следующих за ним полей.




Хранит “последнее известное” количество свободных кластеров диска. Если равно 0xFFFFFFFF, то количество неизвестно, и должно быть вычислено. Может быть любое другое значение, при этом не обязательно корректное. Оно должно проверяться на выполнение условия <= количества кластеров на диске.




Вспомогательное значение для драйвера FAT. Содержит номер кластера, начиная с которого надо искать свободный кластер. Поскольку FAT32 таблица FAT велика, могут происходить значительные затраты времени, когда в начале FAT много занятых кластеров, а драйвер ищет свободный начиная с номера 2. Обычно здесь номер последнего выделенного кластера. Если здесь значение 0xFFFFFFFF, то нет вспомогательного значения, и поиск должен производиться с номера 2. Любое другое значение может использоваться, но должно предварительно проверяться на условие <= количества кластеров на диске.




Зарезервировано на будущее. Программа FAT32 format должна заполнять его 0. Байты этого поля сейчас не используются.




Значение 0xAA550000. Это конечная сигнатура для точного определения сектора FSInfo. Заметьте, что старшие 2 байта этого значения (которые располагаются в байтах 510 и 511) соответствуют сигнатуре с таким же смещением в секторе 0.

FAT32 дополнен полем, которого нет в FAT16/FAT12 - BPB_BkBootSec. Диски FAT16/FAT12 могут быть полностью потеряны, если содержимое сектора 0 затрётся, или повредится и перестанет читаться. Этосмертельная точкадля FAT16 и FAT12 дисков. Поле BPB_BkBootSec уменьшает эту уязвимость для дисков FAT32, потому что, начиная с сектора номер 6, имеется резервная копия boot сектора, включая BPB.

В случае если сектор 0 ошибочно затрётся, любая утилита исправления дисков просто восстановит boot сектор из резервной копии. В случае если сектор 0 повредится, будет возможность подключить диск, чтобы у пользователя была возможность прочитать данные перед его заменой.

Для второго случая — где сектор 0 повреждается — есть резон использовать для BPB_BkBootSec именно значение 6. Если сектор 0 не читаемый, некоторые ОС “жёстко настроены” на проверку резервного boot сектора начиная с номера 6 на диске FAT32. Заметьте что начиная с сектора BPB_BkBootSec находится полная boot копия. Microsoft FAT32 “boot сектор” состоит из трёх 512-байтных секторов. Здесь копия всех трёх секторов, в секторе начиная с BPB_BkBootSec. Копия сектора FSInfo тоже здесь, хотя поле BPB_FSInfo в резервном boot секторе содержит такое же значение, как и в секторе 0 BPB.

ЗАМЕТКА: Все эти 3 сектора имеют сигнатуру 0xAA55 на смещении 510 и 511, так же как первый boot сектор (смотри описание выше, в конце описания структуры BPB).

Структура Директории FAT

Пока мы будет говорить о записях для коротких директорий, не беря во внимание длинных.

Директория FAT - ни что иное как “файл”, состоящий из списка 32-байтных структур. Лишь одна специальная директория, которая всегда должна присутствовать, это корневая директория. На дисках FAT12 и FAT16, корневая директория расположена в фиксированном месте - непосредственно после последней таблицы FAT, и состоит из фиксированного количества секторов, вычисляемого из BPB_RootEntCnt (смотри вычисление RootDirSectors выше). Для дисков FAT12 и FAT16, номер первого сектора корневой директории зависит от номера первого сектора таблицы FAT:

FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16);

Для FAT32, корневая директория может быть произвольного размера из последовательности кластеров, так же как любая другая директория. Номер первого кластера корневой директории FAT32 хранится в BPB_RootClus. В отличие от других директорий, корневая директория любой FAT не имеет штампа даты и времени, не имеет имени файла (кроме неявного имени “\”), и не содержит “.” и “..” в первых двух записях. Ещё один аспект - только в корневой директории может содержаться файл, у которого установлен единственный атрибут ATTR_VOLUME_ID (смотри ниже).

FAT 32 Byte Directory Entry Structure




Размер (байт)





Короткое имя.




Атрибуты файла:








Верхние два бита в байте зарезервированы, и всегда должны быть установлены в 0 когда файл создаётся, никогда не модифицируются и не анализируются.




Зарезервировано для использования Windows NT. Должен быть установлены в 0 когда файл создаётся, никогда не модифицируется и не анализируются..




Штамп миллисекунд текущего времени. Фактически это поле содержит десятые доли секунды. Гранулярность секунд DIR_CrtTime равна 2 секундам, поэтому диапазон допустимых значения значений 0-199 включительно.




Время создания файла.




Дата создания файла.




Дата последнего обращения. Заметим, что здесь нет времени последнего обращения, только дата. Это дата последнего чтения или записи. В случае записи, дата должна быть такой же, как DIR_WrtDate.




Старшее слово номера первого кластера (всегда 0 для FAT12 и FAT16).




Время последней записи. Заметим, что создание файла считается записью.




Дата последней записи. Заметим, что создание файла считается записью.




Младшее слово номера первого кластера.




32-битный DWORD содержит размер файла в байтах.


Специальное назначение первого байта (DIR_Name[0]) в записи директории FAT:

  • Если DIR_Name[0] == 0xE5, то запись директории свободна (в этой записи нет ни файла, ни директории).

  • Если DIR_Name[0] == 0x00, то запись директории свободна (как и 0xE5), и нет существующих записей после этой (все DIR_Name[0] байты после этой записи также равны 0).

Специальное значение 0 (но не значение 0xE5) индицирует драйверу FAT, что оставшиеся записи директорий можно не анализировать, потому что они все свободны.

  • Если DIR_Name[0] == 0x05, то настоящий байт имени файла равен 0xE5. 0xE5 соответствует старшему байту японской кодировки KANJI. Специальное значение 0x05 использовано потому, что данное значение можно корректно интерпретировать и в японской кодировке, и драйвер FAT не будет считать запись свободной.

Поле DIR_Name состоит из двух частей, 8-символьная основная часть имени, и 3-сомвольное расширение. Свободные концы обеих частей заполнены байтами 0x20.

DIR_Name[0] не может быть равным 0x20. Между основной частью и расширением подразумевается символ ‘.’, который отсутствует в DIR_Name. Нижний регистр букв в DIR_Name не разрешён (это специфично для разных стран).

Следующие символы не разрешены в DIR_Name:

  • Значения меньше 0x20, за исключением 0x05 в DIR_Name[0] описанного выше.

  • 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C.

Несколько примеров записи имён в DIR_Name:

“foo.bar” -> “FOO BAR”


“Foo.Bar” -> “FOO BAR”

“foo” -> “FOO “

“foo.” -> “FOO “


“prettybg.big” -> “PRETTYBGBIG”

“.big” -> illegal, DIR_Name[0] cannot be 0x20

В директориях FAT все имена уникальны. Посмотрите на первые три примера выше. Эти три имени соответствуют одному и тому же файлу, а в директории может быть только одно DIR_Name с именем “FOO BAR”.

DIR_Attr содержит атрибуты файла:

ATTR_READ_ONLY Означает что разрешено только чтение, а запись запрещена.

ATTR_HIDDEN Означает что в обычном списке файлов он не будет показан.

ATTR_SYSTEM Означает что это файл операционной системы.

ATTR_VOLUME_ID На диске должен быть только одинфайлс этим атрибутом, и располагаться в корневой директории. Имя этого файла фактически является ярлыком диска. DIR_FstClusHI и DIR_FstClusLO для ярлыка диска должны быть всегда 0 (файл не содержит ни каких данных).

ATTR_DIRECTORY Означает что фактически файл содержит список других файлов.

ATTR_ARCHIVE Атрибут используется утилитами резервного копирования. Этот бит устанавливается в 1 драйвером FAT когда файл создаётся, переименовывается, или записываются данные. Для утилит резервного копирования он означает, что файл изменился с момента последнего резервного копирования.

Отметим, что комбинация атрибутов ATTR_LONG_NAME означает, что “файл” является лишь частью длинного имени другого файла. Описание этой комбинации атрибутов дано в следующем параграфе.

Когда создаётся директория (файл с установленным атрибутом ATTR_DIRECTORY в поле DIR_Attr), DIR_FileSize устанавливается в 0. DIR_FileSize не используется, оно всегда равно 0 у файлов с атрибутом ATTR_DIRECTORY (директория состоит просто из списка кластеров, и оканчивается на EOC). Для директории выделяется кластер (если это не корневая директория FAT16/FAT12), в DIR_FstClusLO и DIR_FstClusHI записывается номер этого кластера, а в таблицу FAT для этого кластера записывается EOC. Затем весь кластер заполняется 0. Если директория является корневой директорией, то на этом всё (в корневой директории нет записей «точка» и «две точки»). Если директория не корневая, то нужно сделать две специальные записи в первых двух 32-байтных структурах (первые две 32 байтные записи, в регионе данных, в кластере который только что создали).

В первой записи директории, поле DIR_Name содержит:

“. ”

Во второй записи директории, поле DIR_Name содержит:

“.. ”

Они называются точка и две точки. Поле DIR_FileSize в обеих записях содержит 0, а поля даты и времени такие же, как у этой новой директории. Затем для записи точка (первая запись) устанавливаются DIR_FstClusLO и DIR_FstClusHI такие же, как у этой новой директории (номер кластера, который содержит эти записи точка и две точки).

В завершении, для записи две точки (это вторая запись) устанавливаются DIR_FstClusLO и DIR_FstClusHI в номер первого кластера родительской директории (значение 0, если она корневая, даже если на FAT32).

Содержание записей точка и две точки:

  • Запись точка это директория, указывающая на саму себя.

  • Запись две точки указывает на первый кластер родительской директории (но 0, если родительская директория является корневой).

Формат Даты и Времени

Многие файловые системы FAT поддерживают Дата/Время только для DIR_WrtTime и DIR_WrtDate. В связи с этим, DIR_CrtTimeMil, DIR_CrtTime, DIR_CrtDate и DIR_LstAccDate практически необязательные поля. Однако DIR_WrtTime и DIR_WrtDate должны поддерживаться. Если другие поля даты и времени не поддерживаются, то они должны быть установлены в 0, и игнорироваться при файловых операциях.

Формат Даты. Штамп даты директории FAT - это 16-битное поле, которое относится к эпохе MS-DOS с 01/01/1980. Описание формата (бит 0 младший в 16-битном слове, бит 15 старший в 16-битном слове):

Биты 0–4: День месяца, допустимый диапазон 1-31 включительно.

Биты 5–8: Месяц года, 1 = Январь, допустимый диапазон 1–12 включительно.

Биты 9–15: Количество лет с 1980, допустимый диапазон 0–127 включительно (1980–2107).

Формат Времени. Штамп времени директории FAT - это 16-битное поле, имеющее кратность 2 секунды. Описание формата (бит 0 младший в 16-битном слове, бит 15 старший в 16-битном слове).

Биты 0–4: 2-секундный счётчик, допустимый диапазон 0–29 включительно (0 – 58 секунд).

Биты 5–10: Минуты, допустимый диапазон 0–59 включительно.

Биты 11–15: Часы, допустимый диапазон 0–23 включительно.

Допустимый диапазон времени: от полуночи 00:00:00 до 23:59:58.

Структура длинных имён FAT

При добавлении длинных имён в FAT, была задача совместимости со старой архитектурой:

· Быть максимально прозрачными для старых версий MS-DOS. Главной целью являлось, чтобы существующие MS-DOS API в старых MS-DOS/Windows, в процессе поиска "find" не находили записи длинных имён. Найти записи длинных имён могут только MS-DOS API функции, использующие FCB с маской любых имён (*.*) и маской любых атрибутов (FFh). В после-Windows 95 версиях MS-DOS/Windows, ни какие MS-DOS API не могут даже случайно найти части записей длинных имён.

· Располагаться на диске компактно, рядом с ассоциированным коротким именем. Как мы потом увидим, записи длинных имён непосредственно примыкают к коротким, и их существование не оказывает заметного влияния на производительность системы.

· Обнаруживаясь дисковыми утилитами, не подвергать опасности целостность данных. Дисковые утилиты обычно не используют MS-DOS API для доступа к структурам диска. Обычно они считывают физические или логические сектора с диска, и сами анализируют их содержимое. Эвристическим методом, они могут предпринять шаги по «исправлению» структур, которые они посчитают «повреждёнными». Записи длинных имён были добавлены в систему FAT таким образом, что данные не теряются при «исправлении» их утилитами, ещё не совместимыми с Windows 95 на старых версиях MS-DOS/Windows.

Для того, чтобы достигнуть цели оптимального размещения и прозрачности, запись длинного имени определена как короткая, со специальным атрибутом. Как уже было сказано, запись длинной директории это просто запись обычной короткой директории, у которой поле атрибутов имеет такое значение:


Маска для определения записи длинного имени:


Когда системе встречается такая запись, производится следующая трактовка. Она трактуется как часть списка записей директорий, ассоциированных с одной записью короткой директории. Каждая запись длинной директории имеет следующую структуру:

Структура длинной директории FAT




Размер (байт)





Порядковый номер этой записи в последовательности записей длинных имён, ассоциированных с записью короткого имени в конце списка.

Если соответствует маске 0
x40 (LAST_LONG_ENTRY), то запись является последней в списке записей длинных имён. Все правильные списки начинаются с данной маской.




Символы 1-5 длинного имени в данном компоненте.




Атрибутысодержит ATTR_LONG_NAME




Если 0, то запись является компонентом длинного имени. ЗАМЕТКА: Другие значения зарезервированы на будущее.

Ненулевые значения означают другие типы.




Контрольная сумма короткого имени (которое располагается в конце списка).




Символы 6-11 длинного имени в данном компоненте.




Должно быть НОЛЬ. Это ложное значение FAT "первый кластер", и должно быть нулевым для совместимости с дисковыми утилитами. Для длинного имени значение не используется.




Символы 12-13 длинного имени в данном компоненте.

Организация и ассоциация коротких и длинных имён в директории

Набор записей длинных имён всегда ассоциирован записи короткого имени, которому они предшествуют. Длинные записи существуют в паре с короткими записями, поскольку только короткие записи видны в старых версиях MS-DOS/Windows. Без сопровождающей записи короткого имени, длинные имена были бы совершенно не видны в старых MS-DOS/Windows. Записи длинных имён не могут легально существовать сами по себе. Записи длинного имени, не имеющие соответствующей записи короткого имени, называются «сиротами». Ниже показано, как набор N записей длинного имени ассоциируются с записью короткого имени.

Записи длинного имени всегда непосредственно предшествуют, и физически прилегают к записи короткого имени. Операционная система делает ещё несколько проверок, чтобы убедиться, что длинное имя правильно ассоциировано короткому.

Последовательность записей длинного имени



N (последняя) запись длинного имени


дополнительные записи длинного имени

1 (первая) запись длинного имени


Запись короткого имени, которому предшествует длинное имя


Во-первых, каждая составная запись длинного имени последовательно пронумерована, и последняя запись в поле номера имеет специальный флаг - индикатор последней записи списка. Для этого используется поле LDIR_Ord. Первая запись имени содержит в LDIR_Ord значение 1. N (последняя) запись содержит (n OR LAST_LONG_ENTRY). Заметим, что поле LDIR_Ord не может содержать значения 0xE5 и 0x00. Эти значения всегда используются файловой системой для индикации "свободных" и "последней" записи в кластере директории. Для LDIR_Ord не используются значения за пределами этих двух значений. Значения для LDIR_Ord должны быть от 1 до (N or LAST_LONG_ENTRY). Записи с другими значениями файловая система считает "повреждёнными" или "сиротами".

Во-вторых, есть 8-битная контрольная сумма, вычисленная из короткого имени при создании записей длинного и короткого имени. В вычислении используются все 11 символов короткого имени. Контрольная сумма присутствует в каждой записи длинного имени. Если в любой из списка записей длинного имени контрольная сумма не соответствует короткому имени, то длинное имя считается сиротским. Это может случиться, когда диск с длинными именами подключен к старой системе MS-DOS/Windows, в этом случае при переименовании файла/директории переименовывается только короткое имя.

Алгоритм для вычисления контрольной суммы, реализованный на C:

// Returns an unsigned byte checksum computed on an unsigned byte
// array. The array must be 11 bytes long and is assumed to contain
// a name stored in the format of a MS-DOS directory entry.
Passed: pFcbName Pointer to an unsigned byte array assumed to be

// 11 bytes long.
Returns: Sum An 8-bit unsigned checksum of the array pointed

// to by pFcbName.
unsigned char ChkSum (unsigned char *pFcbName)
short FcbNameLen;
unsigned char Sum;

Sum = 0;
for (FcbNameLen=11; FcbNameLen!=0; FcbNameLen--) {
// NOTE: The operation is an unsigned char rotate right
Sum = ((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *pFcbName++;
return (Sum);

Являясь парой, запись короткого имени хранит многие важные поля: дата последнего обращения, время создания, дата создания, номер первого кластера, размер. Также она хранит имя, видимое в старых версиях MS-DOS/Windows. Записи длинного имени могут хранить новую информацию, тут нет необходимости дублировать информацию из записи короткого имени. В основном, записи длинного имени содержат лишь длинное имя файла. Короткое имя, которое ассоциировано длинному имени, называется вторичным именем, или просто псевдоним файла.

Размещение длинного имени в записях директории

Длинное имя может состоять из большего количества символов, чем умещается в одной записи. В этом случае, имя размещается в нескольких записях. В любом случае, имя разделено на части даже внутри записи. Ниже дан пример, иллюстрирующий, как длинное имя размещается в нескольких записях. После имени ставится NUL, а остальные символы заполняются значением 0xFFFF, специально для обнаружения ошибок от некорректных дисковых утилит. Если в конце имени нет свободных ячеек (например, размер имени кратен 13), то NUL и 0xFFFF не добавляются.

Допустим, файл создан с именем: "The quick brown.fox". Данный пример иллюстрирует, как имя упаковано в записях директории. Остальные поля тоже содержат свои значения.

Алгоритм для "авто-генерации" короткого имени из длинного имени, будет дан далее.

Ограничения имён. Разрешённые символы

Короткие имена

Короткие имена ограничены 8 символами до точки (.), и 3 символами расширения. Полный путь с коротким именем не может превышать 80 символов (3 для имени диска + 64 символов пути + 12 для (8.3) имени файла + NUL), включая конечный NUL. Имя может состоять из любой комбинации букв, цифр, и символов с кодом больше 127. Следующие символы тоже разрешены:

$ % ' - _ @ ~ ` ! ( ) { } ^ # &

Короткие имена хранятся в странице кодировки OEM, действующей в системе на момент создания записи. Записи коротких имён остаются в OEM для совместимости со старыми версиями MS-DOS/Windows. OEM символы это 8-битные символы, и ещё могут быть DBCS пары символов для определённых кодовых страниц.

Короткие имена, передаваемые в файловую систему, всегда преобразуются к верхнему регистру, при этом изначальный регистр теряется. У многих кодировок OEM есть одна проблема - соотношение букв нижнего и верхнего регистров не 1 к 1. К примеру, несколько букв нижнего регистра отображается на одну букву верхнего регистра. Таким образом, искажается оригинальное имя файла. Также в некоторых случаях это препятствует созданию нормальных файлов с разными именами, поскольку после преобразования в верхний регистр, они становятся одинаковыми.

Длинные имена

Длинные имена ограничены 255 символами, не включая конечный NUL. Полный путь с длинным именем не может превышать 260 символов, включая конечный NUL. Имя может состоять из символов, которые разрешены для коротких имён, плюс символ точки (.) можно использовать многократно. Также разрешён символ «пробел», как и для короткого имени, однако там он обычно не использовался. Следующие шесть символов теперь разрешены в длинных именах (но не в коротких):

+ , ; = [ ]

Пробелы между символами разрешены. Начальные и конечные пробелы игнорируются.

Начальные и промежуточные точки разрешены, они сохраняются в длинном имени. Конечные точки игнорируются.

Длинные имена хранятся в записях в UNICODE. UNICODE символы это 16-битные значения. Но нет возможности использовать UNICODE в записях коротких имён, поскольку они рассчитаны на 8-битные символы или DBCS символы.

Длинные имена, передаваемые в файловую систему, не преобразуются к верхнему регистру, при этом изначальный регистр сохраняется. UNICODE может решать проблему многих кодировок OEM, обеспечивая преобразование символов нижнего регистра к верхнему в соотношении 1 к 1.

Сравнение имён, коротких и длинных

Все имена, хранящиеся в записях коротких имён, составляют "пространство коротких имён". Все имена, хранящиеся в записях длинных имён, составляют "пространство длинных имён". Вместе они образуют объединённое пространство имён, где не бывает повторений. Это значит: любое имя в рамках директории, длинное или короткое, встречается только один раз. Хоть в длинных именах и сохраняется оригинальный регистр букв, два имени не могут быть одинаковыми, отличаясь лишь регистром букв. Например, имя "foobar" не может быть создано, если в директории уже есть короткое имя "FOOBAR" или длинное имя "FooBar".

Все операции с использованием поиска в файловой системе (например: find, open, create, delete, rename) регистро-независимы. При открытии файла "FOOBAR" может быть открыт "FooBar" или "foobar", или такой же похожий. Поиском файла по образцу "FOOBAR" будут найдены те же упомянутые файлы. Такие же правила действуют и на буквы дополнительной кодовой страницы.

Операция поиска короткого имени использует только записи коротких имён. Операция поиска длинного имени использует записи длинных и коротких имён. Пока файловая система сканирует директорию, она кэширует составные записи длинного имени. Как только встречается ассоциированная запись короткого имени, операция поиска длинного имени использует для сравнения сначала кэшированное длинное имя, а затем короткое.

Когда символ на диске, сохранённый в кодировке OEM или UNICODE, не может быть транслирован в соответствующий символ кодовой страницы OEM или ANSI, он всегда "транслируется" в "_" (подчёркивание) при возвращении пользователюон НЕ модифицируется на диске. Этот символ одинаковый в кодовой странице OEM и ANSI.

Правила именования и Длинные имена

API позволяет вызывающему указать длинное имя для присвоения файлу. API не позволяет отдельно задать короткое имя файла. Это запрещено по той причине, что короткие и длинные имена являются объединённым пространством имён. Как мы знаем, пространство имён файловой системы не поддерживает повторяющихся имён. Другими словами, длинное имя файла не может быть таким же, игнорируя регистр, как короткое имя у другого файла. Это ограничение предназначено для предотвращения путаницы у пользователей и программ, касательно правильного имени файла или директории. Чтобы это ограничение сделать прозрачным, при создании нового длинного имени, короткое имя генерируется автоматически из длинного имени, но таким образом, чтобы оно не повторяло других коротких имён.

Данный алгоритм авто-генерации коротких имён из длинных имён разработан после Windows NT. Авто-генерированные короткие имена составляются из базисного имени и возможной конечной цифры.

Алгоритм генерации базисного имени

Алгоритм генерации базисного имени указан ниже. Этот примерный алгоритм служит для иллюстрации того, как короткие имена могут авто-генерироваться из длинных имён. Реализация должна следовать этой базовой последовательности шагов.

1. UNICODE имя переданное в файловую систему преобразуется к верхнему регистру.

2. UNICODE имя в верхнем регистре преобразуется в OEM.
Если (в верхнем регистре UNICODE символ отсутствует как символ OEM в кодовой странице OEM)
или (символ OEM не разрешённый для имени 8.3)
Заменить символ на OEM '_' (подчёркивание).
Установить флаг "неточное преобразование".

3. Удалить все начальные и внутренние пробелы из длинного имени.

4. Удалить все начальные точки из длинного имени.

5. Пока (не конец имени)
и (символ не точка)
и (скопировано символов < 8)
Копировать символ в основную часть базисного имени

6. Если после последней точки имени имеется расширение, то в конце основной части базисного имени добавить точку.

7. Найти последнюю точку в длинном имени.
Если (последняя точка найдена)
Пока (не конец длинного имени)
и (скопировано символов < 3)
Копировать символ в расширенную часть базисного имени

Приступаем к генерации конечной цифры.

Алгоритм генерации конечной цифры

Если (не установлен флаг "неточное преобразование")
и (длинное имя умещается в формат 8.3)
и (базисное имя не повторяется с существующими короткими именами)
Короткое имя - это только базисное имя, без конечной цифры.
Добавить конечную цифру "~n" в конец основной части имени, при этом длинна основной части сформированного имени не должна превышать 8 символов, а полное имя не должно конфликтовать ни с одним существующим коротким именем.

Строка "~n" может быть в пределах от "~1" до "~999999". Номер "n" выбирается следующим из последовательности файлов с такими же базисными именами. К примеру, имеются следующие короткие имена: LETTER~1.DOC и LETTER~2.DOC. Предполагается, что следующее авто-генерированное имя такого же типа будет LETTER~3.DOC. К примеру, имеются следующие короткие имена: LETTER~1.DOC, LETTER~3.DOC. Теперь следующее авто-генерированное имя такого же типа будет LETTER~2.DOC. Однако, вы абсолютно не должны полагаться на это поведение. В директории с очень большим количеством имён с одинаковым типом, алгоритм выбора оптимизируется для скорости, и может выбирать другой "n", базируясь на характеристиках имён которые оканчиваются на "~n", и имеют такое же начальное имя.

Влияние записей длинных имён на существующие диски FAT

Поддержка длинных имён наиболее значима для жёстких дисков, но и для гибких дисков тоже есть поддержка. Реализация обеспечивает поддержку длинных имён с сохранением совместимости с существующими дисками FAT. Диск может читаться старыми версиями систем, без каких либо проблем совместимости. Существующий диск не нуждается в изменении формата перед началом использования длинных имён. Все существующие файлы остаются без изменений. Записи длинных имён создаются только при создании длинных имён. Добавление длинного имени к существующему файлу может потребовать перемещения записи 8.3 имени, если требуемое смежное место занято.

В старых системах, записи длинных имён скрыты как «скрытые» или «системные» файлы. Это позволяет защитить неаккуратных пользователей от случайных проблем. Пользователь может копировать файлы используя 8.3 имя, и записывать новые файлы без каких либо побочных эффектов.

Обратим внимание на то, что происходит с диском FAT при модификации директории в старой системе. Это может сказаться на длинных именах, потому что старые системы игнорируют длинные имена, ассоциированные с 8.3 именами.

Старые системы видят записи длинных имён только при поиске метки диска. При этом, настоящая метка диска будет некорректно определена, если она расположена не первой в корневой директории. Это потому, что у записей длинных имён тоже установлен атрибут «метка диска». Это досадная, но не критичная проблема.

В процессе удаления метки диска, может быть удалена одна из записей длинной директории, хотя это бывает очень редко. Это легко обнаруживается файловой системой. Длинное имя перестанет использоваться от того, что одна или несколько записей помечены удалёнными. Если удалённая запись снова используется, то байт атрибутов уже не будет содержать атрибута длинного имени.

Если файл переименовывается в старой системе, то только короткое имя будет переименовано. Длинное имя останется без изменений. Поскольку в пространстве имён длинные и короткие имена должны быть в согласованном состоянии, то конечно, длинное имя будет неправильным после такого переименования. Контрольная сумма 8.3 имени, которая хранится в длинном имени, служит для выявления таких ошибок. Эта контрольная сумма проверяется перед использованием длинного имени. Переименование может вызвать проблему, только если новое 8.3 имя файла случайно получится с такой же контрольной суммой. Алгоритм контрольной суммы выбран наиболее лучшим для коротких имён.

Переименование 8.3 имени не должно так же конфликтовать с существующими длинными именами. Имеем ввиду, что в старых системах возможно назначить файлу короткое имя, совпадающее с каким-либо длинным именем, без учёта регистра букв. Для предотвращения этого, при автоматическом создании 8.3 имени из длинного имени, которое имеет формат 8.3, это имя напрямую отображается в 8.3 имя путём приведения букв к верхнему регистру.

Если файл удаляется, то длинное имя просто становится сиротским. Если вместо него создаётся новый файл, то длинное имя будет ошибочно ассоциировано новому файлу. Как и в случае переименования, контрольная сумма 8.3 имени предотвращает эту некорректную ассоциацию.

Проверка корректности содержимого директории

Данная информация поможет дисковым утилитам поддерживать 'корректность' каждой записи директории, с учётом возможных будущих нововведений.

1. НЕ смотрите в записи директории на поля, помеченные как 'зарезервировано', и если они содержат не ноль, не считайте их 'плохими'.

2. НЕ обнуляйте в записи директории поля, помеченные как 'зарезервировано', когда они содержат не ноль (считая их плохими’). Поля являются зарезервированными, а не должны содержать ноль. Они должны игнорироваться вашей программой. Эти поля предназначены для будущих расширений файловой системы. Игнорируя их, утилиты могут нормально работать в будущих версиях операционных систем.

3. ИСПОЛЬЗУЙТЕ сначала атрибут A_LONG, когда определяете тип записи директории - длинная или короткая. Ниже дан пример корректного алгоритма:

if (((LDIR_attr & ATTR_LONG_NAME_MASK) == ATTR_LONG_NAME) && (LDIR_Ord != 0xE5))
/* Found an active long name sub-component. */


4. ИСПОЛЬЗУЙТЕ биты 4 и 3 для записи короткой директории вместе, при определении её типа. Ниже дан пример корректного алгоритма:

if (((LDIR_attr & ATTR_LONG_NAME_MASK) != ATTR_LONG_NAME) && (LDIR_Ord != 0xE5))
if ((DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == 0x00)
/* Found a file. */
/* Found a directory. */
/* Found a volume label. */
/* Found an invalid directory entry. */

5. НЕ считайте, что ненулевое значение поля "тип" означает «плохую» запись. Не перезаписывайте "тип" нулевым значением.

6. Используйте значение поля "контрольная сумма" для проверки корректности записи. Поле "первый кластер" в данный момент содержит ноль, но это может быть изменено в будущем.

Несколько заметок относительно директорий FAT

  • Записи длинных имён одинаковы у всех типов FAT. Смотрите детальное описание выше.

  • Поле DIR_FileSize является 32-битным. Для дисков FAT32, ваш драйвер FAT не должен позволять создавать массив кластеров больше чем 0x100000000 байт, и последний байт последнего кластера для такого размера не должен принадлежать файлу. Таким образом, размер файла не должен быть > 0xFFFFFFFF байт. Это общее ограничение для всех файловых систем FAT. Максимальный разрешённый размер на дисках FAT это 0xFFFFFFFF (4 294 967 295) байт.

  • Так же, драйвер FAT не должен допускать директории («контейнер» других файлов) размером более 65 536 * 32 (2 097 152) байт.

    ЗАМЕТКА: Это ограничение не количества файлов в директории. Это ограничение относится к размеру директории как таковой, и не имеет отношения к содержимому директории. Есть две причины этого ограничения:

  1. Поскольку директории FAT не сортированы и не индексированы, то плохая идея создавать огромные директории; в противном случае, такие операции как создание новых записей (которые требуют просмотра каждой существующей записи для проверки наличия такого же имени) станут очень медленными.

  2. Есть много драйверов и дисковых утилит FAT, в том числе от Microsoft, которые считывают количество записей директории, используя 16-битную WORD переменную. По этой причине, директории не должны содержать записей больше, чем умещается в 16-битную переменную.

Переводчик: Александр Кобец. Во многих местах перевод не дословный. Если Вы обнаружите смысловую путаницу или неточность, напишите мне на E-mail: Alexander Kobets <akobets@mail.ru>

« Пред.   След. »
09.04.2020 г.