【问题标题】:Defragmenting File Programatically On Windows在 Windows 上以编程方式对文件进行碎片整理
【发布时间】:2021-04-29 16:58:45
【问题描述】:

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

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

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

我也尝试在C: 卷句柄上调用它,但即使尝试将OVERLAPPED 偏移量设置为0,并将带有SetFilePointer() 的文件指针设置为相对于文件的开头。

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

【问题讨论】:

    标签: c windows winapi filesystems fragmentation


    【解决方案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, &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: %u\n", 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, &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, 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, &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: %u\n", 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, &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, &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);
            }
    
            HeapFree(GetProcessHeap(), 0, rpb);
        }
    
        closefile(fi);
    }
    

    【讨论】:

      猜你喜欢
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 2011-02-01
      • 2018-01-03
      • 1970-01-01
      • 2016-03-12
      • 2012-05-13
      • 2019-02-25
      相关资源
      最近更新 更多