2025_02 실수로 덮어쓴 파일 복구


실수

## 원래 의도
# virsh dumpxml engine >  engine.ovirt1.xml

## 잘못 실행된 명령
# virsh dumpxml engine >  engine.ovirt1.qcow2

## 원래 파일 용량 약 30GB
# ls -alht engine.ovirt1* 
-rw-r--r--. 1 qemu qemu 6.8K 2025-02-26 Wed 05:06:48 engine.ovirt1.qcow2
-rw-r--r--. 1 root root 9.6K 2025-02-26 Wed 05:03:52 engine.ovirt1.xml


QnA ext4 파일시스템 덮어쓰기 방식 by (Claude 3 Sonet)

Q

CentOS8 이고 ext4 파일 시스템이야
30GB 짜리 engine.ovirt1.qcow2 가 있어
내가 잘못해서 echo XML > engine.ovirt1.qcow2 을 했어
이 때, 새로운 inode 에 내용을 작성하고 링크만 바꾸는 식으로 파일을 관리해?
아니면 engine.ovirt1.qcow2 의 시작 섹터에 내용을 바꿔버려?

A

파일 시스템이 ext4이고 echo XML > engine.ovirt1.qcow2 명령을 실행했을 때 일어나는 일은 두 번째 경우입니다. 이 명령은 기존 파일의 시작 부분에 새 내용을 덮어씁니다.
이 명령이 실행되면 다음과 같은 일이 발생합니다:

파일 시스템은 새로운 inode를 생성하지 않습니다.
기존 engine.ovirt1.qcow2 파일의 동일한 inode를 유지합니다.
파일의 크기를 XML 문자열 길이로 줄이고(truncate), 기존 파일의 처음 몇 바이트를 XML 내용으로 덮어씁니다.
원본 파일의 나머지 데이터는 디스크에 물리적으로 여전히 존재할 수 있지만, 논리적으로는 더 이상 파일의 일부로 간주되지 않습니다.

이것이 데이터 복구가 가능할 수도 있는 이유입니다. 원본 데이터의 대부분이 물리적으로 디스크에 여전히 존재하지만, 파일 시스템에서는 그 데이터를 접근할 수 없게 됩니다. 파일의 크기가 줄어들었기 때문에, 파일 시스템은 크기를 넘어선 데이터를 "없는" 것으로 취급합니다.
복구의 핵심은 파일 시스템이 아닌 디스크 섹터 레벨에서 직접 데이터에 접근하는 방법을 찾는 것입니다.


파일 섹터 확인

Q

특정 파일의 시작 블럭번호와 끝 블럭번호를 아는 방법

A

filefrag -v 파일경로
# 이 명령어는 파일의 각 조각(extent)이 어디에 위치하는지 자세히 보여줍니다.

hdparm --fibmap 파일경로
# 이 명령어는 파일의 실제 물리적 블록 위치를 보여줍니다.

Run

# filefrag -v engine.ovirt1.qcow2
Filesystem type is: 58465342
File size of engine.ovirt1.qcow2 is 6941 (2 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..       1:   56952621..  56952622:      2:             last,eof
engine.ovirt1.qcow2: 1 extent found

# hdparm --fibmap engine.ovirt1.qcow2
engine.ovirt1.qcow2:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0  455620968  455620983         16
잘못 덮혀진 파일이거든
이걸 시작부터 40GB 영역을 dd로 떠서 /mnt/usb2/sectors.bin 에 옮겨주고
파일시스템의 흔적을 찾아줘


섹터 백업

Q

이 파일의 시작부터 40GB 영역을 dd로 떠서 /mnt/usb2/sectors.bin 에 옮겨주고 파일시스템의 흔적을 찾아줘

A

네, 파일의 물리적 위치 정보를 확인했고 이제 해당 영역을 dd로 백업한 후 복구 과정을 진행해 보겠습니다.

# 40GB 복사 (hdparm에서 찾은 시작 LBA 사용)
dd if=/dev/sdX of=/mnt/usb2/sectors.bin bs=512 skip=455620968 count=83886080
# (40GB = 83886080 * 512 바이트 섹터)

Q

파일시스템과 마운트 정보는 다음과 같아. input을 수정해줘

# lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0   931G  0 disk
├─sda1        8:1    0     1G  0 part /boot
└─sda2        8:2    0   930G  0 part
  ├─cl-root 253:0    0 866.5G  0 lvm  /
  └─cl-home 253:2    0    32G  0 lvm  /home
sdb           8:16   1   239G  0 disk
└─sdb1        8:17   1   239G  0 part /mnt/usb2

# cat /etc/fstab
/dev/mapper/cl-root     /                       xfs     defaults        0 0
/dev/mapper/cl-home     /home                   xfs     defaults        0 0

A

dd if=/dev/mapper/cl-root of=/mnt/usb2/sectors.bin bs=512 skip=455620968 count=83886080 status=progress

QFI 시그니처 찾기

A

이제 이 백업 파일에서 qcow2 파일의 흔적을 찾아보겠습니다:

# qcow2 헤더 찾기 (QFI 시그니처)
hexdump -C /mnt/usb2/sectors.bin | head -20

# 또는 바이너리 검색
grep -a -b "QFI\xfb" /mnt/usb2/sectors.bin

RUN

QFI 시그니처 찾기 실패


XFS 시그니처 찾기

Q

xfs 파일 시스템의 흔적을 찾아보려는데

A

# sectors.bin에서 XFSB 패턴 재확인
hexdump -C /mnt/usb2/sectors.bin | grep -A 4 "58 46 53 42"

Run

# hexdump -C /mnt/usb2/sectors.bin | grep -A 4 "58 46 53 42"
02f20000  58 46 53 42 00 00 10 00  00 00 00 00 00 1f ff 00  |XFSB............|
02f20010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
02f20020  44 a6 a6 13 4e 21 47 8b  a9 09 ab 65 3c 9d 39 df  |D...N!G....e<.9.|
02f20030  00 00 00 00 00 10 00 04  00 00 00 00 00 00 00 40  |...............@|


XFS 파일시스템 추출

Q

이걸 바탕으로 xfs 파일시스템을 추출할 수 있어?

A

# sectors.bin에서 발견된 위치부터 XFS 파일시스템 추출
dd if=/mnt/usb2/sectors.bin of=/mnt/usb2/xfs_extracted.img bs=512 skip=96768

# 추출된 이미지 마운트해보기
mkdir /mnt/xfs_test
mount -t xfs -o loop,ro /mnt/usb2/xfs_extracted.img /mnt/xfs_test