FAT32 파일시스템 구조

MBR

첫번째 섹터(LBA=0)는 Master Boot Record(MBR)이다. 모든 IDE 드라이브는 LBA를 지원하므로 CHS 모드에 대해서는 잊어도 된다(LBA는 0번째 섹터부터 시작한다). MBR의 처음 446바이트는 부트업 코드다. 그 다음 64바이트에 파티션 테이블 정보가 놓이고 마지막 두 바이트는 항상 0x55, 0xaa다.

/--------------------------\
|                          |
|                          |
|                          |
|        Boot Code         |
|        446 Bytes         |
|                          |
|                          |
|                      ____|
|                     |    |
|---------------------|----
| Partition1, 16bytes |    |
|---------------------|----|
| Partition2, 16bytes |    |
|---------------------|----|
| Partition3, 16bytes |    |
|---------------------|----|
| Partition4, 16bytes |55aa|
\---------------------|----/

MBR은 4개의 파티션 정보만 갖는다. 확장 파티션은 기본 파티션의 첫번째 섹터에 또다른 파티션 테이블을 두는 방식이다. 각 파티션 정보는 16바이트다. 파일시스템 타입을 나타내는 5번째 바이트와 파티션의 LBA 시작 주소를 가리키는 12번째부터의 4바이트를 제외한 나머지는 대부분의 경우 무시된다. 보통 각 파티션 엔트리에서 파일시스템 타입이 FAT32(0x0b 또는 0x0c)인지 검색하고 LBA 시작 주소를 로드한다.

/-----------------------------------------------------------------------------\
| 1 byte    | 3 bytes   | 1 byte    | 3 bytes | 4 bytes   | 4 bytes           |
|-----------|-----------|-----------|---------|-----------|-------------------|
| Boot Flag | CHS Begin | Type Code | CHS End | LBA Begin | Number of Sectors |
\-----------------------------------------------------------------------------/

확장 파티션 테이블 읽기

파티션 테이블의 첫번째 레코드는 주파티션을 가리키고 두번째 레코드는 확장 파티션을 가리킨다. 다음 파티션을 읽기 위해서는 두번째 레코드의 첫번째 섹터를 읽으면 된다. 이 섹터는 코드가 공백으로 남겨진 MBR과 같다. 즉 루트 MBR의 첫번째 파티션 레코드는 파티션1을 가리키고 두번째 레코드는 확장 파티션을 가리킨다. 이 확장 파티션의 MBR은 루트 MBR과 같은 포맷을 가지며, 첫번째 파티션 레코드는 파티션2를 가리키고 두번째 레코드는 다음 확장 파티션을 가리킨다. 다음 확장 파티션의 MBR의 첫번째 파티션 레코드는 파티션3을 가리키고 두번재 레코드는 다음 확장 파티션을 가리킨다. 물론 마지막 파티션일 경우 항목은 비어있을 것이다.

FAT32 Volume ID

FAT32 파일시스템의 첫번째 섹터는 Volume ID다. 여러 값들이 나열되어 있지만 주요한 값은 4가지이고 이 값을 검증하기 위해 3가지 값을 더 이용할 뿐이다.

/----------------------------------------------------------------------------------------\
| Field                        | MS Name        | Offset| Size    | Value                |
|----------------------------------------------------------------------------------------|
| Bytes Per Sector             | BPB_BytsPerSec | 0x0b  | 16 bits | Always 512 Bytes     |
| Sector Per Cluster           | BPB_SecPerClus | 0x0d  | 8 bits  | 1,2,4,8,16,32,64,128 |
| Number of Reserved Sectors   | BPB_RsvdSecCnt | 0x0e  | 16 bits | Usually 0x20         |
| Number of FATs               | BPB_NumFATs    | 0x10  | 8 bits  | Always 2             |
| Sectors Per FAT              | BPB_FATSz32    | 0x24  | 32 bits | Depends on disk size |
| Root Directory First Cluster | BPB_RootClus   | 0x2c  | 32 bits | Usually 0x00000002   |
| Signature                    | (none)         | 0x1fe | 16 bits | Always 0xaa55        |
\----------------------------------------------------------------------------------------/

3개의 필드를 확인했으면, 파일시스템이 512바이트 섹터를 사용하는지, 2 FAT인지, 그리고 시그내처를 체크한다. 다음 코드는 FAT32 파일 시스템을 액세스하기 위해 MBR과 Volume ID에서 필요한 정보를 네개의 변수에 저장하는 코드이다:

(unsigned long)fat_begin_lba = Partition_LBA_Begin + Number_of_Reserved_Sectors;
(unsigned long)cluster_begin_lba = Partition_LBA_Begin + Number_of_Reserved_Sectors + (Number_of_FATs * Sectors_Per_FAT);
(unsigned char)sectors_per_cluster = BPB_SecPerClus;
(unsigned long)root_dir_first_cluster = BPB_RootClus;

