강좌
클라우드/리눅스에 관한 강좌입니다.
자격증 분류

리눅스마스터1급 : 리눅스에서 삭제된 파일 복구하기

작성자 정보

  • 관리자 작성
  • 작성일

컨텐츠 정보

본문

리눅스마스터1: 리눅스에서 삭제된 파일 복구하기





 

 

지워진 파일 복

 

무엇보다 영향받은 파티션을 최대한 빨리 아무 것도 하지 않은 채로 언마운트시키는 것이 매우 중요하다.

 

 

 

만약 사고 후에 이 파티션에 파일을 카피했다면 이 방법이 성공할 가능성은 매우 낮아진다.

 

 

 

복구 방법은 리눅스 시스템의 ext4 파일 시스템을 기준으로 한다.

 

 

 

 

우선 지워진 파일이 있는 파티션을 언마운트한다.

 

 

 

이 파티션을 /dev/hdx1이라 하겠다.

 

 

 

 

 

 

 

 

# umount /dev/hdx1

 

 

 

 

 

그리고 /dev/hdx1의 크기를 블록 단위로 체크한다.

 

 

 

 

 

 

 

 

# fdisk -l /dev/hdx

 

 

 

 

 

 

 

안전을 기하기 위해 /dev/hdx1를 다른 파티션으로 복사하여 작업한다.

 

 

 

따라서 /dev/hdx1와 같은 크기의 또 다른 파티션이 필요하다.

 

 

 

/dev/hdy에 비어있는 하드 드라이브를 가지고 있다고 가정하자. fdisk 명령으로 /dev/hdy 디스크에 /dev/hdx1과 같은 사이즈의 파티션을 새로 만든다.

 

 

 

여기서 사이즈는 블록 단위(각 블록은 1,024kB)로 나타낸 /dev/hdx1의 사이즈이다.

 

 

 

 

 

 

 

 

# fdisk /dev/hdy

 

 

 

 

 

 

 

이제 원본 파티션의 내용을 새로운 파티션으로 복사한다.

 

 

 

 

 

 

 

 

# dd if=/dev/hdx1 of=/dev/hdy1 bs=1k

 

 

 

 

 

 

 

이 과정은 파티션의 크기에 따라 꽤 오래 걸릴 수도 있다.

 

 

 

만약 블록 사이즈 bs를 늘린다면 더 빠르게 할 수 있겠지만, 그럴 경우에는 파티션의 크기가 bs로 나누어 떨어져야 한다.

 

 

 

 

이제부터 시스템이 잘못되는 것을 방지하기 위해 원본 파티션의 복사본만을 가지고 작업할 것이다.

 

 

 

 

지워진 디렉토리의 inode를 찾기

 

지워진 디렉토리의 inode 번호들을 찾는다.

 

 

 

 

 

 

# debugfs /dev/hdy1

debugfs 1.41.12 (17-May-2010)

debugfs :

 

 

 

 

 

 

지워진 디렉토리가 원래 위치했던 곳으로 이동한다.

 

 

 

debugfs 안에서는 cd 명령으로 이동할 수 있다.

 

 

 

그리고 해당 디렉토리의 내용은 ls 명령으로 볼 수 있다.

 

 

 

 

 

 

 

 

# debugfs /dev/hdy1

debugfs 1.41.12 (17-May-2010)

debugfs : ls l

2 40555 (2) 0 0 1024 19-Nov-2013 01:53 .

2 40555 (2) 0 0 1024 19-Nov-2013 01:53 ..

11 40700 (2) 0 0 12288 19-Nov-2013 01:00 lost+found

65025 40755 (2) 0 0 1024 19-Nov-2013 01:56 grub

65027 40755 (2) 0 0 1024 19-Nov-2013 01:37 efi

12 100644 (1) 0 0 166 22-Feb-2013 09:56 .vmlinuz-2.6.32-358

13 100644 (1) 0 0 2407466 22-Feb-2013 09:56 System.map-2.6.32-358

14 100644 (1) 0 0 104081 22-Feb-2013 09:56 config-2.6.32-358

15 100644 (1) 0 0 185734 22-Feb-2013 09:56 symvers-2.6.32-358.gz

