Programming2008. 12. 3. 11:50
 

윈도우는 크게 윈도우 95, 98, ME 등의 9x 계열과 윈도우 NT, 2000, XP, 2003 등의 NT 계열로 구분된다. 이것은 파일복구 소프트웨어를 구현하는 과정에서도 매우 중요한 고려사항인데, 두 계열이 디스크에 대한 접근 방식이 서로 다르기 때문이다. 디스크는 크게 논리적 볼륨과 물리적 볼륨으로 나누어 생각할 수 있다. 논리적 볼륨은 파티션의 시작을 0으로 보는 것이고 물리적 볼륨은 디스크의 시작을 0으로 보는 것이다. 여기서 0은 오프셋 섹터(Offset Sector)를 의미하며 디스크에 물리적으로 접근할 것인지 논리적으로 접근할 것인지에 따라 차이가 있다.
예를 들어 디스크에 2개의 드라이브 즉 C:와 D:가 존재하고 디스크의 섹터수는 총 100개라면 물리적 볼륨은 0부터 99가 된다. 반면 논리적 볼륨은 C 드라이브의 경우 0부터 49가 되고 D드라이브는 50부터 99가 아닌 0부터 49가 된다. 이것은 C 드라이브라는 논리적 볼륨과 D 드라이브라는 논리적 볼륨의 오프셋 섹터가 각각 0부터 시작되기 때문이다. 물리적 볼륨은 디스크 전체에 대하여 오프셋 섹터가 0부터 시작하므로 어떤 볼륨으로 할 것인지 여부가 무의미하다. 다만 해당 볼륨의 위치부터 0으로 간주해 별도의 처리를 해야 한다. 따라서 디스크를 논리 드라이브 단위로 액세스한다면 논리 C 드라이브를 읽어들일 것인지 D 드라이브로 읽어들일 것인지 결정하는 것이 중요하다.

윈도우 9x와 NT 계열 판별하기
한편 9x 계열과 NT 계열의 차이는 앞서 살펴본 바와 같이 물리적 볼륨과 논리적 볼륨에 대한 함수 인터페이스가 동일한 지에 대한 여부이다. NT 계열은 물리적으로 디스크에 액세스하든 논리적으로 디스크에 액세스하든 입출력 장치제어 API 함수를 호출해 사용하지만, 9x 계열은 논리 볼륨에 대한 액세스의 경우 FAT 파일 시스템의 파일할당 테이블의 비트 깊이가 12인지 16인지 32인지에 따라 각각 다른 방법으로 접근해야 하고 그 외의 파일 시스템은 모두 물리 볼륨에 대한 액세스로 해야 한다. 이 때 물리 볼륨에 대한 액세스는 지난 호에 설명한 썽킹(thunking) 레이어 방식 등을 이용해 16비트와 32비트 DLL을 각각 별도로 빌드하여 연결고리가 있는 부메랑처럼 디스크를 액세스한다.
9x 계열과 NT 계열에 따라 디스크 접근방식이 다르므로 이번 호에 구현하는 소프트웨어에서는 프로그램이 실행될 때  어떤 계열인지 판별해 그에 맞는 디스크 접근방식으로 동작하도록 해야 한다. 윈도우 2000은 여러 제품군이 있지만 실질적으로 윈도우 NT 버전 5.0이다. 이 때 주 번호(Major), 부 번호(Minor), 빌드번호(Build) 등으로 나눌 수 있는데 윈도우 2000의 경우 각각 주 번호는 5, 부 번호는 00, 빌드번호는 2195이다.
윈도우 NT 4.0은 주 번호가 4, 부 번호가 00이고, NT 3.51은 주 번호가 3, 부 번호가 51이다. 윈도우 ME는 4.90.3000이고 윈도우 98 SE는 4.10.2222, 윈도우 98은 4.10.1998이다. 이러한 정보들은 구조체 OSVERSIONINFOEX를 API 함수인 GetVersionEx()에 건네주어 호출함으로써 값들을 얻어낼 수 있다. OSVERSION INFOEX가 윈도우 2000 이상에서 지원되기 때문에 윈도우 9x에서는 OSVER SIONINFO를 이용하여 호출하면 된다.

출처 : 마이크로스프트웨어

Posted by skensita
Programming2008. 12. 3. 11:48

