#c #windows #winapi #filesystems #fragmentation
#c #Windows #winapi #файловые системы #Фрагментация
Вопрос:
Я пытаюсь следовать этому руководству: дефрагментация файлов.
Я вызываю DeviceIoControl()
с FSCTL_GET_VOLUME_BITMAP
помощью дескриптора C:
тома и получаю правильный ответ.
Затем я успешно открываю дескриптор другого файла (я пробовал файлы от 10 КБ до нескольких МБ), затем я вызываю DeviceIoControl()
with FSCTL_GET_RETRIEVAL_POINTERS
, и он завершается успешно без последней ошибки или сбоя, но RETRIEVAL_POINTERS_BUFFER
не заполняется.
Я также пытался вызвать его с C:
помощью дескриптора тома, но он продолжает возвращаться ERROR_HANDLE_EOF
даже после попытки установить OVERLAPPED
смещение равным 0 и установить указатель на файл SetFilePointer()
равным 0 относительно начала файла.
BOOL dic(HANDLE dev, DWORD code, LPVOID in, DWORD ins, LPVOID out, LPDWORD outs)
{
HANDLE h = GetProcessHeap();
DWORD s = 1000;
DWORD r = 0;
out = HeapAlloc(h,HEAP_ZERO_MEMORY,s);
while (!DeviceIoControl(dev, code, in, ins, out, s, amp;r, 0))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
{
s *= 10;
LPVOID t = HeapReAlloc(h, HEAP_ZERO_MEMORY, out, s);
if(!t){
HeapFree(h, 0, out);
return 0;
}
out = t;
}
else
{
HeapFree(h, 0, out);
printf("dic unk: %dn", GetLastError());
return 0;
}
}
*outs = s;
return 1;
}
BOOL getvolptr(HANDLE volh, PRETRIEVAL_POINTERS_BUFFER rpb, LPDWORD rpbs)
{
STARTING_VCN_INPUT_BUFFER vcn = { 0 };
return dic(volh, FSCTL_GET_RETRIEVAL_POINTERS, amp;vcn, sizeof(vcn), rpb, rpbs);
}
RETRIEVAL_POINTERS_BUFFER rpb = { 0 };
DWORD rpbs = 0;
ULONGLONG cluster_cnt=0;
HANDLE fi = openfile("C:\Windows\System32\Kernel32.dll");
if (INVALID_HANDLE_VALUE == fi)
{
printf("failed to open file! (%d)n", GetLastError());
getchar();
}
r = getvolptr(fi, amp;rpb, amp;rpbs);
if (!r)
{
printf("failed to get vol ptrs! (%d)n", GetLastError());
getchar();
}
for (int i = 0; i < rpb.ExtentCount; i)
{
cluster_cnt = (ULONGLONG)(rpb.Extents[i].NextVcn.QuadPart) - (ULONGLONG)(rpb.StartingVcn.QuadPart);
printf("%d) size: %llu clusters (0x6X)n", i, cluster_cnt, rpb.Extents[i].Lcn.QuadPart);
}
Ответ №1:
Вы не проверяете первый HeapAlloc()
на сбой. И HeapFree()
может стереть последний код ошибки DeviceIoControl()
перед его печатью.
Но что еще более важно, вы неправильно передаете out
данные обратно вызывающей стороне, поэтому происходит утечка выделенной памяти, и вызывающая сторона получает мусор для вывода.
Поскольку вызывающий объект передает свои собственные RETRIEVAL_POINTERS_BUFFER
данные для получения данных, вам необходимо скопировать содержимое выделенной памяти в этот буфер, например:
BOOL dic(HANDLE dev, DWORD code, LPVOID in, DWORD ins, LPVOID out, LPDWORD outs)
{
if (!in || !out || !outs)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*outs = 0;
HANDLE h = GetProcessHeap();
DWORD s = 1000;
LPVOID buf = HeapAlloc(h, HEAP_ZERO_MEMORY, s);
if (!buf)
return FALSE;
DWORD r = 0;
while (!DeviceIoControl(dev, code, in, ins, buf, s, amp;r, 0))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
{
s *= 10;
LPVOID t = HeapReAlloc(h, HEAP_ZERO_MEMORY, buf, s);
if (!t)
{
HeapFree(h, 0, buf);
return FALSE;
}
buf = t;
}
else
{
printf("dic unk: %un", GetLastError());
HeapFree(h, 0, buf);
return FALSE;
}
}
if (s > *outs)
{
HeapFree(h, 0, buf);
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
CopyMemory(out, buf, s);
*outs = s;
HeapFree(h, 0, buf);
return TRUE;
}
BOOL getvolptr(HANDLE volh, PRETRIEVAL_POINTERS_BUFFER rpb, LPDWORD rpbs)
{
STARTING_VCN_INPUT_BUFFER vcn = { 0 };
return dic(volh, FSCTL_GET_RETRIEVAL_POINTERS, amp;vcn, sizeof(vcn), rpb, rpbs);
}
HANDLE fi = openfile("C:\Windows\System32\Kernel32.dll");
if (INVALID_HANDLE_VALUE == fi)
{
printf("failed to open file! (%u)n", GetLastError());
getchar();
}
else
{
RETRIEVAL_POINTERS_BUFFER rpb = { 0 };
DWORD rpbs = sizeof(rpb);
if (!getvolptr(fi, amp;rpb, amp;rpbs))
{
printf("failed to get vol ptrs! (%u)n", GetLastError());
getchar();
}
else
{
ULONGLONG cluster_cnt = 0;
for (int i = 0; i < rpb.ExtentCount; i)
{
cluster_cnt = (ULONGLONG)(rpb.Extents[i].NextVcn.QuadPart) - (ULONGLONG)(rpb.StartingVcn.QuadPart);
printf("%d) size: %llu clusters (0x6X)n", i, cluster_cnt, rpb.Extents[i].Lcn.QuadPart);
}
}
closefile(fi);
}
В качестве альтернативы, вы можете вернуть указатель на выделенную память вызывающей стороне, и вызывающей стороне придется освободить память после завершения ее использования, например:
BOOL dic(HANDLE dev, DWORD code, LPVOID in, DWORD ins, LPVOID* out, LPDWORD outs)
{
if (!in || !out || !outs)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*out = NULL;
*outs = 0;
HANDLE h = GetProcessHeap();
DWORD s = 1000;
LPVOID buf = HeapAlloc(h, HEAP_ZERO_MEMORY, s);
if (!buf)
return FALSE;
DWORD r = 0;
while (!DeviceIoControl(dev, code, in, ins, buf, s, amp;r, 0))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
{
s *= 10;
LPVOID t = HeapReAlloc(h, HEAP_ZERO_MEMORY, buf, s);
if (!t)
{
HeapFree(h, 0, buf);
return FALSE;
}
buf = t;
}
else
{
printf("dic unk: %un", GetLastError());
HeapFree(h, 0, buf);
return FALSE;
}
}
*out = buf;
*outs = s;
return TRUE;
}
BOOL getvolptr(HANDLE volh, PRETRIEVAL_POINTERS_BUFFER* rpb, LPDWORD rpbs)
{
STARTING_VCN_INPUT_BUFFER vcn = { 0 };
return dic(volh, FSCTL_GET_RETRIEVAL_POINTERS, amp;vcn, sizeof(vcn), (void**)rpb, rpbs);
}
HANDLE fi = openfile("C:\Windows\System32\Kernel32.dll");
if (INVALID_HANDLE_VALUE == fi)
{
printf("failed to open file! (%u)n", GetLastError());
getchar();
}
else
{
PRETRIEVAL_POINTERS_BUFFER rpb = NULL;
DWORD rpbs = 0;
if (!getvolptr(fi, amp;rpb, amp;rpbs))
{
printf("failed to get vol ptrs! (%u)n", GetLastError());
getchar();
}
else
{
ULONGLONG cluster_cnt = 0;
for (int i = 0; i < rpb->ExtentCount; i)
{
cluster_cnt = (ULONGLONG)(rpb->Extents[i].NextVcn.QuadPart) - (ULONGLONG)(rpb->StartingVcn.QuadPart);
printf("%d) size: %llu clusters (0x6X)n", i, cluster_cnt, rpb->Extents[i].Lcn.QuadPart);
}
HeapFree(GetProcessHeap(), 0, rpb);
}
closefile(fi);
}