16 100755 (1) 0 0 4043888 22-Feb-2013 09:56 vmlinuz-2.6.32-358

17 100644 (1) 0 0 16536638 19-Nov-2013 01:44 initramfs-2.6.32-358.img

18 100600 (1) 0 0 4263623 19-Nov-2013 02:00 initrd-2.6.32-358.kdump.img

 

debugfs:

 

 

 

 

 

각 필드의 설명

inode 번호

맨 앞 두(혹은 첫) 숫자는 inode의 종류를 의미한다.

 

 

 

2 = 문자 디바이스 4 = 디렉토리 6 = 블록 디바이스 10 = 일반 파일 12 = 심볼릭 링크 남은 네 숫자는 운영체제에서 정해지는 것이다.

 

 

 

 

숫자로 표현된 소유주

숫자로 표현된 소유 그룹

바이트로 나타낸 크기

날짜

시간

파일 이름

 

 

 

 

이제 상위 디렉토리를 디스크에 덤프하자.

 

여기서 inode는 그에 해당하는 inode 번호를 가리킨다(‘<’ ‘>’를 빼먹지 않도록 해야 한다).

 

dump는 하나의 아이노드를 파일로 출력하여 저장하는 것이다.

 

 

 

 

 

 

 

 

debugfs : dump <inode 번호> [저장될 파일명]

 

 

 

 

 

 

 

debugfs에서 빠져나온다.

 

 

 

 

 

 

 

 

debugfs : quit

 

 

 

 

 

 

 

덤프된 디렉토리의 분석

읽을 수 있는 형태로 덤프된 inode를 보자.

 

 

 

 

 

 

 

# xxd debugfs-dump | less

 

 

 

 

 

 

 

모든 엔트리는 다섯 개의 필드로 구성된다.

 

 

 

첫 두 필드는 역순으로 바이트가 배열되어 있다.

 

 

 

이는 첫 번째 바이트가 제일 낮은 자리의 수라는 것을 의미한다.

 

 

 

 

각 필드의 설명

 

 

4 바이트 Inode 번호

2 바이트 디렉토리 엔트리 길이

1 바이트 파일 이름 길이(1~255)

1 바이트 파일의 종류 0 = 알 수 없음 1 = 일반 파일 2 = 디렉토리 3 = 문자 디바이스 4 = 블록 디바이스 5 = FIFO 6 = SOCK 7 = 심볼릭 링크

파일이름(1~255)

 

 

 

 

만약 디렉토리의 어떤 엔트리가 지워져야 한다면, 지워져야 할 엔트리 바로 앞에 있는 엔트리의 두 번째 필드가 지워져야 할 엔트리의 두 번째 필드 값만큼 증가된다.

 

 

 

만약, 파일 이름이 더 짧은 것으로 바뀌면 세 번째 필드값이 줄어든다.

 

 

 

맨 첫 엔트리는 ‘.’으로 표현되는 그 디렉토리 자신이다.

 

 

 

 

다음과 같은 디렉토리 엔트리들을 가지고 있다고 하자.

 

 

c1 02 0e 00 40 00 05 01 ‘u’ ‘t’ ‘i’ ‘l’ ‘s’

 

 

 

그러면 inode16진수로 e02c1이 될 것이고, 이는 10진수로 918209이다.

 

 

 

다음 엔트리는 64바이트(16진수로 40) 뒤에 위치하게 될 것이고, 파일 이름이 5(“utils”)로 구성된 것을 알 수 있다.

 

 

 

그리고 파일의 종류는 일반 파일임을 알 수 있다.

 

 

 

 

이제 디렉토리의 inode 번호를 10진수로 다시 계산하자.

 

 

 

지워진 inode들을 원 위치시키기

 

 

지워진 inode들의 목록을 얻는다.

 

 

 

 

 

 

 

 

# echo lsdel | debugfs /dev/hdy1 > lsdel.out

 

 

 

 

 

 

문제는 여기서 debugfs가 크기가 0인 파일(아마도 /etc 디렉토리에서 이러한 것들을 볼 수 있을 것이다)inode 번호를 주지 않는다.

 

 

 

“lsdel.out”을 문서 편집기로 불러온다.

 

 

 