지난 호에서 NTFS(New Technology File System)의 내부구조에 대해서 알아보았는데 실제로 삭제된 파일을 복구하기 위해서 어디서부터 어떻게 개발해야 할지 막막한 느낌이 없지 않을 것이다. 가장 먼저 해야 할 일은 부트섹터를 읽어 들이는 것이다. 이 자료를 바탕으로 볼륨 전체의 경계선(boundary) 정보를 추출하고 MFT와 MFT Mirror는 어디서부터 시작되는지, 클러스터의 크기는 얼마인지 등에 대해 알아낼 수 있다.
그 후 MFT 파일레코드를 순차적으로(또는 임의로) 읽어 들여 삭제된 파일을 목록화한다. 이 때는 파일명을 기준으로 정렬하되, 날짜, 크기, 파일 내용 등 삭제된 파일을 복구하는데 필요한 정보들을 구조체 또는 클래스로 개발해 궁극적으로는 사용자들이 복구할 파일이나 폴더를 선택할 수 있는 <화면 1>과 같은 형태로 시각적으로 보여줘야 한다.
윈도우 NT, 윈도우 2000 그리고 윈도우 XP용 파일시스템과 필터 드라이버를 개발하는데 필요한 NT IFS(Installable File System) 헤더 파일은 전체가 8000줄 정도로 다소 간단한 편이다. 그러나 이번 호에 구현하는 것은 디스크 드라이버에서 읽은 섹터 내용을 참고해 NTFS를 직접 구성하고 읽어 들이는 방식이므로 이렇게 많은 코드가 필요치 않다. 여기서는 이 파일 가운데 꼭 필요한 내용을 중심으로 NTFS의 내부 자료구조들을 구조체로 정의해본다.
먼저 다음과 같은 새로운 자료형을 정의하자. 식별이 용이하도록 기존 자료형인 UCHAR, USHORT, ULONG, ULONGLONG, USN을 U8, U16, U32, U64, U64로 정의한다. 여기서 8, 16, 32, 64는 비트 수를 의미하며, 각각 1바이트, 2바이트, 4바이트, 8바이트이다. BOOLEAN은 참, 거짓을 1과 0으로 식별할 수 있는 자료형으로, 여기서는 간단하게 TF라고 재정의하자.

typedef BOOLEAN  TF;
typedef UCHAR  U8;
typedef USHORT  U16;
typedef ULONG U32;
typedef ULONGLONG U64;
typedef USN  U64;

다음은 NTFS의 레코드 헤더를 구조체로 정의한 것이다. Type에는 레코드 헤더의 매직넘버 즉 ‘FILE’이라는 식별자가 들어간다(실제로 읽어 들일 때에는 ‘ELIF’로 순서가 바뀐다). UsaOffset은 업데이트 시퀀스(Update Sequence)에 대한 오프셋이고 UsaCount는 USN(Update Sequence Number)과 배열의 워드 크기이다. Usn은 $LogFile의 시퀀스 번호(LSN)이며 NTFS_RECORD_HEADER는 구조체 변수, PNTFS_RECORD_HEADER는 구조체의 포인터 변수다.

출처 : 마이크로소프트웨어

Posted by skensita
Programming2008. 12. 3. 11:48

지난 호에서는 파일복구 프로그램을 제작함에 있어 필수적으로 알고 있어야 할 기본원리, 즉 파일시스템의 정의와 종류, 디스크 접근방법, 파일복구 프로그래밍을 위한 준비 등에 대해서 알아보았다. 이번 호에서는 파일복구 프로그램의 성능을 좌우하고 기본적으로 주요 개발대상이 되어야 할 ‘다양한 파일시스템’을 지원하기 위하여 NTFS 파일시스템의 내부구조에 대해 상세히 다뤄보자. 아울러 파일복구 프로그램 성능에 관한 판단기준도 살펴보자.

지난 호에서 FAT(File Allocation Table)와 NTFS(New Technology File System) 등 두 가지 파일시스템의 성능 측면을 개괄적으로 살펴보았는데 이번 호에서는 여기서 한 발 더 나아가 심도있는 내용을 다뤄보자. NTFS는 상당히 복잡한 구조를 가지고 있기 때문에 그 구조를 알기 위해 알아야 할 개념들도 방대하고 난해하다. 특히 FAT에 비해 파일을 읽어 들이는 방법이 공개돼 있지 않고 알고리즘 역시 알려지지 않았으므로 여기서는 NTFS에 초점을 맞춰 진행한다.
지난 호를 통해 파일복구 과정은 삭제된 파일을 복구하는 것임을 살펴봤다. 그렇다면 디스크 또는 드라이브에서 단지 삭제된 파일만 찾는 것이 중요할까. 꼭 그렇지는 않다. 삭제된 파일은 단지 삭제된 것으로 최소의 표시를 해두고 다른 데이터가 기록될 수 있도록 공간이 쓰기 가능한 곳으로 남게 되므로 정상인 파일을 읽어 들이는 방법도 반드시 알고 있어야 한다. 즉 추가적인 기록이 없다면 복구작업 자체가 불가능하다.

