win7下清除带有稀疏块的文件的稀疏属性时导致文件损坏
众所周之,使用下面的代码可以设置文件为稀疏文件。
::DeviceIoControl(file, FSCTL_SET_SPARSE, 0, 0, 0, 0, &temp, 0);
使用这段代码清除稀疏文件标志(vista及以后才有效)
DWORD temp;
FILE_SET_SPARSE_BUFFER b;
b.SetSparse = FALSE;
::DeviceIoControl(file, FSCTL_SET_SPARSE, &b, sizeof(b), 0, 0, &temp, 0));
但,在使用libtorrent 1.6.0的代码时遇到问题,对于一个较大文件的下载时,可能有一块内存数据未写入
到物理文件中时就清除了SPARSE属性,然后下载完成的文件被损坏。以写模式访问会返回错误码5,
拷贝该文件到一定进度会失败,删除也不能删除。
解决办法是,将该文件重新设置为稀疏文件。
所以,在清除稀疏标志之前,必须判断是否还有hole(稀疏的部分)。
bool HasSparseRegion(HANDLE file)
{
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(file, &fileSize))
{
return true;
}
FILE_ALLOCATED_RANGE_BUFFER in;
in.FileOffset.QuadPart = 0;
in.Length.QuadPart = fileSize.QuadPart;
FILE_ALLOCATED_RANGE_BUFFER out[2];
DWORD processedSize = 0;
BOOL ret = DeviceIoControl(file,
FSCTL_QUERY_ALLOCATED_RANGES,
(void*)&in,
sizeof(in),
out,
sizeof(out),
&processedSize,
NULL);
if (ret == FALSE)
{
return true;
}
// if we only have a single range in the file, we're not sparse
return processedSize != sizeof(FILE_ALLOCATED_RANGE_BUFFER);
}