inode들의 목록은 시간 순서대로 정렬되어 있을 것이다.

 

 

 

rm -rf를 언제 했는지를 기억해 보자. 아마도 그것은 마지막으로 지운 것이었을 것이고, 목록이 시간 순으로 정렬되어 있기 때문에 그것들은 목록의 맨 마지막에 있을 것이다.

 

 

 

필요하지 않은 것들을 모두 지우고, 이를 “lsdel.out-selected”로 저장한다.

 

 

 

 

이제 inode를 제외한 모든 정보를 지운다.

 

 

 

 

 

 

 

 

# cut b 1-8 lsdel.out-selected | tr d “ ” > inodes

 

 

 

 

 

 

 

확실히 하기 위해서, 위에서 찾은 지워진 디렉토리들의 inode가 목록에 있는지 확인하자.

 

 

 

 

 

 

# grep ^inode$ indoes

 

 

 

 

 

 

 

여기서 inode는 그에 해당하는 inode 번호이다.

 

 

 

 

inode들을 활성화시키기

 

 

이제 지워진 inode들의 플래그들을 조정해야 한다.

 

 

 

“make-debugfs-input”이란 파일을 만들고, 다음 6줄을 넣어라

 

(debugfs의 버전에 따라 엔터의 개수를 조절해야 할 수 있으므로 주의한다).

 

 

 

 

 

 

 

#!/bin/sh

awk ‘{ print “mi <” $1 “>\n”\

“\n\n\n\n\n\n\n”\

“0\n”\

“1\n”\

“\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n” }’

 

 

 

 

 

 

 

이는 inode를 직접 수정할 때, 사람의 입력을 시뮬레이트할 것이다.

 

 

 

여기서는 지워진 시간을 0으로 하고, 링크 숫자를 1로 할 것이다.

 

 

 

 

이제 inode를 수정하자.

 

 

 

 

 

 

# ./make-debugfs-input < inodes | debugfs w /dev/hdy1 | tail c 40

 

 

 

 

 

 

 

만약, 모든 것이 잘 수행되었다면 위 명령은 “Triple Indirect Block [0] debugfs:”라고 하면서 끝나야 한다.

 

 

 

 

디렉토리 엔트리를 더하기

 

 

debugfs를 읽기-쓰기 모드로 시작한다.

 

 

 

 

 

 

 

 

# debugfs w /dev/hdy1

 

 

 

 

 

 

이제 지워진 디렉토리가 위치했던 곳에 디렉토리를 새로 넣어야 한다.

 

 

 

 

 

 

 

 

debugfs : link <inodes> directory_name

 

 

 

 

 

 

 

여기서 inodeinode 번호이고, directory_name은 디렉토리 이름이다.

 

 

 

 

링크를 추가한 다음, 디렉토리가 현재 디렉토리에 추가된 것을 확인할 수 있을 것이다.

 

 

 

이제 그것들의 내용을 (debugfs에서) 확인할 수 있다.

 

 

 

그러나 각 디렉토리의 크기가 0이기 때문에 이는 고쳐져야 한다.

 

 

 

그렇지 않으면 쉘에서 ls 명령으로 보았을 때, 비어있는 것으로 보일 것이다.

 

 

 

debugfs에서 빠져나온다.

 

 

 

 

 

 

 

 

debugfs : quit

 

 

 

 

 

 

 

재계산

 

 

이제 크기와 체크섬을 다시 계산하기 위해 e2fsck를 실행시킬 차례이다.

 

 

 

만약 여러분이 복구하고자 하는 파일 중 크기가 0인 파일이 하나도 없다면 아래의 내용을 실행한 뒤, 이 글의 나머지 부분은 넘어가도 된다

 

(물론 인자 y를 쓰지 않을 수도 있겠지만, 그럴 경우 모든 질문에 일일이 손으로 대답해야 하므로, 많은 시간이 걸릴 것이다).

 

 

 

 

 

 

 

# e2fsck f y /dev/hdy1 > e2fsck.out 2>&1

 

 

 

 

 

 

 

