หากไฟล์ถูกลบ แต่ยังคงเปิดอยู่นั่นหมายความว่าไฟล์นั้นยังคงมีอยู่ในระบบไฟล์ (มีinode ) แต่มีจำนวนฮาร์ดลิงก์เป็น 0 เนื่องจากไม่มีลิงก์ไปยังไฟล์คุณจะไม่สามารถเปิดด้วยชื่อ . ไม่มีสิ่งอำนวยความสะดวกในการเปิดไฟล์โดย inode เช่นกัน
ไม่มีวิธีค้นพบไฟล์ผ่านระบบไฟล์และโดยเฉพาะอย่างยิ่งไม่มีวิธีการค้นหาไฟล์ในไดเรกทอรีที่ไฟล์ล่าสุดอยู่ รายการไดเรกทอรีหายไป สิ่งที่เหลืออยู่ก็คือไฟล์นั่นเอง คุณสามารถไปที่ไฟล์ด้วยดีบักเกอร์ระบบไฟล์ แต่ต้องมีการอนุญาตรูทและใช้งานยากและเกิดข้อผิดพลาดได้ง่าย
ลินุกซ์ exposes /proc
เปิดไฟล์ผ่านการเชื่อมโยงสัญลักษณ์พิเศษภายใต้ ลิงก์เหล่านี้ถูกเรียก/proc/12345/fd/42
โดยที่ 12345 เป็น PID ของกระบวนการและ 42 คือหมายเลขของไฟล์ descriptorในกระบวนการนั้น โปรแกรมที่รันด้วยผู้ใช้เดียวกันกับกระบวนการนั้นสามารถเข้าถึงไฟล์ได้ (สิทธิ์ในการอ่าน / เขียน / ดำเนินการเหมือนกันกับที่คุณมีเมื่อไฟล์ถูกลบ)
ชื่อตามที่ไฟล์นั้นถูกเปิดก็ยังคงปรากฏอยู่ในเป้าหมายของการเชื่อมโยงสัญลักษณ์: ถ้าไฟล์นั้นแล้วเป้าหมายของการเชื่อมโยงคือ/var/log/apache/foo.log
/var/log/apache/foo.log (deleted)
(หากไฟล์ถูกเปลี่ยนชื่อหลังจากเปิดแล้วเป้าหมายของ symlink อาจแสดงถึงการเปลี่ยนชื่อ)
ดังนั้นคุณสามารถกู้คืนเนื้อหาของไฟล์ที่ถูกลบที่เปิดอยู่เนื่องจาก PID ของกระบวนการที่เปิดอยู่และตัวบ่งชี้ที่เปิดในลักษณะนี้:
recover_open_deleted_file () {
old_name=$(readlink "$1")
case "$old_name" in
*' (deleted)')
old_name=${old_name%' (deleted)'}
if [ -e "$old_name" ]; then
new_name=$(TMPDIR=${old_name%/*} mktemp)
echo "$oldname has been replaced, recovering content to $new_name"
else
new_name="$old_name"
fi
cat <"$1" >"$new_name";;
*) echo "File is not deleted, doing nothing";;
esac
}
recover_open_deleted_file "/proc/$pid/fd/$fd"
หากคุณรู้ ID กระบวนการ แต่ไม่ใช่ตัวบ่งชี้คุณสามารถกู้คืนไฟล์ทั้งหมดได้
for x in /proc/$pid/fd/*; do
recover_open_deleted_file "$x"
done
หากคุณไม่ทราบ ID กระบวนการคุณสามารถค้นหาระหว่างกระบวนการทั้งหมดได้:
for x in /proc/[1-9]*/fd/*; do
case $(readlink "$x") in
/var/log/apache/*) recover_open_deleted_file "$x";;
esac
done
นอกจากนี้คุณยังสามารถรับรายการนี้โดยแยกวิเคราะห์ผลลัพธ์lsof
แต่มันก็ไม่ง่ายกว่าหรือน่าเชื่อถือกว่าและพกพาได้มากกว่า
lsof / | awk '(/deleted/||/abc.txt/) {print "FD :-",$4,"| File Name:-",$9}'