보다시피 대부분의 정보는 첫번째 클러스터와 FAT의 위치를 알아내기 위한 것이다. 클러스터 사이즈와 루트 디렉토리 위치를 알아두어야 한다.

FAT32 파일시스템 구조

FAT32 파일시스템의 레이아웃은 단순하다. 첫번째 섹터는 Volume ID다. 그리고 사용되지 않는 예약된 섹터들이 있다. 그리고 2개의 FAT(File Allocation Table) 복사본이 있다. 나머지는 클러스터로 정렬된 데이터이다. 마지막 클러스터 뒤에는 약간의 미사용 공간이 있을 수 있다.

대부분의 디스크 공간은 파일과 디렉토리를 저장하는 클러스터가 차지한다. 클러스터는 2번째부터 시작한다(0, 1번째는 없음). LBA 주소로 특정 클러스터에 접근하기 위해서는 다음 식을 사용한다:

lba_addr = cluster_begin_lba + (cluster_number - 2) * sectors_per_cluster;

일반적으로 클러스터 크기는 4k(8 sectors), 8k, 16k, 32k가 사용된다.

위 정보로 알 수 있는 것은 루트 디렉토리의 첫번째 클러스터 위치 뿐이다. 루트 디렉토리를 읽음으로써 서브디렉토리와 파일의 이름과 첫번째 클러스터 위치를 알 수 있다. 디렉토리는 오직 파일과 서브디렉토리의 첫번째 클러스터를 어떻게 찾는지 알리는 역할을 한다. 물론 디렉토리는 파일 길이라던가 수정시간, 속성과 같은 정보도 포함한다. 첫번째 클러스터 다음을 읽기 위해서는 FAT을 사용해야 한다.

| Field              | MS Name       | Offset | Size     |
|--------------------------------------------------------|
| Short Filename     | DIR_Name      | 0x00   | 11 bytes |
| Attrib Byte        | DIR_Attr      | 0x0b   | 8 bits   |
| First Cluster High | DIR_FstClusHI | 0x14   | 16 bits  |
| First Cluster Low  | DIR_FstClusLO | 0x1a   | 16 bits  |
| File Size          | DIR_FileSize  | 0x1c   | 32 bits  |

디렉토리는 32바이트 레코드로 구성된다. 이 레코더에는 4가지 타입이 있다.

  1. Normal record with short filename - Attrib is normal
  2. Long filename text - Attrib has all four type bits set
  3. Unused - First byte is 0xE5
  4. End of directory - First byte is zero

삭제된 파일은 미사용 레코드가 된다. 레코드가 0xe5나 0x00으로 시작하지 않는다면 실제 디렉토리 데이터이다. 그 포맷은 속성비트로 알 수 있다.

6개의 속성비트가 정의되어 있다. 이 비트들을 체크함으로 normal record인지 long filename data인지, 그리고 보통파일인지 서브디렉토리인지 알 수 있다. long filename 레코드일 경우 하위 4bits가 모두 셋된다.

파일이름 필드에 짧은 이름이 들어갈 경우 빈 공간은 스페이스(0x20)으로 채워진다. 클러스터와 사이즈 필드는 little endian으로 정렬된다.

FAT

루트 디렉토리의 첫번째 클러스터는 volume ID 섹터에서 알 수 있고, 모든 디렉토리 항목은 파일 또는 서브디렉토리의 첫번째 클러스터 위치를 알려준다. 하나 이상의 클러스터가 할당된 파일이나 디렉토리의 경우 그 다음 클러스터의 위치를 얻기 위해 FAT(File Allocation Table)을 사용해야 한다. FAT32라는 이름은 이 테이블 이름에 기인한다. 테이블의 각 항목은 32비트이기 때문이다.

FAT는 32비트 항목으로 이루어진 큰 배열이다. 따라서 FAT의 각 섹터는 128개의 항목을 갖고 있으므로, 0-6비트는 섹터내의 몇번째 항목인지, 7-31비트는 FAT의 몇번째 섹터인지를 나타낸다. 항목의 위치는 순서대로 클러스터 번호가 된다. 그리고 항목에 저장된 값은 다음 클러스터의 위치다. FAT의 목적은 현재 클러스터의 다음 클러스터를 알려주는 것이다. 하나의 클러스터만 차지하는 작은 파일과 데렉토리에 대해서 FAT은 그외에 할당된 클러스터가 없음을 알려준다(0xfffffff8 ~ 0xffffffff).

마이크로소프트 스펙에 따르면 클러스터 번호는 28비트만 사용된다. 상위 4비트는 예약된 공간으로 0으로 클리어해야 한다. FAT 클러스터의 0 값은 미할당 공간을 의미한다. FAT 항목은 모두 little endian으로 정렬되어있다.

원문

http://www.pjrc.com/tech/8051/ide/fat32.html
http://home.teleport.com/~brainy/fat32.htm