微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Windows 上以编程方式对文件进行碎片整理

如何解决在 Windows 上以编程方式对文件进行碎片整理

我正在尝试学习本教程:Defragmenting Files

我在 DeviceIoControl() 卷的句柄上使用 FSCTL_GET_VOLUME_BITMAP 调用 C:,我得到了正确的响应。

然后我成功打开另一个文件的句柄(我尝试了从 10KB 到几 MB 的文件),然后我用 DeviceIoControl() 调用 FSCTL_GET_RETRIEVAL_POINTERS,它成功了,没有最后的错误或失败的结果,但 RETRIEVAL_POINTERS_BUFFER 未填充。

我还尝试在 C: 卷句柄上调用它,但即使在尝试将 ERROR_HANDLE_EOF 偏移量设置为 0 并将文件指针设置为 {{ 1}} 到 0 相对于文件的开头。

OVERLAPPED

解决方法

您没有检查第一个 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,&r,0))
    {
        if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
        {
            s *= 10;
            LPVOID t = HeapReAlloc(h,s);
            if (!t)
            {
                HeapFree(h,buf);
                return FALSE;
            }
            buf = t;
        }
        else
        {
            printf("dic unk: %u\n",GetLastError());
            HeapFree(h,buf);
            return FALSE;
        }
    }

    if (s > *outs)
    {
        HeapFree(h,buf);
        SetLastError(ERROR_INSUFFICIENT_BUFFER);
        return FALSE; 
    }

    CopyMemory(out,s);
    *outs = s;

    HeapFree(h,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,&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,&rpb,&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 (0x%016X)\n",i,cluster_cnt,rpb.Extents[i].Lcn.QuadPart);
        }
    }

    closefile(fi);
}

或者,您可以将指向已分配内存的指针返回给调用者,调用者在使用完内存后必须释放内存,例如:

BOOL dic(HANDLE dev,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,buf);
            return FALSE;
        }
    }

    *out = buf;
    *outs = s;

    return TRUE;
}

BOOL getvolptr(HANDLE volh,PRETRIEVAL_POINTERS_BUFFER* rpb,(void**)rpb,GetLastError());
    getchar();
}
else
{
    PRETRIEVAL_POINTERS_BUFFER rpb = NULL;
    DWORD rpbs = 0;

    if (!getvolptr(fi,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 (0x%016X)\n",rpb->Extents[i].Lcn.QuadPart);
        }

        HeapFree(GetProcessHeap(),rpb);
    }

    closefile(fi);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。