Files

使用 debugfs cat 讀取過時的文件數據

  • June 2, 2021

我正在嘗試使用文件的 inode 讀取文件的內容。

這工作正常:

echo "First line" > data.txt
sync
sudo debugfs -R "cat <$(stat -c %i data.txt)>" /dev/sda3

debugfs 告訴我文件內容是“第一行”。這部分命令獲取 data.txt 的 inode 號:$(stat -c %i data.txt)

添加第二行時出現問題:

echo "Second line" >> data.txt
sync
sudo debugfs -R "cat <$(stat -c %i data.txt)>" /dev/sda3

我仍然只能從調試文件中獲得“第一行”。sync在添加更多行、再次執行或幾天后重試後,這不會改變。

為什麼 debugfs 不顯示文件內容的其餘部分?我是否以錯誤的方式使用 debugfs?

我可以使用其他文件可靠地重現此行為。


我注意到當用 覆蓋現有文件內容時echo "New content" > data.txt,debugfs 確實顯示了新內容。但是,如上所述,添加第二行將只顯示第一行。


我在 Arch Linux 5.12.3 上使用 debugfs 1.46.2。文件系統/dev/sda3是ext4。呼叫debugfs -R "stat ..."會產生以下結果,這對我來說似乎並不可疑:

Inode: 16515371   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 3923658711    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 34
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x60b639e5:71315fa0 -- Tue Jun  1 15:45:09 2021
atime: 0x60b63988:b7c456cc -- Tue Jun  1 15:43:36 2021
mtime: 0x60b639e5:71315fa0 -- Tue Jun  1 15:45:09 2021
crtime: 0x60b63988:b7c456cc -- Tue Jun  1 15:43:36 2021
Size of extra inode fields: 32
Inode checksum: 0xbfa4390e
EXTENTS:
(0):66095479

這是由於記憶體。你至少有兩個選擇。

  1. 使用-D標誌:
-D 使 debugfs 使用 Direct I/O 打開設備,繞過緩衝區
fer記憶體。請注意,某些 Linux 設備,尤其是設備映射器
本文不支持 Direct I/O。
  1. 丟棄緩衝區記憶體:
迴聲 1 | sudo tee /proc/sys/vm/drop_caches

參見例如:


如果您不傳遞-D標誌,您仍然可以通過將結果傳遞到例如xxd

sudo debugfs -R "cat <$(stat --printf %i data.txt)>" /dev/sda3 | xxd -a -c 32

您將看到*cat*’ed 文件充滿了零字節,有時還有數據(如果已寫入足夠多的數據)。

例如,之後echo A >data.txt

00000000: 410a                A.

然後之後for i in {1..7}; do echo A >>data.txt; done

00000000: 410a 0000 0000 0000 0000 0000 0000 0000  A...............

您還可以使用以下方式進行監控:

用法:sudo ./script file_to_monitor

watch它使用一個腳本啟動,該腳本除了列印文件的結果外,還列印awk設備的統計資訊。/sys/block``cat <inode>

#!/bin/sh

if [ "$1" = "-h" ]; then
   printf '%s FILE\n' "$0"
   exit 1
fi

file="$1"
inode=$(stat --printf %i "$file")
dev_path="$(df -P -- "$file" | awk 'END{print $1}')"
dev_name="$(lsblk -no NAME  "$dev_path")"
dev_core="$(lsblk -no PKNAME  "$dev_path")"

if [ "$dev_core" = "loop" ]; then
   fn_stat=/sys/block/$dev_name/stat
else
   fn_stat=/sys/block/$dev_core/$dev_name/stat
fi

printf 'File : %s\n' "$file"
printf 'Inode: %s\n' "$inode"
printf 'Stat : %s\n' "$fn_stat"
printf 'Dev  : %s\n' "$dev_path"

printf "Continue? [yN] " >&2
read -r ans
if ! [ "$ans" = "y" ] && ! [ "$ans" = "Y" ]; then
   exit
fi

watch -n 0.2 'awk \
   -v inode="'$inode'" \
   -v dev_path="'$dev_path'" \
"{
   rs = \$3 * 512
   rsk = rs / 1024
   rsm = rsk / 1024
   ws = \$7 * 512
   wsk = ws / 1024
   wsm = wsk / 1024

   printf \" 1: Reads  Completed   : %9d\n\", \$1
   printf \" 2: Reads  Merged      : %9d\n\", \$2
   printf \" 3: Read   Sectors     : %9d %6d MiB %9d KiB %d bytes\n\",
   \$3, rsm, rsk, rs
   printf \" 4: Read   ms          : %9d\n\", \$4
   printf \" 5: Writes Completed   : %9d\n\", \$5
   printf \" 6: Writes Merged      : %9d\n\", \$6
   printf \" 7: Write  Sectors     : %9d %6d MiB %9d KiB %d bytes\n\",
   \$7, wsm, wsk, rs
   printf \" 8: Write  ms          : %9d\n\", \$8
   printf \" 9: I/Os   in progress : %9d\n\", \$9
   printf \"10: I/O    ms          : %9d\n\", \$10
   printf \"11: I/O    ms weighted : %9d\n\", \$11

   printf \"\n\nFILE <%d> %s:\n\", inode, dev_path

   system(\"sudo debugfs -R '\''cat <\"inode\">'\'' \"dev_path\" | xxd -a -c 32\")
}
"' "$fn_stat"

引用自:https://unix.stackexchange.com/questions/652338