내용
1. 파일시스템 소개
1) 파일시스템의 탄생
[ FAT파일 시스템 변화 ]
- FAT 12는 플로피디스크를 관리하는데 이용하기 위해 구현하게 되었다.
- Tim Paterson 이 QDOS 운영체제를 개발하면서 FAT를 파일시스템으로 선택하면서 PC환경에 쓰이게 된다.
- FAT의 경우 매우 단순한 구조를 가지고 있었고, 조금만 수정하면 32MB 이상 관리도 할 수 있을 거라 생각 했는데 PC환경에서도 충분한 용량으로 생각 했다.
[Thinks~] IBM은 개인용 컴퓨터 성능이 16bit CPU면 충분하다고 생각 하는 바람에 32bit CPU 출시를 빼앗겼고, Microsoft는 메모리의 크기를 640KB면 충분하다고 생각해서 MS-DOS를 사용한 유저들을 고통으로 몰아 넣게 됨. |
- QDOS가 나오면서 FAT파일시스템이 소개 되며, IBM과 Microsoft로 넘어가면서 PC-DOS, MS-DOS로 바꾸고, x86 PC의 운영체제로 탐재되고, IMB x86 PC가 엄청난 성공을 거두면서 표준처럼 자리잡고, 다른 PC 메이커들도 호환기존으로 만들어 내면서 MS-DOS도 대중적인 OS가 되었다. 따라서 자연스레 FAT 파일시스템이 가장 많이 쓰이는 파일시스템으로 자리 잡게 되었다.
2) FAT 12
- 80년에 나온 FAT 파일시스템의 최초 버전은 다른 버전과 구분하기 위해 FAT12라고 불리며 플로피디스크 파일저장을 위해 개발되었다.
- 당시 PC는 HDD가 없고 5.25인치 플로피디스크가 대세였던 시절이였고, 최초로 발표된 FAT 12구조가 매우 단순해서, 디렉토리(Directory)라는 개념도 없었다.
- MS-DOS 2.0이 나오면서 FAT12에 계층형 디렉토리가 지원되고, 최근의 FAT파일시스템의 기본 구조가 갖추게 된다.
3) FAT 16
- 개인용 PC에 HDD를 장착하는 경우가 많아지면서 HDD에서 사용할 파일시스템의 필요성이 증가고, FAT 16버전의 경우 비로서 HDD에사용할 만한 파일시스템이 되었다.
- 구조적으로 FAT 12와 거의 동일하지만 FAT 16에서는 클러스터를 표현하는 비트수가 12개에서 16개로 늘어나면서 이론적으로 최대 216 인65,535개의 클러스터를 표현할 수 있게 되었다.
- 이렇게 클러스터 크기를 32KB로 할 경우 최대 2GB까지 표현 할 수 있었다. 이때는 평생 써도 남을 정도로 충분하다고 판단 했었다.
4) VFAT(Virtual FAT)
- Windows 95버전으 나오면서 FAT파일시스템의 성능 및 기능을 향상 시켰다.
- VFAT 또는 FAST FAT라고 불러야 하지만 사람들은 FAT 파일시스템이라 불렀다.
- 32Bit 보호모드(Protected Mode)에 적합하게 코드 재 작성하여 성능향상을 시켰고, 독점모드(Exclusive Mode)를 추가하여 동시에 여러 프로그램을 같은 파일을 접근할 경우에 대비하였다. 하지만 이는 파일시스템 구조라기 보단 OS의 파일 시스템 처리 성능이 개선된 것이다.
- VFAT의 경우 LFNs(Long File Names)를 지원하여 파일명을 최대 255까지 적을 수 있게 되었다. 이전 버전의 경우 파일명이 최대 8byte 확장명은 최대 3byte가 고작 이였고, 파일명과 확장명은 모두 대문자만 가능 했었다. LFNs의 경우 이전 버전의 DOS와도 호환성을 가지면서 파일명의 길에 제한으로부터 자유로울 수 있게 되었다.
- 파일명의 최대 글자수는 늘어났지만 최대 용량은 여전히 2GB정도가 최대였다.
5) FAT 32
- 1996년 FAT32버전이 출시되었고, VFAT를 기반으로 수정하여 클러스터를 표현하는 bit를 32개로 늘렸으나 최상위 4bit는 예약 영역으로 사용되지 않고, 총 28bit를 이용하여 클러스터를 표현한다.
- 이는 클러스터 크기를 16KB로 하면 최대 4TB까지 가능한 용량이다.
- Windows의 경우 FAT32를 2TB까지 인식 할 수 있지만 여러 가지 이유로 최대용량을 32GB로 제한하고 있다.
- 만약 Windows에서 32GB 이상되는 저장 장치를 사용하고 싶다면 NTFS를 사용해야 한다.
6) FAT 파일시스템들의 비교
[FAT 파일 시스템 비교]
구분 |
FAT12 |
FAT16 |
FAT32 |
사용 용도 |
플로피 디스크용 |
저용량 하드디스크 |
고용량 하드디스크 |
클러스터 표현 비트 수 |
12 bit |
16bit |
32bit(28bit만 사용) |
최대 클러스터 개수 |
4,084개 |
65,524개 |
약 228 개 |
최대 볼륨 크기 |
16MB |
2GB |
2TB |
파일의 최대 크기 |
볼륨 크기 만큼 |
볼륨 크기 만큼 |
4GB |
디렉토리당 최대 파일 개수 |
X |
65,535개 |
65,535ro |
루트 디렉토리의 파일 개수 제한 |
제한 있음 |
제한 있음 |
제한 없음 |
[클러스터 개수의 경우 Microsoft에서 발표한 문서에서 표시한 내용이다.]
7) 클러스터 크기와 슬랙(Slack) 문제
- 클러스터 크기와 볼륨 크기와 어떤 관계가 있는지, 클러스터 크기에 따른 장단점이 무엇인지 파악 해보자.
[Windows 2000 기준]
볼륨 크기 |
FAT16 클러스터 크기 |
FAT32 클러스터 크기 |
NTFS 클러스터 크기 |
16MB ~ 32MB |
512Byte |
지원 안 함 |
512Byte |
32MB ~ 63MB |
1KB |
512Byte |
512Byte |
64MB ~ 128MB |
2KB |
1KB |
512Byte |
128MB ~ 256MB |
4KB |
2KB |
512Byte |
256MB ~ 512MB |
8KB |
4KB |
512Byte |
512MB ~ 1GB |
16KB |
4KB |
1KB |
1GB ~ 2GB |
32KB |
4KB |
2KB |
2GB ~ 4GB |
64KB(가) |
4KB |
4KB |
4GB ~ 8GB |
지원 안 함 |
4KB |
4KB |
8GB ~ 16GB |
지원 안 함 |
8KB |
4KB |
16GB ~ 32GB |
지원 안 함 |
16KB |
4KB |
32GB ~ 2TB |
지원 안 함 |
인식 가능 (나) |
4KB |
-
NT, 2000, xp에서 클러스터 크기를 64KB로 해서 2~4GB의 볼륨을 16으로 포맷 가능하지만 일부 응용프로그램에서는 64KB 클러스터 볼륨을 인식 못하는 경우가 있으니 2GB넘는 볼륨은 FAT16이 아닌 다른 파일시스템을 사용하길 권장한다.
-
Windows는 32GB가 넘는 볼륨에 FAT32를 이용해서 포맷하는 것을 지원하지 않지만 다른 장치가 포맷한 32GB가 넘는 FAT32 볼륨은 인식 할 수 있다.
[클러스터 크기에 따른 장단점]
구분 |
클러스터 크기가 작을 때 |
클러스터 크기가 클 때 |
장점 |
버려지는 용량이 적다 |
FAT 영역이 작다. Cluster 처리 부담이 적다. |
단점 |
FAT 영역이 커진다 |
버려지는 용량(Slack)이 많다. |
- 클러스터 크기에 따른 장단점이 있으나 클러스터 크기가 작은 경우 버려지는 용량이 적다. 반면 클 경우 버려지는 용량이 큰 경우 버려지는 용량이 크기 때문에 NTFS 파일시스템에선 클러스터 할당 크기를 작게 해 놓았다.
- 영상 데이터 같이 대용량 파일만 저장하는 경우 굳이 클러스터 크기를 작게 할 필요는 없을 것이다.
2. FAT 파일시스템 구조
1) FAT 파일시스템의 구조
[FAT 16 파일시스템 구조]
[FAT 32 파일시스템 구조]
- FAT16과 FAT32의 구조적인 부분에서 차이점은 FAT16의 경우 루트 디렉토리 영역이 따로 존재한다.
- FAT16의 경우 루트 디렉토리 영역이 따로 존재하며 하위 디렉토리들과 달리 FAT#2 영역 뒤에 오지만 FAT32의 경우 일반 디렉토리 중의 하나로 간주 하기 때문에 데이터 영역 어디서든지 상관 없다.
2) 부트 레코드(Boot Recort)
- 볼륨의 첫 번째 섹터이며, 예약된 (Reserved) 영역의 첫 번째 섹터이다.
- Windows를 부팅을 시키기 위한 기계어 코드와 FAT 파일시스템의 여러 설정 값들이 있다.
- BIOS Parameter Block(BPB)이라고도 하며, 크기가 1섹터밖에 안 되는 작은 영역이지만 Windows가 FAT 파일 시스템을 인식하는데 가장 중요한 역할을 담당한다.
- 만약 볼륨 내용이 완벽히 살아있어도 부트레코드 섹터의 데이터가 지워지면 Windows에서는 해당 볼륨을 인식 할 수 없다.
3) 예약된(Reserved) 영역
- FAT16의 경우 1섹터, FAT32인 경우 32섹터를 할당한다.
- FAT16의 경우 1섹터 바로 뒤에 FAT영역이 오며 이 영역은 미래를 위해 예약되어 있는 영역으로 사용하지 않는 영역이다.
- 만약 특별한 정보를 기록 하고 싶은 경우 이 영역에 기록 하면 될 것이다. 단 FAT32의 경우 예약된 영역 안에 몇 개의 섹터를 사용하여 저장하고 있으므로 겹치지 않게 유의해야 한다.
4) FAT #1 영역과 FAT #2 영역
- 클러스터들을 관리하는 테이블이 모여 있는 공간으로 FAT 영역을 통해 어떤 클러스터가 비어 있는지, 어떤 파일에 어떤 클러스터가 연결되어 있는지 알 수 있다.
- 이 영역에 손상이 된다면 상당히 위험하며, 백업본을 한 개 이상 만들어 두게 해놓았다.
- FAT #1영역과 #2영역은 동일한 내용을 담고 있다. FAT #2영역은 일종의 백업본으로 FAT #1에 손상이 갔을 경우를 대비해 만들어 져있다.
- FAT 영역은 최소 1개 이상 되어야 한다. 보통 2개의 영역을 만든다.
5) 루트 디렉토리 영역(FAT 16만 존재)
- FAT 16에서는 루트 디렉토리의 위치가 무조건 FAT #2 영역 뒤쪽으로 고정되어 있다.(크기는 가변적일 수 있다.)
- 이 방식은 루트 디렉토리가 어디에 있는지를 조사할 필요가 없어서 개발의 편의성이 증가하게 되는 장점이 있지만, 루트 디렉토리의 파일 개수 제한 등 단점이 있어서 FAT32에서는 구조가 바뀌었다.
- FAT32에서는 루트 디렉토리가 데이터 영역 어디에 와도 상관이 없으며, 단지 그 위치를 부트 레코드에 기록하고 있을 뿐이다. 이 방법의 유일한 단점은 부트 레코드가 망가지면 루트 디렉토리를 찾아내기가 매우 힘들다.
- 따라서 대부분의 FAT 코드들이 FAT32인 경우라도 FAT #2 영역 바로 뒤에 루트 디렉토리를 위치시킨다. 따라서 부트 레코드가 망가져서 루트 디렉토리의 위치를 알 수 없게 되어버린 경우에도 간단히 찾을 수 있다.
6) 데이터 영역(파일과 디렉토리)
- 이 영역에는 파일 또는 디렉토리가 저장되어 있으며, 클러스터(Cluster)라고 불리는 논리적인 단위로 읽기/쓰기가 된다.
7) 사용하지 않는(Unused) 영역
- 이 영역은 물리적으로 사용해도 상관없지만, FAT 파일시스템이 볼륨이 구조화시키는 과정에서 잉여분이 조금 남는 영역이다.
- 매우 작은 양이기 때문에 무시할 수 있을 정도이다.
8) 영역별 정리
구분 |
부트 레코드 |
예약된 영역 |
FAT 영역 |
데이터 영역 |
크기 |
1섹터 |
1~32섹터 |
파티션의 1~0.5% |
파티션의 99% 이상 |
접근 단위 |
섹터 |
섹터 |
섹터 |
클러스터 |
3. 부트레코드
1) 부트레코드 소개
- BIOS Parameter Block(BPB)라고 불리는 이 영역은 해당 볼륨의 여러 가지 설정 값들을 저장하고 있으며, 해당 볼륨이 부팅될 수 있도록 부팅에 필요한 실행 코드도 포함하고 있다.
- Boot Record가 저장되는 위치는 해당 볼륨의 첫 번째 섹터이며 FAT 파일 시스템을 구성하는 영역 중 맨 앞에 위치하는 예약된(Reserved) 영역의 첫 번째 섹터이기도 하다.
- HDD에 볼륨이 여러 개 있다면 각각의 볼륨에 부트 레코드도 하나씩 있게 된다.
- 하드디스크에 파티셔닝이 되어 있지 않아 볼륨이 1개인 경우 부트레코드는 MBR(Master Boot Record) 영역에 존재한다.
[파티션 없이 단일 볼륨인 하드디스크의 부트 레코드 위치]
[파티션이 존재하고 볼륨이 2개인 하드디스크의 부트 레코드 위치]
2) 부트레코드에서 FAT 16과 FAT 32의 차이
[FAT16과 FAT32의 부트 레코드 레이아웃]
- 32오프셋 까지는 공통된 항목을 가졌으나 32번 이후에는 항목이 달라 서로호환이 않된다.
- FAT16용 부트 레코드 구조체와 FAT32용 부트 레코드 구조체를 따로 선언해야 되는 것이다.
- 볼륨의 파일시스템을 조사할 때 0~32번 오프셋까지 공통 항목의 내용을 조사하면 알 수 있을 것이다.
3) FAT 16 부트 레코드
[FAT16 부트레코드 영역]
- 512Byte의 16진수 내용이 FAT16 부트 레코드의 모든 것이다.
- Windows가 FAT 파티션을 인식하는데 필수적인 사항들이기 때문에 꼭 들어가야 한다.
- 색칠이 되어있지 않은 부분은 부팅할 때 사용하는 부트 코드 영역이다. 이 파티션을 부팅용으로 사용하지 않을 경우 모두 '0'으로 채워도 상관 없는 영역이다.
[FAT16 부트 레코드 항목]
- FAT 파일시스템은 리틀 엔디언(Little Endian)으로 설계되어 있기 때문에 출력되는 값들은 실제 저장한 값과 반대로 뒤집혀 있다.
4) FAT 16과 FAT 32 부트 레코드 공통 항목 설명
이름 |
Jmp Boot Code |
||||
위치 (Offset) |
0~2 |
크기 (Size) |
3 Byte |
일반적인 값 (Value) |
EB 3C 90 |
설명 |
부트 코드로 점프하는 명령어. x86 계열 PC는 부팅 시 이 항목을 읽어서 부트 코드가 있는 영역으로 점프하게 된다. 해당 볼륨을 이용해서 부팅할 일이 없다면 어떤 값이 와도 무방하다. |
이름 |
OEM Name |
||||
위치 (Offset) |
3~10 |
크기 (Size) |
8 Byte |
일반적인 값 (Value) |
ASCII Code 'MSDOS5.0' |
설명 |
이 항목은 단지 OEM 회사를 나타내기 위한 문자열일 뿐이다. Windows는 이 항목에 대해서 어떠한 참조도 하지 않는다. Windows는 보통 'MSWIN4.1'이라고 적거나 'MSDOS5.0'이라고 적는다. 이 항목은 어떤 값이 되어도 상관없다. |
이름 |
Byte Per Sector |
||||
위치 (Offset) |
11~12 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
512 |
설명 |
섹터당 바이트 수를 적는다. 하드 디스크의 한 섹터가 몇 바이트를 담고 있는지에 대한 항목으로 이 항목은 필수적으로 다음 값만 적어주어야 한다. 512, 1024, 2048, 4096 (이 값 외에 다른 값은 사용하지 않는다.) Windows나 다른 FAT를 인식하는 장치들에서 여러분이 기록한 FAT 하드디스크가 잘 인식되길 바란다면 이 항목에 512가 되어야 할 것이다. 섹터당 크기가 512Byte가 아닌 하드디스크는 거의 없기 때문에 512로 적는 것이 좋다. |
이름 |
Sector Per Cluster |
||||
위치 (Offset) |
13 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
32 |
설명 |
클러스터당 섹터 수, 한 클러스터가 몇 개의 섹터로 이루어져있는지 기록되는 부분이다. 이 값은 반드시 '0'보다 큰 값이어야 하며 2의 배수여야 한다. |
이름 |
Reserved Sector Count |
||||
위치 (Offset) |
14~15 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
FAT16은 '1' FAT 32는 '32' |
설명 |
예약된(Reserved) 영역의 섹터 수를 저장한다. 예약된 영역의 크기는 최소한 1개 섹터 이상 되어야 하는데, 그것은 부트 레코드가 예약된 영역의 첫 번째 섹터에 위치하기 때문이다. 따라서 이 항목의 값이 '0'이 되어서는 안 된다. FAT16에 경우 보통 '1'의 값을 가지며, FAT 32는 보통 '32'값을 가진다. 예약된 영역에서 부트 레코드나 특별히 다른 정보를 담지 않고 있는 섹터는 전부 '0'으로 초기화 되어있어야 한다. |
이름 |
Number of FATs |
||||
위치 (Offset) |
16 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
2 |
설명 |
볼륨에 있는 FAT 영역의 수를 담고 있다. 이 항목은 최소한 '1' 이상의 값을 가지며, '2'라고 적는 것을 추천한다. 주의할 점은 이 항목에다 '2'라고 적어놓고 실제 FAT영역을 3개 만들거나 1개 만드는 것은 좋지 않다. CF Card와 같은 저용량 매체에서 data 영역을 조금이라도 더 확보하기 위해 이 항목을 '1'로 지정하는 개발자도 있다. Windows는 이 항목의 값이 '1'이더라도 호환성을 보장하지만, 모든 FAT코드가 호환할 수 있을지는 장담 할 수 없다. Number of FATs의 값이 무조건 '2'일 것이라는 가정하에 코드를 짜는 개발자들도 있을 수 있다. |
이름 |
Root Directory Entry Count |
||||
위치 (Offset) |
17~18 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
FAT16은 '512' FAT 32는 '0' |
설명 |
FAT16의 경우 이 항목은 루트 디렉토리에 몇 개의 엔트리(파일과 디렉토리 모두 1개의 엔트리로 친다.)를 수용할 것인지 나타낸다. 이 항목의 값은 Bytes Per Sector의 짝수이어야 한다. 즉 Bytes Per Sector가 512라면 이 항목은 512, 1024,2048과 같이 들어갈 수 있다. 최대 호환성을 위해서는 '512'로 적는게 좋다. 주의할 점은 FAT32에서는 반드시 '0'이어야 한다. |
이름 |
Total Sector 16 |
||||
위치 (Offset) |
19~20 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
FAT16은 가변적 FAT 32는 반드시 '0' |
설명 |
이 항목은 볼륨상에 있는 총 섹터 수를 2Byte로 나타낸다. 저장장치의 총 섹터수가 아닌 볼륨의 총 섹터 수이며 볼륨에 존재하는 모든 영역을 합친 섹터 수를 기록해야 한다. 이 항목의 값이 '0'이 올 수 있다. 만약 이 항목의 값이 '0' 이라면 아래 설명할 Total Sector 32 항목의 값은 절대 '0'이 되어서는 안 된다. FAT 16의 경우 총 섹터수가 '0xFFFF'보다 크다면 Total Sector 32의 항목을 이용한다. FAT32에서는 이 항목의 값이 반드시 '0'이어야 한다. |
이름 |
Media |
||||
위치 (Offset) |
21 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
0xF8 |
설명 |
이 항목은 이 볼륨이 어떤 미디어에 저장되어 있는지를 나타낸다. 보통은 고정식 디스크 값인 '0xF8'이 쓰인다. CF Card나 USB Memory는 이동식이므로 '0xF8'이 아닐 것이라고 생각 하기 쉽다. 실제 Windows가 CF Card를 포맷하면 이 항목 값을 '0xF8'이라고 적는다. 플로피 외의 저장장치라면 이 항목에 '0xF8'을 적는 것이 좋다. |
[Media 항목에 들어갈 수 있는 값들]
값 |
용량 |
저장장치 형태 |
0xF0 |
2.88MB |
3.5inch, 양면, 36 sector 플로피디스크 |
0xF0 |
1.44MB |
3.5inch, 양면, 18 sector 플로피디스크 |
0xF9 |
720KB |
3.5inch, 양면, 9 sector 플로피디스크 |
0xF9 |
1.2MB |
5.25inch, 양면, 15 sector 플로피디스크 |
0xFD |
360KB |
5.25inch, 양면, 9 sector 플로피디스크 |
0xFF |
320KB |
5.25inch, 양면, 8 sector 플로피디스크 |
0xFC |
180KB |
5.25inch, 단면, 9 sector 플로피디스크 |
0xFE |
160KB |
5.25inch, 단면, 8 sector 플로피디스크 |
0xF8 |
X |
고정식 디스크(플로피를 제외한 모든 장치 |
이름 |
FAT size 16 |
||||
위치 (Offset) |
22~23 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
FAT16은 가변적 FAT 32는 반드시 '0' |
설명 |
이 항목은 FAT 영역의 섹터 수를 저장하는 항목이다. FAT #1영역과 FAT #2영역을 합친 값이 1개의 FAT 영역의 섹터 수를 적어야 한다. 이 항목은 FAT12와 FAT16만 사용한다. FAT32는 FAT Size 32라는 항목이 따로 있다. 중요한 점은 FAT32에서는 항목의 값이 반드시 '0'이어야 한다. |
이름 |
Sector Per Track |
||||
위치 (Offset) |
24~25 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
63 |
설명 |
이 항목은 x86 프로세서 계열에서 발생하는 인터럽트(INT) 0x13을 위해 존재하는 항목으로 저장장치의 트랙당 섹터 수를 저장한다. Windows 계열에서는 더 이상 이 항목을 참조 하지 않는다. |
이름 |
Number Of Heads |
||||
위치 (Offset) |
26~27 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
255 |
설명 |
이 항목은 x86 프로세서 계열에서 발생하는 인터럽트(INT) 0x13을 위해 존재하는 항목으로 저장장치의 헤더 수를 저장한다. Windows 계열에서는 더 이상 이 항목을 참조 하지 않는다. |
이름 |
Hidden Sector |
||||
위치 (Offset) |
28~31 |
크기 (Size) |
4 Byte |
일반적인 값 (Value) |
32 |
설명 |
이 항목은 x86 프로세서 계열에서 발생하는 인터럽트(INT) 0x13을 위해 존재하는 항목으로 해당 봉륨 앞에 존재하는 (숨겨진) 섹터 수를 저장한다. 파티션되지 않은 볼륨에서는 반드시 '0'이어야 한다. Windows 계열에서는 더 이상 이 항목을 참조 하지 않는다. |
이름 |
Total Sector 32 |
||||
위치 (Offset) |
32~35 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
32 |
설명 |
이 항목은 볼륨상에 있는 섹터 수를 4Byte로 나타낸다. 중요한 것은 저장장치의 총 섹터 수가 아닌 볼륨의 총 섹터 수 라는 점이다. 볼륨에 존재하는 모든 영역을 전부 합친 섹터 수를 적어야 한다. FAT16의 경우 이 항목의 값이 '0'이 올 수 있다. 이 항목이 '0'이라면 위에서 설명한 Total Sector 16의 항목의 값은 절대 '0'이 되어서는 안 된다. FAT32에서는 이 항목의 값이 반드시 '0'이 아니여야 한다. FAT32는 Total Sector16의 항목은 이용하지 않고, Total Sector32 만을 이용해야 한다. |
여기까지는 동일한 항목이다.
여기서 클러스터의 크기를 알아보도록 하자.
Sector Per Cluster X Bytes Per Sector = 클러스터 크기 |
Sector Per Cluster : 02 (2)
Byte Per Sector : 00 02(Little Endian) => 0200(16진수)=> 512
2 X 512 = 1024 Byte, 즉 1KB가 되는 것이다.
5) FAT 16 부트 레코드 항목 설명
이름 |
Drive Number |
||||
위치 (Offset) |
36 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
0x80 |
설명 |
이 항목은 x86 프로세서 계열에서 발생하는 인터럽트(INT) 0x13을 위해 존재하는 항목으로 INT 0x13에서 정의한 드라이브 값을 설정한다. 플로피 디스크는 '0x0', 그 외의 대부분의 저장장치는 '0x80'의 값을 가진다. Windows계열에서는 더 이상 이 항목을 참조하지 않는다. 이 항목은 FAT 16에만 해당한다. |
이름 |
Reserved1 |
||||
위치 (Offset) |
37 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
0 |
설명 |
Windows NT 계열에서 사용하려고 만든 항목으로 이 값은 항상 '0'으로 해야 한다. 이 항목은 FAT 16에만 해당 한다. |
이름 |
Boot Signature |
||||
위치 (Offset) |
38 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
0x29 |
설명 |
확장 부트 서명, 이 항목의 값은 항상 '0x29'여야 한다. 이 항목이 의미하는 것은 여기가 끝이 아니라 이 항목 아래쪽에 3가지 항목이 더 추가되었다는 것을 말한다. 이 항목은 FAT16에만 해당 한다. |
이름 |
Volume ID |
||||
위치 (Offset) |
39~42 |
크기 (Size) |
4 Byte |
일반적인 값 (Value) |
가변적임 |
설명 |
볼륨 시리얼 번호, 고유의 임의의 시리얼 번호를 생성해서 기록한다. 이 항목은 FAT16에만 해당 한다. |
이름 |
Volume Label |
||||
위치 (Offset) |
43~53 |
크기 (Size) |
11 Byte |
일반적인 값 (Value) |
가변적임 |
설명 |
해당 볼륨의 레이블을 적는다. 여기에 적은 문자열은 Windows에서 드라이브 이름으로 쓰이게 된다. 사실 볼륨 레이블을 적는 부분은 2군데가 있는데, 그 중 한곳은 여기이고, 다른 한 곳은 루트 디렉토리에 존재하는 레이블 엔트리이다. 볼륨 레이블이 변경될 경우 2군데 모두 값을 바꿔 주어야 한다. 루트 디렉토리에 레이블 엔트리를 생성하지 않았다면 이 항목은 "NO NAME "라고 적어야 한다. 이 항목은 FAT16에만 해당 한다. |
이름 |
File System Type |
||||
위치 (Offset) |
54~61 |
크기 (Size) |
8 Byte |
일반적인 값 (Value) |
ASCII Code "FAT16 " |
설명 |
이 항목에는 "FAT12 ", "FAT16 ", "FAT " 중 적절한 문자열을 적어주면 된다. 주의 할 점은 여러분이 어떤 하드디스크가 FAT16인지 FAT32인지를 조사할 때 이 영역에 적힌 값을 이용해서 판단을 내리면 안 된다는 점이다. 이 항목은 단순한 문자열이며 그 외에 어떤 의미도 없기 때문에 이 영역을 잃고 볼륨을 FAT16이라고 결론을 내리면 안 된다. 이 항목은 FAT16에만 해당 한다. |
6) FAT 32 부트 레코드 항목 설명
[FAT32 부트 레코드 항목]
이름 |
FAT Size 32 |
||||
위치 (Offset) |
36~39 |
크기 (Size) |
4 Byte |
일반적인 값 (Value) |
가변적임 |
설명 |
이 항목은 Fat 영역의 섹터 수를 저장하는 항목이다. FAT #1영역과 FAT #2영역을 합친 값이 아닌 1개의 FAT 영역의 섹터 수를 적어야 한다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Ext Flags |
||||
위치 (Offset) |
40~41 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
0x00 |
설명 |
FAT 테이블을 조작하는 것에 대하여 여러 설정 값을 가진다. 이 항목은 FAT 32에만 해당한다. |
[Ext Flags]
속성 이름 |
크기 |
설명 |
||
Active FAT Number |
4Bit |
활동시킬 Fat의 번호, 0부터 시작한다. Flag 값이 '1'인 경우에만 의미가 있다. |
||
Reserved |
3Bit |
사용되지 않음. 미래를 위해 예약된 공간. |
||
Flag |
1Bit |
0 : 변경 내용을 모든 FAT 영역에 반영하라. 1 : 변경 내용을 Active FAT Number에 적힌 FAT 영역에만 반영하고 다른 영역에는 손대지 마라. |
||
Reserved |
8Bit |
사용되지 않음. 예약된 공간. |
이름 |
File System Version |
||||
위치 (Offset) |
42~43 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
0x00 |
설명 |
이 항목은 FAT32의 버전 정보를 나타낸다. 상위 바이트는 주 버전, 하위 바이트는 부 버전을 나타낸다. Windows는 이 항목을 조사하여 만약 적혀 있는 버전이 자신이 인식할 수 있는 버전보다 높다면 파티션 인식 작업을 포기하게 된다. 지금까지 나온 FAT 버전은 전부 0x00으로 설정되어 있고, 아직까지 이 버전 정보가 올라간 적이 없다. 따라서 0x00으로 설정하는 것이 좋다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Root Directory Cluster |
||||
위치 (Offset) |
44~47 |
크기 (Size) |
4 Byte |
일반적인 값 (Value) |
2 |
설명 |
이 항목은 루트 디렉토리의 클러스터 값을 담고 있다. FAT16과 다르게 FAT32의 경우 루트 디렉토리가 데이터 영역 어디에 와도 상관 없기 때문에 루트 디렉토리의 시작 위치를 적어 논 것이다. 보통의 경우 이 항목의 값은 2가 들어가는데 여러분들도 이 값을 따르는 게 좋다. 만약 실수로 이 항목의 값이 엉망이 되어 버렸다면 루트 디렉토리의 위치를 알 수 없게 되는데 항상 루트 디렉토리를 클러스터 2번 위치시켜 놓는다면 쉽게 루트 디렉토리의 위치를 복구할 수 있다. 이 항목은 FAT 32에만 해당한다. |
이름 |
File System Information |
||||
위치 (Offset) |
48~49 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
1 |
설명 |
이 항목은 FSInfo 구조체가 어디에 저장되어 있는지를 가리킨다. 보통의 경우 볼륨의 1번 섹터에 저장된다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Boot Record Backup Sector |
||||
위치 (Offset) |
50~51 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
6 |
설명 |
부트 레코드는 매우 중요하기 때문에 백업을 해두는데 그 위치를 기록 한다. 사본의 위치는 예약된(Reserved) 영역 어디에 오든 상관없지만, 일반적으로 6번 섹터를 이용한다. 이 항목의 값이 '0'이라면 백업을 하지 않았다는 의미이다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Reserved |
||||
위치 (Offset) |
52~63 |
크기 (Size) |
12 Byte |
일반적인 값 (Value) |
0 |
설명 |
미래를 위해 예약된 영역이다. 항상 0으로 채워져 있다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Drive Number |
||||
위치 (Offset) |
64 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
1 |
설명 |
이 항목은 인터럽트(INT) 0x13을 위해 존재하는 항목이다. Windows 계열에서는 더 이상 이 항목을 참조하지 않으므로 어떤 값을 써도 무방하다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Reserved1 |
||||
위치 (Offset) |
65 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
0 |
설명 |
Windows NT 계열에서 사용하려고 만든 항목이다. 이 항목은 항상 0으로 해야 한다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Boot Signature |
||||
위치 (Offset) |
66 |
크기 (Size) |
1 Byte |
일반적인 값 (Value) |
0x29 |
설명 |
확장 부트 서명이다. 이 항목의 값은 항상 '0x29'여야 한다. 이 항목이 의미하는 것은 여기가 끝이 아니라 이 항목 아래쪽에 세 가지 항목이 더 추가되었다는 것을 말한다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Volume ID |
||||
위치 (Offset) |
67~70 |
크기 (Size) |
4 Byte |
일반적인 값 (Value) |
가변적임 |
설명 |
볼륨 시리얼 번호이다. 고유의 임의의 시리얼 번호를 생성해서 기록한다. 이 항목은 FAT 32에만 해당한다. |
이름 |
Volume Label |
||||
위치 (Offset) |
71~81 |
크기 (Size) |
11 Byte |
일반적인 값 (Value) |
가변적임 |
설명 |
볼륨 레이블로 해당 파티션의 볼륨 레이블을 적는다. 여기에 적은 글자는 Windows에서 디스크 이름으로 쓰인다. 볼륨 레이블을 적는 부분이 2군데가 있는데 그 중 하나는 여기이고, 다른 한 곳은 루트 디렉토리이다. 볼륨 레이블이 변경될 경우 2군데 모두 값을 바꿔야 한다. 볼륨 레이블이 없는 경우 "NO NAME "이라고 적어준다. 이 항목은 FAT 32에만 해당한다. |
이름 |
File System Type |
||||
위치 (Offset) |
82~89 |
크기 (Size) |
8 Byte |
일반적인 값 (Value) |
ASCII Code "FAT32 " |
설명 |
Windows는 이 항목에 항상 "Fat32 "라고 적는다. 이 항목은 단순한 문자열이며 그 외에 어떤 의미도 없기 때문에 이 영역을 잃고 볼륨을 FAT32이라고 결론을 내리면 안 된다 이 항목은 FAT 32에만 해당한다. |
- 부트 레코드 항목 중에는 문자열을 저장하는 항목이 있는데 OEM Name, Volume Label, File System Type 항목은 문자열을 저장한다.
- 이 항목에 문자열을 저장하는 데 있어서 주의해야 할 점은 빈 공간을 반드시 Space(0x20)로 처리해야 한다.
만약 C언어로 File System Type에 "FAT16"이라는 문자를 넣을 때 코드를 보자
strcpy(FileSystemType, "FAT16");
이렇게 되면 저장되는 모양은
F |
A |
T |
1 |
6 |
NULL |
X |
X |
0x46 |
0x41 |
0x54 |
0x31 |
0x36 |
0x0 |
알 수 없음 |
알 수 없음 |
하지만 빈 공간에는 Space가 들어가야 한다.
아래 형태로 구현을 하기 위해 문자열 제어 함수를 사용하지 말고 직접 특별한 문자열 제어 함수를 구현하던지 배열 값을 넣어야 한다.
F |
A |
T |
1 |
6 |
Space |
Space |
Space |
0x46 |
0x41 |
0x54 |
0x31 |
0x36 |
0x20 |
0x20 |
0x20 |
7) 부트 레코드의 끝부분
- 부트 레코드를 구현하는데 있어 FAT16/32 모두 부트 레코드 영역의 Offset 511~512에는 반드시 0xAA55라는 서명이 들어간다.
이름 |
Signature |
||||
위치 (Offset) |
510~511 |
크기 (Size) |
2 Byte |
일반적인 값 (Value) |
반드시 0xAA55 |
설명 |
이 항목은 부트 레코드가 손상되었는지 아닌지 확인 하는 용도로 사용하며 이 항목이 없다면 Windows에서는 부트레코드가 망가졌다고 판단하고 인식을 못하게 된다. 이 항목은 FAT 16, FAT32에만 모두 해당한다. |
많은 FAT문서에는 "Signature의 위치는 부트 레코드 가장 끝부분" 이라고 하지만 이것은 섹터가 512Byte일 경우에만 유효한 내용이며, Microsoft에서 제공하는 공식 문서에는 섹터의 크기가 512Byte보다 큰 경우라도 Signature는 Offset 510~511에 와야한다.
4. 부트레코드 실습
관리자권한으로 실행
프로젝트 속성 – 구성 속성 – 일반 -> 프로젝트 기본값 – 문자집합 : 멀티 바이트 문자 집합 사용
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#define U8 unsigned char
#define S8 char
#define U16 unsigned short
#define U32 unsigned int
#define U64 unsigned __int64
#pragma pack(1) //컴파일러에게 구조체 패딩을 넣지 말라고 선언
typedef struct _FAT16_BPB_struct{ //FAT16 부트 레코드 선언
//공통 영역
U8 JmpBoot[3];
U8 OEMName[8];
U16 BytsPerSec;
U8 SecPerClus;
U16 RsvdSecCnt;
U8 NumFATs;
U16 RootEntCnt;
U16 TotSec16;
U8 Media;
U16 FATs16;
U16 SecPerTrk;
U16 NumHeads;
U32 HiddSec;
U32 TotSec32;
//FAT 16영역
U8 DirveNumber;
U8 Reserved1;
U8 BootSignal;
U32 VolumeID;
U8 VolumeLabel[11];
U8 FileSysType[8];
U8 BootCodeArea[448];
U16 Signature;
}FAT16_BPB;
#pragma pack()
typedef struct _VOL_struct{ //볼륨의 전반적인 정보를 담는 구조체
U32 Drive;
U32 VolBeginSec;
U32 FirstDataSec;
U32 RootDirSec;
U32 RootEntCnt;
U32 RootDirSecCnt;
U32 FATSize;
U32 FATStartSec;
U32 TotalClusCnt;
U32 TotalSec;
U32 DataSecSize;
U32 ClusterSize;
U32 SecPerClus;
}VolStruct;
U32 HDD_read(U8 drv, U32 SecAddr,U32 blocks, U8* buf);
U32 get_BPB_info(FAT16_BPB* BPB, VolStruct* PVol);
VolStruct gVol;
int main(void){
U8 buf[512];
gVol.Drive = 0x2; //드라이브 설정
gVol.VolBeginSec = 0x87; //부트 섹터가 있는 곳
if(HDD_read(gVol.Drive, gVol.VolBeginSec,1, buf) == 0){
printf("Boot Sector Read Failed \n");
return 1;
}
if(get_BPB_info((FAT16_BPB*)buf, &gVol) ==0){
printf("It is not FAT16 File System \n");
return 1;
}
printf("[[[[[[[[[Volume Information ]]]]]]]]]\n");
printf("Total Sector = %d Sectors : %dMB\n",gVol.TotalSec, ((gVol.TotalSec*512)/1024)/1024);
printf("FAT Size = %d Sectors \n",gVol.FATSize);
printf("Root Dir Sector = %d \n", gVol.RootDirSec);
printf("Root Dir Sector Count = %d \n", gVol.RootDirSecCnt);
printf("First Data Sector = %d \n",gVol.FirstDataSec);
printf("Data Sector Count = %d Sectors \n",gVol.DataSecSize);
printf("Total Cluster = %d \n", gVol.TotalClusCnt);
printf("Size of Cluster = %d : %dKB \n",gVol.ClusterSize, gVol.ClusterSize/1024);
return 0;
}
U32 get_BPB_info(FAT16_BPB* BPB, VolStruct* pVol){
//Root Entry Count 항목 조사, 0이면 FAT16이므로 파일시스템 종류 알기 좋다.
if(BPB->RootEntCnt == 0 || BPB->Signature != 0xAA55)
return 0;
//부트 레코드 정보 얻기.
if(BPB->TotSec16 !=0) pVol->TotalSec = BPB->TotSec16;
else pVol->TotalSec = BPB->TotSec32;
//get FAT Size
pVol->FATSize = BPB->FATs16;
//get FAT Start Secotr
pVol->FATStartSec = pVol->VolBeginSec + BPB->RsvdSecCnt;
//get Root Dir Entry Count
pVol->RootEntCnt = BPB->RootEntCnt;
//get Root Dir Sector
pVol->RootDirSec = pVol->VolBeginSec + BPB->RsvdSecCnt + (BPB->NumFATs * BPB->FATs16);
//get Root Dir Sector Count
pVol->RootDirSecCnt = ((BPB->RootEntCnt * 32) + (BPB->BytsPerSec -1 )) /BPB->BytsPerSec;
//get FAT Start Sector
pVol->FirstDataSec = pVol->VolBeginSec +BPB->RsvdSecCnt + (BPB->NumFATs * pVol->FATSize) + pVol->RootDirSecCnt;
//get Size of Data Area
pVol->DataSecSize = pVol->TotalSec - (BPB->RsvdSecCnt + (BPB->NumFATs * pVol->FATSize) + pVol->RootDirSecCnt);
//get Total Cluster Count
pVol->TotalClusCnt = pVol->DataSecSize / BPB->SecPerClus;
//get Sector per Cluster
pVol->ClusterSize = BPB->SecPerClus * BPB->BytsPerSec;
//get Sector Per Cluster
pVol->SecPerClus = BPB->SecPerClus;
return 1;
}
U32 HDD_read (U8 drv, U32 SecAddr, U32 blocks, U8* buf){
U32 ret;
U32 ldistanceLow, ldistanceHigh, dwpointer, bytestoread, numread;
char cur_drv[100];
HANDLE g_hDevice;
sprintf_s(cur_drv,sizeof(cur_drv),"\\\\.\\PhysicalDrive%d",(U32)drv);
g_hDevice=CreateFile(cur_drv, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(g_hDevice==INVALID_HANDLE_VALUE) return 0;
ldistanceLow = SecAddr << 9;
ldistanceHigh = SecAddr >> (32 - 9);
dwpointer = SetFilePointer(g_hDevice, ldistanceLow, (long *)&ldistanceHigh, FILE_BEGIN);
if(dwpointer != 0xFFFFFFFF) {
bytestoread = blocks * 512;
ret = ReadFile(g_hDevice, buf, bytestoread, (unsigned long*)&numread, NULL);
if(ret) ret = 1;
else ret = 0;
}
CloseHandle(g_hDevice);
return ret;
}
[드라이브 설정]
위에 진하게 주석 한 부분에서 드라이브 설정을 할 때
gVol.Drive = 0x2를 한 것은 아래 D드라이브를 테스트 하려고 한 것이다.
만약 디스크0번을 분석하려면
gVol.Drive = 0x0 으로 설정 해야한다.
[부트레코드 섹터위치]
gVol.VolBeginSec = 0x87;
아래 스샷은 FTK Imager로 확인을 해보았다.
실행화면..
'Operating System' 카테고리의 다른 글
[파일시스템] FAT16 파일시스템 (3/3) (0) | 2020.05.26 |
---|---|
[파일시스템] FAT16 파일시스템 (2/3) (0) | 2020.05.26 |
[파일시스템] 파티션 (1) | 2020.05.26 |
[파일시스템] 파일시스템의 이해 (0) | 2020.05.24 |
[임베디드OS개발프로젝트] 5장. UART (0) | 2020.01.20 |