NTFS의 탄생 배경
NTFS는 OS2의 HPFS((High Performance File System)와 도스/윈도우의 FAT 파일시스템을 대체하기 위해 개발됐다. 구체적으로는 신뢰성(reliability)과 보안성(security), 데이터 중복성(data dedundancy), 결함 방지(fault tolerance), 대용량 디스크와 파일, 다중 데이터 스트림, 유니코드 지원, 파일 속성의 인덱싱, 불량 클러스터에 대한 동적 리맵핑(회피), POSIX 지원 등에 초점을 맞춰 설계됐다.
신뢰성은 데이터의 저장과 접근에 있어 신뢰할 만한 트랜잭션 처리모델에 기반한 파일시스템 복구 기능을 제공하고 모든 입출력 연산을 단위 트랜잭션으로 처리하는데 주력했으며, 데이터베이스에서의 트랜잭션에서 볼 수 있는 ACID(Atomicity, Consistency, Isolation, Durability) 속성을 새롭게 지원한다. 보안성은 윈도우 NT의 객체모델에서 파생된 것으로, 프로세스가 파일객체에 대한 핸들을 열기 위한 권한의 적합성을 가졌는지 여부를 검증한다.
또한 NTFS는 WDM(Windows Driver Model), WDF 등 윈도우 NT 계층의 드라이버 모델을 사용해 결함방지가 가능한 디스크 지원을 제공한다. 이를 통해 하드디스크 드라이버와 간접적으로 교류하며 데이터 미러링(레이드0)과 패리티를 통한 스트라이핑(레이드5)도 지원한다. NTFS는 클러스터를 어드레싱하기 위해 이론적으로 64비트를 사용한다. 클러스터의 크기는 최대 64KB까지 264개까지 가능하다. 파일의 최대 크기는 264바이트이다.

출처 : 마이크로스프트웨어

Posted by skensita
Programming2008. 12. 3. 11:39
파일복구 프로그램이란 디스크에 저장한 파일이 삭제됐을 때 이를 원형 그대로 복원하는 작업을 자동화한 애플리케이션이다. 복원률은 파일시스템의 특성에 따라 100%에서 0%까지 천차만별인데, 일반적으로 FAT(File Allocation Table) 파일시스템의 경우 덮어쓰기(overwrite)되지 않았고 데이터가 연속적으로 저장돼 있는 경우 100% 복원 가능하며, 두 가지 조건에서 어긋날 수록 확률이 낮아진다. NTFS(New Technology File System) 파일시스템 역시 복원률을 결정하는 조건은 FAT와 같다(물론 파일시스템의 설계 상 기본적으로 FAT보다 복원률이 높다).
복원이나 복구나 서로 유사한 말이긴 하나, 복원이란 말은 원형 그대로 다시 살릴 수 있는 경우이고 복구란 원형 그대로는 다시 살릴 수 없으나 부분적으로 회복하는 경우다. 이번 연재를 통해 개발해 볼 프로그램은 역시 하드디스크에 기록된 파일이 삭제됐을 때 이를 복구해 주는 프로그램이다.
현재 국내에 출시된 파일복구 프로그램에는 여러 가지가 있다. 파이널데이터의 파이널데이터와 바이로봇이라는 백신 프로그램으로 유명한 하우리의 데이터메딕, 라이브데이터의 라이브데이터, 그리고 필자가 무료배포하고 있는 데이터매직 등이 있다. 프리웨어로 배포하는 해외 프로그램에는 일본인인 Brian Kato가 만든 Restoration 2.5.14 버전이 있으나 2002년 5월 14일 이후로 버전업이 중단된 상태다(클러스터 검색기능은 데이터복구 프로그램과 파일복구 프로그램을 구분하는 기준이기도 하다).

파일복구 프로그램의 원리
파일복구 프로그램은 어떻게 삭제된 파일을 복구하는 것일까? 해답은 파일시스템의 설계에 있다. 현재 가장 널리 사용되는 FAT과 NTFS를 기준으로 살펴보면, 먼저 FAT에는 디렉토리 엔트리(Directory Entry)가 존재한다. 이곳에 파일과 디렉토리에 대한 정보와 파일명이 기록되는데 파일이나 폴더가 삭제되면 첫 번째 바이트에 E5h가 마킹돼 탐색기 상에서는 마치 지워진 것으로 간주돼 표시되지 않는다. 파일복구 프로그램은 이렇게 E5h로 된 엔트리의 시작 클러스터 값을 참조해 파일할당 테이블에서 데이터 클러스터와 맵핑된 위치로 가서 파일 크기만큼 읽어오는 방식을 사용한다. 이렇게 찾은 것이 곧 복구하고자 하는 파일의 내용이므로 이를 다른 드라이브에 저장해 파일을 복구한다. 이 때 덮어쓰기가 이루어지지 않았고, 데이터가 즉 클러스터가 연속적으로 저장돼 있다면 거의 100%까지 복구할 수 있다.
NTFS는 섹터의 몇 개 묶음을 최대 4KB 이내에서 하나의 클러스터로 보고, 이러한 단위 클러스터에 파일 레코드를 하나씩 배치한다. 섹터를 512바이트로 보면 8개 섹터가 하나의 클러스터가 되고 이것이 최대치이므로 클러스터가 곧 파일레코드이자 NTFS의 저장단위인 셈이다.
NTFS는 메타데이터와 정상파일(normal files)로 구분된다. 메타데이터에는 $MFT, $MFTMirr, $LogFile, $Volume, $AttrDef, .(루트), $Bitmap, $Boot, $BadClus, $Secure, $UpCase, $Extend 등이며, 정상파일은 파일과 폴더를 의미한다. 파일레코드에는 메타데이터들이 각각 존재하며 이러한 파일레코드를 읽어 지워진 파일레코드로 표시된 경우를 찾아 복구하는 방식이다. 실제 복구과정은 삭제된 것으로 표시된 파일레코드의 LCN (Logical Cluster Number)를 찾아 VCN (Virtual Cluster Number)만큼 런리스트(Run List)를 참조해 읽어 들인 후 저장한다.

파일복구 프로그래밍의 출발점, 파일시스템
이처럼 파일시스템에 대한 이해는 파일복구 소프트웨어를 만드는 출발점이다. 파일시스템은 운영체제의 특성을 가장 잘 표현하며 자료를 기록할 수 있는 스토리지 미디어의 근간을 이루는 것으로 미디어 내에 데이터를 저장, 관리하는데 있어 프로세스 권한에 따라 데이터를 노출, 은닉, 암호화하고 손실 시 이를 다시 원래 상태로 회복시키는 등 총체적인 데이터 운용 기술이 적용된다(파일시스템과 비슷하게 사용되는 개념이 파일링시스템이다. 파일링(filing)이란 컴퓨터에 의해 제공되는 가장 중요한 서비스 가운데 하나로 오랜 시간에 걸쳐 대량의 데이터를 조직하고 저장할 수 있는 것을 뜻한다. 파일링시스템은 더 광의의 파일시스템이다).
FAT 파일시스템의 가장 중요한 설계 중심은 파일할당 테이블이라는 연결리스트(Linked List)의 자료구조다. FAT는 파일할당 테이블의 단위 크기에 따라 구분되는데, FAT12는 파일할당 테이블의 크기가 12비트이며, FAT16과 FAT32는 각각 16비트, 32비트의 단위 크기를 가지고 있다(<표 1> 참고). 이들은 클러스터 크기도 달라, FAT12는 212, FAT16과 FAT32는 각각 216, 232이다. 이밖에도 FAT32는 유니코드를 지원하는데, 긴파일이름(Long File Name)이라는 개념은 기존 디렉토리 엔트리와의 길이 호환성을 위해 나온 것이다.
일반적으로 FAT32는 루트 디렉토리의 크기제한이 없기 때문에 루트 디렉토리가 없다고 알려져 있으나 FAT32에도 엄연히 루트 디렉토리가 존재한다. 다만 그 형태가 FAT12, FAT16처럼 루트 디렉토리 영역으로 제한되지 않고 서브 디렉토리와 같은 형태로 자유롭다는 차이가 있다.
NTFS는 설계 상 새로운 기술들이 많이 적용된 파일시스템으로 <표 2>는 그 특징을 FAT 파일시스템과 비교해 정리한 것이다. 많은 사람들이 NTFS 버전 3.0 이상의 특징 중 하나인 희소 파일(Sparse Files)에 대해서 어렵게 생각하는데 이것은 자료구조를 배운 개발자라면 쉽게 이해할 수 있다. 희소행렬을 연결리스트 또는 비트맵(Bitmap)으로 표현한다고 보면 된다. 예를 들어 다음과 같이 가로, 세로가 8×3 크기의 행렬이 있다고 가정하면 2차원 배열을 이용했을 때 24바이트가 필요하다.

3 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 5

반면 연결리스트를 이용하면 다음과 같이 선형(linear)으로 이용할 수 있다.

3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5

이렇게 하면 단지 2개의 값 3, 5에 대해서만 연결을 갖고 있고 나머지는 0으로 간주해 더 효율적으로 구현할 수 있다. 희소파일이란 이처럼 0이 많은 데이터의 경우 0에 대해 디스크에 기록하거나 보관할 필요가 없도록 하는 파일들을 말한다. 100MB 용량의 파일 가운데 0이 아닌 데이터가 1MB이고 나머지 99MB가 0이라면 실제 디스크를 차지하는 공간은 1MB가 되는 것이다.
그렇다면 구체적으로 디스크와 드라이브에는 어떻게 접근해야 할까. 접근방법에는 크게 4가지가 있다. 예를 들어 디스크 하나를 파티션 두 개로 분할해 2개의 드라이브로 사용한다면, 논리적인 접근은 해당 드라이브의 파일시스템 구조만 알면 섹터 읽기/쓰기를 할 수 있다. 반면 디스크 단위로 섹터에 접근할 때 사용하는 물리적 접근은 파일시스템에 대한 구조뿐만 아니라 MBR(Master Boot Record)과 확장 MBR에 대한 이해가 필수적이다.
CHS(Cylinder Head Sector) 방식과 LBA(Logical Blocking Address) 방식도 있다. CHS 방식은 실린더, 헤드, 그리고 섹터 값을 통해 디스크에 접근하는 것이며, LBA는 선형적으로 1번 섹터 형태로 단일 값으로 순차적으로 접근하는 방식이다. CHS 방식은 바이오스에서 실린더를 1024개까지만 지원하는데 실린더로 MBR에 10비트만 기록할 수 있다. 이는 실린더 210=1024, 헤드 28-1 = 255, 섹터 26-1 = 63과 같은 형태로 3바이트를 차지하기 때문으로, 1024×255×63×512를 계산한 뒤 1024로 3회 나누면 GB 단위가 되므로 약 7.8GB, 즉 기존 CHS 방식으로는 7.8GB 제한이 발생하는 것이다(이런 제한을 개선한 것이 확장 CHS 방식이다. LBA 값을 환산해 CHS로 표기하는 형태다).
이 때 중요한 개념이 마스터 부트섹터(MBS)와 파티션 부트섹터(PBS)다. 이들은 문자 그대로 하나의 섹터로, 512바이트를 기준으로 하면 매우 작은 공간에 불과하지만 매우 큰 역할을 맡고 있다. MBR은 썬 계열과 일반 PC 사용자들이 많이 접하는 인텔 계열이 있는데, IPL(Initial Program Loader)이라는 446바이트 크기의 프로그램과 16바이트 길이의 4개 파티션 테이블, 그리고 매직넘버(Magic Number)가 기록된다.
IPL의 일반적인 역할은 다음과 같다. PC에 전원이 들어온 후 PO ST(Power On Self Test) 과정을 거치고 나면 바이오스 롬이 MBR을 0000:7C00h에 로드한다. 하드디스크 개수를 DL 레지스터에 건네주면 그 수를 점검한 후(일부 바이오스는 0) 부트로더용 부트 플래그(0 또는 1)를 확인하고 기본 파티션에서 활성 파티션을 찾는다. 이때 적절한 파티션이 없으면 그 다음 하드디스크 드라이브로 부팅하고 어떤 파티션이 존재하지 않을 경우 첫 번째 플로피디스크 드라이브로 부팅한다. 하드디스크이든 USB-UFC 등의 메모리이든 부팅할 수 있는 파티션이라면 해당 파티션의 부트섹터 즉 파티션 부트섹터가 메모리에 올라간다. 그리고 부트코드(Boot Code)가 실행된다(부트코드는 커널을 로드하거나 운영체제에서 처음에 수행해야 할 초기 설정을 실행한다). 그러나 IPL과 부트로더는 다양한 형태가 있다.

디스크 접근 방법
PBS는 도스용 백신 프로그램에서 DBS(DOS Boot Sector)라고 표기하기도 한다. PBS와 MBR는 개념적으로는 유사해, 코드 영역과 데이터 영역을 갖는 공통점이 있고 부트코드에서 부트로더로의 바통 터치도 흡사하다. 단 MBR은 코드 영역이 먼저 위치하고 데이터 영역이 뒤따르는 반면 PBR은 데이터 영역이 먼저 온다.
부트코드는 512바이트의 공간에 존재하는 코드 영역으로, 부트로더라고도 부른다. 최근의 운영체제들은 디스크 내의 모든 파티션에서 부팅할 수 있는, 이른바 멀티부트를 지원하는 확장 부트로더 개념이 도입돼 있는데 예를 들어 NT 로더는 MBR 차원이 아닌 PBR 차원에서 더 많은 섹터를 사용해 기능을 확장했다. FAT16의 부트코드를 보면 FAT 16 파일시스템은 설계상 2GB의 제한이 있어, 이를 사용했던 윈도우 95의 경우 부트 파티션의 크기가 2GB를 넘는 부트코드를 인식하지 못했다(물론 부트코드를 수정해 기술적으로 2GB 문제를 해결할 수 있지만 부트코드를 만드는 업체는 마이크로소프트(이하 MS)이므로 일반 사용자는 그냥 불편을 감수해야 했다. 물론 개발자라면 누구나 시도해 볼 수 있지만 어셈블리로 구현하는 경우가 많으므로 이 언어에 대한 지식이 필수적이다).
MBR이 PBR을 0000:7C00h에 로드하면 도스 커널인 IO.SYS 파일을 찾는 작업을 시작한다. 부트섹터에 있는 데이터 영역을 참조해 루트 디렉토리 엔트리(Root Directory Entry)의 위치를 찾고, 32바이트씩 읽어 들이되 맨 앞에서부터 11바이트를 로드한다. 처음 8바이트는 파일 이름이 IO인지 비교하고 이후 3바이트는 확장자가 SYS인지 비교한다.
<표 3>을 보면 IO.SYS 파일을 찾아 시작 클러스터의 값을 읽어들이는 것을 알 수 있다. 파일할당 테이블에서 시작 클러스터 값에 해당하는 데이터 영역의 위치를 계산해 찾은 뒤 파일 크기만큼 읽는다. 특히 첫 번째 섹터에 있는 헤더가 MZ인지 확인한 뒤 IO.SYS 즉 커널을 로드한다.
전통적인 부트코드의 역할은 이 정도다. 현재와 같은 멀티부트로더는 NT 로더와 같이 더 복잡하게 작동한다. 이 원리를 이해하는 것이 중요한 이유는 파일을 불러오는 원리가 파일복구 프로그램의 그것과 동일하기 때문이다. 즉 파일이 삭제되면 IO.SYS 파일에서의 I 값에 해당하는 값이 49h가 E5h로 마킹된다. 이것을 도스나 윈도우 운영체제는 지워진 것으로 판단하고 화면에 보여주지 않는다. <화면 2>는 데이터 영역 즉 데이터 클러스터에 있는 내용을 확인한 대화상자다. FAT 부트섹터는 도스 버전이 2.x, 3.x, 4.x, 5.x 등으로 높아지면서 디스크 용량도 증대되고 시대적 요구에 맞게 부트섹터 또한 확장됐다.
NTFS 부트섹터 역시 FAT과 유사하다. 그러나 앞서 언급한 대로 NTFS 고유의 특성과 정보를 담아야 하기 때문에 일부 FAT와 다른 부분이 있다. 예를 들어 FAT32 등으로 기록해야 할 파일시스템 ID은 NTFS로 변경되고 제조자 ID는 제거되며, 총 섹터수가 64비트로 늘어나면서 NTFS 고유의 내부구조를 알 수 있는 정보인 $MFT의 논리 클러스터 번호(Logical Cluster Number for the file $MFT), $MFTMirr의 논리 클러스터 번호(Logical Cluster Number for the file $MFTMirr), 파일레코드 세그먼트당 클러스터수(Cluster/File Record segment), 인덱스 블럭당 클러스터수(Cluster/Index Block), 체크섬(Checksum) 등은 NTFS 고유의 특성 정보들이 추가됐다.

파일시스템의 종류
디스크 기반의 파일시스템에는 다양한 특성과 목적을 가진 파일시스템이 있다. 특히 파일시스템은 목적지향(Purpose-oriented)적으로 설계된다. 각 파일시스템은 특정 목적에 맞게 개발되기 때문에 어떤 파일시스템이 좋다고 평가하는 것은 무리다. 단 같은 분류에 속한 파일시스템 간에는 비교할 수 있는데, 예를 들어 많은 사람들이 사용하는 FAT와 NTFS의 비교가 바로 그것이다.
그러나 여기도 한 가지 함정이 있다. 양쪽 모두 디스크 파일시스템임은 분명하지만 NTFS는 저널링 파일시스템(Journaling File System)이고 FAT는 그렇지 않다. MS는 FAT와 NTFS를 비교해 발표하지만 이는 단지 마케팅 전략의 하나로 윈도우 9x 유저에게 새로운 운영체제의 우수성을 알리기 위한 것일뿐 디스크 파일시스템(Disk File System)으로 비교한 것은 아니다.
파일시스템의 종류는 상당히 많지만 특성에 따라 분류하면 디스크 파일시스템(Disk File Systems), 로그 구조의 파일시스템(Log-structured File System), 저널링 파일시스템(Journaling File Systems), 네트워크 파일시스템(Network File Systems), 특수 목적 파일시스템(Special Purpose File Systems), 의사파일시스템(Pseudo File System), 분산 파일시스템(Distributed File System), 플래시 파일시스템(Flash File System or Memory File System) 등을 꼽을 수 있다.
혹자는 디스크 파일시스템을 디스크 기반의 파일시스템이라고도 한다. 거의 대부분의 하드디스크가 여기에 속하며 컴퓨터에 직간접적으로 연결할 수 있다. 디스크 파일시스템은 무수히 많은데 도스와 윈도우에서 사용되는 12, 16비트 테이블 깊이의 FAT와 32비트 테이블 깊이를 갖는 FAT32, 아미가(Amiga) 시스템에서 사용되는 FFS(Fast File System), BSD 시스템에서 사용되는 FFS, OpenVMS 파일시스템인 Files-11, 구 맥OS 시스템에서 사용된 HFS(Hierarchical File System), 신 맥OS 시스템에서 사용되는 HFS플러스(HFS+), HFSX(HFS+의 case-sensitive한 변종) 등이 있다.
로그기반의 파일시스템은 디스크 파일시스템이 갑작스러운 정전 등의 위험에 노출될 경우 데이터의 신뢰성과 무결성 등을 보완하기 위해 로그를 남기는 것이 특징이다. 저널링 파일시스템으로 진화하기 위한 과도기적 기술로, 파일시스템 레이아웃을 특정한 위치에 기록하는 방법으로 유사시 대비하는 방법으로 제안됐다. 순수 저널링은 아니지만 이후 WAFL(Write Anywhere File system Layout)에 영향을 주기도 했다.
저널링 파일시스템(Journaling File Systems)은 문자 그대로 저널링을 지원하는 파일시스템이다. 저널링의 개념은 트랜잭션을 지원하는 파일시스템을 떠올리면 간단하다. 마치 일기처럼 언제(앞으로 할 기록에 대한 작업이 발생 시) 어디서든(파일시스템의 공간 내에서) 무엇을 통해서(파일에) 기록을 남기는 것이다. 미리 구조화된 정보를 파일시스템의 로그파일에 남기고 실제 작업을 수행하며 이를 완료하면 별도 표시를 하고 다음 작업을 수행한다. 이러한 흐름을 반복하다가 정전이 되거나 전원이 꺼지면 다음 부팅시에 수행 중이었던 부분을 복구하는 것이다. 미리 정의한 크기만큼 백업을 진행하면서 작업하기 때문에 큰 부담없이 복구할 수 있는 것이 특징이다.
플래시 파일 시스템은 최근 들어 저널링 개념이 도입되면서 디스크와 어깨를 나란히 할 만큼 신뢰성을 높였다. 저널링 파일시스템으로는 리눅스의 ext3 파일시스템(ext2 파일시스템에 저널링이 추가됐다)과 JFS, ReiserFS, Reiser4, XFS, OS/2의 JFS, AIX의 JFS, 윈도우 NT의 NTFS(리눅스에서는 현재 NTFS에 대한 읽기를 지원한다), 맥OS의 HFS+(저널링은 맥OS X 10.2.2.에서 추가됐다), 아이릭스의 XFS, 솔라리스의 UFS Logging, VxFS(베리타스 소프트웨어의 써드파티), HP-UX의 VxFS(HP 시스템의 JFS로 알려져 있으나 IBM의 JFS와는 다르다), BFS의 BeOS 파일시스템, WAFL 파일시스템 등이 있다.
네트워크 파일시스템(Network File Systems)이란 것도 있다. 여러 대의 컴퓨터에 의해 잠재적으로 동시에 파일이 액세스되는 파일시스템이다. AFS(Andrew File System), AppleShare(AppleShare File System), CIFS(SMB, Samba File System) 등이 대표적이다.
이밖에도 더 좁은 의미의 특화된 용도로 쓰이는 특수 목적의 파일시스템(Special Purpose File Systems)이 있다. 디스크 파일시스템과 네트워크 파일시스템이 아닌 파일시스템을 총칭하는 것으로 소프트웨어에 의해 파일이 동적으로 배치되거나 컴퓨터 프로세스 또는 임시 파일공간으로 의도된 시스템을 포함한다. 특수 목적의 파일시스템에는 텍스트 윈도우의 acme(Plan 9, Plan 9는 9P 프로토콜), archfs(archive), CD 읽기/쓰기를 목적으로 하는 cdfs, 캐싱 목적의 cfs, DEVFS, FTP 액세스 목적의 ftpfs, swapfs(Swap File System), WinFS 등이 있다.
마지막으로 플래시 파일시스템은 낸드/노어타입의 플래시 메모리에 사용되는 파일시스템으로, JFFS(Journaling Flash File System), JFFS2, JFFS3과 YAFFS(Yet Another Flash File System), YAFFS2, 그리고 삼성전자에서 설계한 RFS(Robust File System)가 대표적이다. JFFS는 노어형 플래시 메모리에 사용되고, YAFFS와 RFS는 낸드형 플래시 메모리에 사용된다.

파일복구 프로그래밍을 위한 준비
지금부터는 가장 널리 사용되는 윈도우 운용체제용 파일복구 프로그래밍에 대해 살펴보자. 윈도우 95/98/SE/ME 등 16비트와 32비트가 혼재된 9x 계열에서 디스크를 물리적으로 접근(읽기/쓰기)할 수 있는 모듈을 DLL로 개발하려면 32비트 응응 프로그램 프로그래밍이 가능한 VC++ 6.0 또는 VC++ .NET을 이용해 실행파일을 만들어야 한다. 이 때 중요한 것은 16비트 DLL에 접근하는 32비트 DLL도 함께 개발해야 한다는 점이다.
32비트 응용 프로그램이 16비트 DLL에 직접 접근할 수 없어 Thunking이라는 통신방법을 이용하기 때문이다. 이밖에 터보 어셈블러 4.0 또는 매크로 어셈블러 6.11이라는 툴도 필요한데 이는 16비트 DLL 버전을 3.1에서 4.0으로 바꾸는데 사용한다. 커널이 안정적으로 동작하고 DLL의 무결성을 검사하기 위한 것으로, 이렇게 하지 않으면 16비트 모듈이 정상적으로 작동하지 않는다.
윈도우 9x에서 FAT에 접근하는 것은 일부 논리적 접근법만 특별할 뿐 크게 어렵지 않다. 문제는 NTFS, ext3, HFS+ 등 윈도우 98에서 지원하지 않는 파일시스템을 구현하는 것인데, 이는 디바이스 드라이버로 구현하는 방법도 있으나 해당 파일시스템에 대한 이해나 테스트없이 바로 디바이스 차원으로 넘어가는 것은 바람직하지 않다. 대신 직접 물리적으로 디스크를 읽어들인 뒤 파티션 정보에 따라 해당 드라이브로 접근해 파일시스템 레이아웃에 따라 섹터를 읽어 처리하면 탐색기와 같은 인터페이스의 프로그램을 제작할 수 있다.
현재 널리 쓰이고 있는 윈도우 XP는 어떨까. 흔히 윈도우 NT와 2000, XP, 2003 버전을 통칭하는 것이 바로 윈도우 NT다. 윈도우 NT는 DeviceIOControl()이라는 윈도우 API를 이용해 물리디스크를 열고 해당 디스크로 접근해 원하는 섹터를 읽기/쓰기한다. 윈도우 9x와 달리 관리자 권한만 있으면 간단하게 구현할 수 있도록 설계돼 있다.
윈도우 NT에서는 파일시스템별로 전용 코드가 필요없다. 즉 물리디스크를 열어 디스크 차원에서 섹터에 액세스하거나 논리 드라이브를 열어 드라이브 차원에서 액세스하면 된다. 다만 파일시스템 레이아웃에 대한 모든 정보를 알고 있어야 실제로 FAT 파일시스템과 NTFS를 읽어들일 수 있다(이 부분은 다음 호에 자세하게 다룰 것이다). 이밖에 ext3, HFS+, iso9660, joliet, udf 등의 파일시스템 역시 디스크나 메모리에 사용할 수 있다. 물리적인 접근이 추가로 필요할 뿐이다.
지금까지 파일복구 프로그래밍의 기본이 될만한 제작원리에 대해 살펴봤다. 다음 호에서는 FAT와 NTFS 내부구조에 대해 알아보고 실제 소프트웨어를 구현해 본다.

출처 : 마이크로스프트웨어
Posted by skensita