만약 크기가 0인 파일들을 되살리고 싶다면, 엔트리를 지우겠냐는 질문에 no라고 대답해야 하고, 지워도 되는 엔트리에 대해서는 yes라고 대답하면 된다.

 

 

 

아래 7줄의 내용을 “e2fsck-wrapper”란 파일에 넣는다.

 

 

 

 

 

 

 

 

#!/usr/bin/expect f

set timeout 1

spawn /sbin/e2fsck f $argv

expect {

“Clear<y>? ” { send “n” ; exp_continue }

“<y>? ” { send “y” ; exp_continue }

}

 

 

 

 

 

 

 

위 스크립트를 실행시킨다.

 

 

 

 

 

 

 

 

# ./e2fsck-wrapper /dev/hdy1 > e2fsck.out 2>&1

 

 

 

 

 

 

 

e2fsck에서 어떻게 파티션을 처리했는지 보기 위해서는, e2fsck.out의 내용을 보아라. 만약 /lost+found 디렉토리가 비어있지 않다면 몇몇 디렉토리나 파일이 정확한 위치에 나타나지 않을 수도 있다.

 

 

 

대신에 그 파일들은 /lost+found 파일에 그들의 inode를 파일 이름으로 하여 나타났을 것이다.

 

 

 

이 경우는, “..” 디렉토리 엔트리에 대한 포인터가 증가되어 그 다음 디렉토리를 가리키고 있게 된다

 

(이런 현상이 일어나는 이유는 알 수 없다. 아마 파일 시스템의 버그인 것 같다).

 

디렉토리의 연결성이 검사되는 “e2fsck.out”pass 3을 조사해 보아라. 아마도 거기서 영향받은 디렉토리를 찾을 수 있을 것이다.

 

 

 

이제 디스크를 덤프한다.

 

 

 

 

e2diranap 인자를 주고, 실행시키고, 인자없이 또 실행시킨다(이는 “..” 디렉토리 엔트리의 포인터를 변화시킬 것이다).

 

여기서 dump는 덤프된 디렉토리이다.

 

 

 

 

 

 

 

 

# e2dirana dump > dump1

# e2dirana p dump > dump2

 

 

 

 

 

두 가지 출력된 것을 비교해 보아라.

 

 

 

 

 

 

# diff dump1 dump2

 

 

 

 

 

만약 두 가지 출력이 같지 않다면 디렉토리의 어떤 파일이 없어진 것이다.

 

 

 

그러면 해당하는 파일을 /lost+found에서 찾아서 올바른 위치로 옮겨주어라. 여기서 dest는 목적 디렉토리에 대한 심볼릭 링크이다.

 

 

 

출력을 스크립트에 넣고, 동의한다면 스크립트를 실행시켜라.

 

 

 

 

 

 

 

# diff dump1 dump2 |\

tail n $[‘diff dump1 dump2 | wc l’ -1] | cut b 3- |\

sed e ‘s/^\([^ ]*\) \(.*\)$/mv lost+found\/#\1 dest\/#\1 dest\/“\2” /’ |\

sed e ‘s/!/“\\\!” /g’

 

 

 

 

 

 

이 과정을 /lost+found가 완전히 비워질 때까지 반복한다.

 

 

 

 

마지막 손질

 

 

만약 크기가 0인 파일들을 되살리기로 결정했으면 문제가 하나 남아있다.

 

 

 

이 파일들은 0이 아닌 삭제 시간과 0의 링크 숫자를 가지고 있기 때문이다.

 

 

 

이는 e2fsck가 실행될 때마다 이 파일들을 삭제하라고 물어보게 될 것이기 때문이다.

 

 

 

이 문제를 해결하는 가장 쉬운 방법은 전체 디렉토리 구조를 다른 곳(같은 파티션 상에 있어도 됨)으로 복사하고, 원본 파일들을 지운 후, 다시 원래 위치로 복사해 오는 것이다.

 

 

 

이렇게 하지 않으면, 일일이 inode를 알아내서 debugfs로 바꿔주어야 한다.

 

 

 

이제 모든 것이 잘 되었다면, 모든 것들이 삭제되기 전의 상태가 되어야 한다.

 

 

 

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,037 명
  • 현재 강좌수 :  35,810 개
  • 현재 접속자 :  112 명