书接上文,咱们这次说的7.2版本testDisk源码, github地址:(GitHub - cgsecurity/testdisk: TestDisk & PhotoRec)
其中有三个主应用程序,现在我们从qphotorec开始,并且只关注windows下的代码(项目兼容性强,支持各种平台下的功能),这是基于c++的qt窗口程序,主要功能就是实现扫描并恢复数据,功能相对单一,易于入手。
- 项目目录结构总览
项目结构总览
2. 直接定位到src下的qphotorec.cpp这个文件,这是窗口程序基类,是程序启动后执行的第一步:进行各类数据的初始化和读取分析磁盘。
窗口类构造函数-初始化数据
3.解析磁盘函数:hd_parse(我们暂时只关注核心代码,过滤掉窗口相关和次要代码)
129行 list_disk=hd_parse(NULL, verbose, testdisk_mode);
参数分析:第一个参数应该是list_disk_t类型的参数
第二个参数是verbose:主要用于控制输出的详细程度。这是一个可选的调试参数,通常是一个布尔类型的标志,用来决定函数
在运行时是否要输出额外的调试信息或详细日志。
verbo = 0: 表示静默模式,此时函数不会输出任何多余的调试信息,适用于生产环境或用户不需要了解
具体的恢复过程时。
verbo = 1: 表示详细模式,函数会输出更多的信息,方便开发者或技术人员跟踪硬盘解析和数据恢复的
流程。这在调试或诊断复杂问题时非常有用。
第三个参数是testdisk_mode: 如上代码中96行,赋值testdist_mode = TESTDISK_O_RDONLY| TESTDISK_O_READAHEAD_32K;
TESTDISK_O_RDONLY表示只读模式很好理解,TESTDISK_O_READAHEAD_32K是指启用了 32KB 的预读功能。
Read-ahead(预读) 是一种文件系统或存储优化技术。它指的是在程序请求某一段数据时,
操作系统或硬件不仅仅只读取当前请求的数据块,还会提前将后续的一些数据块也读入缓存。
这样可以减少后续的 I/O 操作次数,提高性能,尤其是在顺序读取大量数据的情况下。
32K (32KB) 表示每次的预读数据块大小。在启用该宏时,TestDisk 每次从磁盘读取数据时,
系统可能会提前读取接下来的 32KB 数据并缓存,以便后续访问时减少磁盘 I/O 操作,
提升恢复操作的速度。
进入hd_parse函数的内部( hdaccess.c文件):
char device_hd[]="\\\\.\\PhysicalDrive00";
char device_cdrom[]="\\\\.\\C:";
/* Disk 磁盘(我们主要说这快) */
for(i=0;i<64;i++)
{
disk_t *disk_car;
sprintf(device_hd,"\\\\.\\PhysicalDrive%u", i); //从0号开始遍历所有磁盘
disk_car=file_test_availability_win32(device_hd, verbose, testdisk_mode);
list_disk=insert_new_disk(list_disk,disk_car);
}
/* cdrom and digital camera CD光盘和数码相机---暂时跳过这部分*/
for(i='C';i<='Z';i++)
{
disk_t *disk_car;
device_cdrom[strlen(device_cdrom)-2]=i;
disk_car=file_test_availability_win32(device_cdrom, verbose, testdisk_mode);
if((testdisk_mode&TESTDISK_O_ALL)==TESTDISK_O_ALL)
list_disk=insert_new_disk(list_disk,disk_car);
else
list_disk=insert_new_disk_nodup(list_disk,disk_car,device_cdrom, verbose);
}
}
再跳入file_test_availability_win32(device_hd, verbose, testdisk_mode)函数(Win32.c)
三个参数当下的值:
device_hd='\\\\.\\PhysicalDrive00'
verbose=1
testdisk_mode=TESTDISK_O_RDONLY| TESTDISK_O_READAHEAD_32K
disk_t *file_test_availability_win32(const char *device, const int verbose, int testdisk_mode)
{
disk_t *disk_car=NULL;
HANDLE handle=INVALID_HANDLE_VALUE;
int mode=0;
int try_readonly=1;
if((testdisk_mode&TESTDISK_O_RDWR)==TESTDISK_O_RDWR) //testdisk_mode传参是只读,所以不会进来
{
mode = FILE_READ_DATA | FILE_WRITE_DATA;
handle = CreateFile(device,mode, (FILE_SHARE_WRITE | FILE_SHARE_READ),
NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE)
{
try_readonly=0;
}
}
if(handle==INVALID_HANDLE_VALUE && try_readonly>0) //直接跳入这儿
{
testdisk_mode&=~TESTDISK_O_RDWR;
mode = FILE_READ_DATA; //只读模式
handle = CreateFile(device,mode, (FILE_SHARE_WRITE | FILE_SHARE_READ),
NULL, OPEN_EXISTING, 0, NULL);
}
}
CreateFile:打开文件或 I/O 设备,参数比较简单,着重说几个。
OPEN_EXISTING:仅当文件或设备存在时才打开该文件或设备。
FILE_SHARE_WRITE | FILE_SHARE_READ:Windows 文件共享模式标志,都置为看可读可写,表示不锁 定设备,在本进程打开设备的时候,其他设备还能正常的进行读写操作。
函数执行成功返回设备的打开句柄,否则返回INVALID_HANDLE_VALUE
函数详情参见:CreateFileA 函数 (fileapi.h) - Win32 apps
下次和大家一起看看代码中的那些自定义结构体的作用!