Ext4文件系统删除文件恢复:分区读取异常问题求助
问题分析与解决方案
问题1:os.stat获取分区大小为0的原因与解决
/dev下的块设备文件是特殊字符设备,os.stat()返回的st_size不会反映实际分区大小,而是固定为0。需要通过系统调用ioctl获取设备的真实容量。
解决方法:用fcntl获取分区实际大小
通过BLKGETSIZE64这个ioctl命令可以直接获取设备的字节数:
import fcntl import struct def get_partition_size(partition_path): with open(partition_path, 'rb') as f: # BLKGETSIZE64 命令码,用于获取设备总字节数 size_bytes = struct.unpack('Q', fcntl.ioctl(f, 0x80081272, struct.pack('Q', 0)))[0] return size_bytes
问题2:os.walk遍历块设备无输出的原因
/dev/nvme0n1p6是块设备文件,并非挂载后的文件系统目录,os.walk只能遍历文件系统的目录结构,无法直接扫描块设备。即使挂载了分区,已删除文件的目录项已被标记为删除或覆盖,常规文件系统遍历也无法发现它们。
正确实现ext4已删除文件定位与数据访问
要恢复ext4的已删除文件,需要直接解析分区的文件系统结构,步骤如下:
1. 获取ext4实际块大小
ext4的块大小不一定是4096字节,需从文件系统超级块读取真实值:
def get_ext4_block_size(partition_path): SUPERBLOCK_OFFSET = 1024 # ext4超级块默认在1024字节偏移处 with open(partition_path, 'rb') as f: f.seek(SUPERBLOCK_OFFSET) superblock = f.read(1024) # 读取s_log_block_size字段(偏移0x18,4字节小端),计算实际块大小 s_log_block_size = struct.unpack('<I', superblock[0x18:0x1C])[0] block_size = 1024 << s_log_block_size return block_size
2. 查找已删除的目录项
ext4删除文件时,会将对应目录项中的inode编号设为0。我们可以遍历每个块,查找inode为0的目录项并解析文件名:
import os def list_deleted_files(partition_path): deleted_files = [] block_size = get_ext4_block_size(partition_path) partition_size = get_partition_size(partition_path) num_blocks = partition_size // block_size with open(partition_path, 'rb') as f: for block_num in range(num_blocks): f.seek(block_num * block_size) block_data = f.read(block_size) offset = 0 # 遍历块内的所有目录项 while offset + 8 <= len(block_data): # 目录项最小长度为8字节 inode = struct.unpack('<I', block_data[offset:offset+4])[0] rec_len = struct.unpack('<H', block_data[offset+4:offset+6])[0] name_len = block_data[offset+6] # 已删除文件的目录项特征:inode为0且文件名长度有效 if inode == 0 and rec_len > 0 and name_len > 0: name = block_data[offset+8:offset+8+name_len].decode('utf-8', errors='replace') if name: deleted_files.append(name) offset += rec_len # 防止无效的rec_len导致死循环 if offset >= block_size: break return deleted_files # 运行需要root权限 if __name__ == '__main__': partition_path = '/dev/nvme0n1p6' deleted_files = list_deleted_files(partition_path) print("已找到的删除文件:") for name in deleted_files: print(name)
3. 访问已删除文件的数据(进阶)
已删除文件的数据能否恢复取决于数据块是否被覆盖:
- 如果inode未被复用:读取inode结构(inode通常位于块组的inode表中),解析其中的直接/间接块指针,然后读取对应块的数据。
- 如果inode已被复用:只能通过文件签名(如图片的
FF D8 FF、文档的特定头)在分区中搜索原始数据。
注意:
- 必须以root权限运行脚本,否则无法访问块设备。
- 立即停止向目标分区写入数据,避免已删除文件的块被新数据覆盖。
内容的提问来源于stack exchange,提问作者Loopinfility
相关产品推荐
相关产品推荐

