GetFreeDiskSpaceEx 如何返回(看似)错误的磁盘空间量?

发布于 2024-12-28 20:52:24 字数 2405 浏览 2 评论 0原文

因此,我使用可以输出大图像(从 30MB 到 2GB 以上)的设备。在开始创建这些映像之一之前,我们通过 GetDiskFreeSpaceEx 检查是否有足够的磁盘空间。通常(在本例中)我们会写入同一网络上的共享文件夹。正在运行的磁盘空间没有用户配额。

昨晚,为了准备演示,我们开始了测试运行。在跑步过程中,我们经历了一次失败。我们需要 327391776 字节,但被告知我们只有 186580992 可用。来自 GetDiskFreeSpaceEx 的数字是:

用户可用空间:186580992

可用总可用空间:186580992

这些对应于两个(输出)参数 lpFreeBytesAvailablelpTotalNumberOfFreeBytes 中的 QuadPart 变量获取DiskFreeSpaceAvailable

该代码已使用多年,我从未见过漏报。下面是完整的函数:

long IsDiskSpaceAvailable( const char* inDirectory, 
                           const _int64& inRequestedSize, 
                           _int64& outUserFree, 
                           _int64& outTotalFree, 
                           _int64& outCalcRequest  )
{
    ULARGE_INTEGER  fba;
    ULARGE_INTEGER  tnb;
    ULARGE_INTEGER  tnfba;
    ULARGE_INTEGER  reqsize;
    string          dir;
    size_t          len;

    dir = inDirectory;
    len = strlen( inDirectory );

    outUserFree     = 0;
    outTotalFree    = 0;
    outCalcRequest  = 0;

    if( inDirectory[len-1] != '\\' )
        dir += "\\";
    
    // this is the value of inRequestSize that was passed in
    // inRequestedSize = 3273917760;
    if( GetDiskFreeSpaceEx( dir.c_str(), &fba, &tnb, &tnfba ) )
    {
        outUserFree         = fba.QuadPart;
        outTotalFree        = tnfba.QuadPart;

        // this is computed dynamically given a specific compression
        // type, but for simplicity I had hard-coded the value that was used
        float compressionRatio = 10.0;
        reqsize.QuadPart = (ULONGLONG) (inRequestedSize / compressionRatio);
        outCalcRequest   = reqsize.QuadPart;

        // this is what was triggered to cause the failure,
        // i.e., user free space was < the request size
        if( fba.QuadPart < reqsize.QuadPart )
            return( RetCode_OutOfSpace );
    }
    else
    {
        return( RetCode_Failure );
    }
    
    return( RetCode_OK );
}

因此,值 3273917760 被传递给函数,它是压缩前所需的磁盘空间总量。该函数将其除以10 的压缩比以获得所需的实际大小。

当我检查共享所在的磁盘时,它有大约 177GB 的可用空间,远远超过报告的数量。再次开始测试后,没有更改任何内容,它就起作用了。

所以我的问题是;什么会导致这样的事情?据我所知,这不是一个编程错误,并且正如我之前提到的,这段代码已经使用了很长一段时间,没有任何问题。

我检查了远程计算机的事件日志,在故障发生时没有发现任何有趣的事情。我希望有人以前见过类似的东西,提前致谢。

So I work on a device that outputs large images (anywhere from 30MB to 2GB+). Before we begin creating one of these images we check to see if there is sufficient disk space via GetDiskFreeSpaceEx. Typically (and in this case) we are writing to a shared folder on the same network. There are no user quotas on disk space at play.

Last night, in preparation for a demo, we kicked off a test run. During the run we experienced a failure. We needed 327391776 bytes and were told that we only had 186580992 available. The numbers from GetDiskFreeSpaceEx were:

User free space available: 186580992

Total free space available: 186580992

Those correspond to the QuadPart variables in the two (output) arguments lpFreeBytesAvailable and lpTotalNumberOfFreeBytes to GetDiskFreeSpaceAvailable.

This code has been in use for years now and I have never seen a false negative. Here is the complete function:

long IsDiskSpaceAvailable( const char* inDirectory, 
                           const _int64& inRequestedSize, 
                           _int64& outUserFree, 
                           _int64& outTotalFree, 
                           _int64& outCalcRequest  )
{
    ULARGE_INTEGER  fba;
    ULARGE_INTEGER  tnb;
    ULARGE_INTEGER  tnfba;
    ULARGE_INTEGER  reqsize;
    string          dir;
    size_t          len;

    dir = inDirectory;
    len = strlen( inDirectory );

    outUserFree     = 0;
    outTotalFree    = 0;
    outCalcRequest  = 0;

    if( inDirectory[len-1] != '\\' )
        dir += "\\";
    
    // this is the value of inRequestSize that was passed in
    // inRequestedSize = 3273917760;
    if( GetDiskFreeSpaceEx( dir.c_str(), &fba, &tnb, &tnfba ) )
    {
        outUserFree         = fba.QuadPart;
        outTotalFree        = tnfba.QuadPart;

        // this is computed dynamically given a specific compression
        // type, but for simplicity I had hard-coded the value that was used
        float compressionRatio = 10.0;
        reqsize.QuadPart = (ULONGLONG) (inRequestedSize / compressionRatio);
        outCalcRequest   = reqsize.QuadPart;

        // this is what was triggered to cause the failure,
        // i.e., user free space was < the request size
        if( fba.QuadPart < reqsize.QuadPart )
            return( RetCode_OutOfSpace );
    }
    else
    {
        return( RetCode_Failure );
    }
    
    return( RetCode_OK );
}

So, a value of 3273917760 was passed to the function which is the total amount of disk space needed before compression. The function divides this by the compression ratio of 10 to get the actual size needed.

When I checked the disk that the share resides on it had ~177GB free, far more than what was reported. After starting the test again without changing anything it worked.

So my question here is; what could cause something like this? As far as I can tell it is not a programming error and, as I mentioned earlier, this code has been in use for a very long time now with no problems.

I checked the event log of the remote machine and found nothing of interest around the time of the failure. I'm hoping that someone out there has seen something similar before, thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷…雨湿花 2025-01-04 20:52:24

可能没有任何用处,但“奇怪”的是:

177GB ~= 186580992 * 1000。

这可以通过代码中其他地方发生的堆栈损坏(因为您没有初始化局部变量)来解释。

代码“inRequestedSize/compressionRatio”不必使用浮点数进行除法,并且由于您已经通过强制转换消除了“转换松散精度”警告,因此您实际上也可能会遇到错误(但是在示例应该有效)。您可以简单地执行“inRequestedSize / 10”。

最后但并非最不重要的一点是,您没有说明代码在哪里运行。在移动设备上,GetDiskFreeSpaceEx 的文档指出:

启用移动加密后,此功能的报告行为会发生变化。每个加密文件至少有一个 4 KB 页的关联开销。该函数在报告可用空间量时会考虑此开销。也就是说,如果 128 KB 磁盘包含单个 60 KB 文件,则此函数会报告 64 KB 可用,减去该文件占用的空间及其相关开销。

虽然此函数报告总可用空间,但在估计剩余空间是否适合多个新文件时,请记住加密文件的空间要求。包括启用移动加密时开销所需的空间量。每个文件至少需要额外 4 KB。例如,单个 60 KB 文件需要 64 KB,但两个 30 KB 文件实际上需要 68 KB。

Might not be of any use, but it's "strange" that:

177GB ~= 186580992 * 1000.

This could be explained by a stack corruption (since you don't initialize your local variable) happening elsewhere in the code.

The code "inRequestedSize / compressionRatio" doesn't have to be using float for the division, and since you've silented the "conversion loose precision" warning with the cast, you might actually hit an error too (but the number given in the example should work). You could simply do "inRequestedSize / 10".

Last but not least, you don't say where the code is running. On Mobile, the documentation of GetDiskFreeSpaceEx states:

When Mobile Encryption is enabled, the reporting behavior of this function changes. Each encrypted file has at least one 4-KB page of overhead associated. This function takes this overhead into account when it reports the amount pf space available. That is, if a 128-KB disk contains a single 60-KB file, this function reports that 64 KB is available, subtracting the space occupied by both the file and its associated overhead.

Although this function reports the total available space, keep the space requirement for encrypted files in mind when estimating whether multiple new files will fit into the remaining space. Include the amount of space required for overhead when Mobile Encryption is enabled. Each file requires at least an additional 4 KB. For example, a single 60-KB file requires 64 KB, but two 30-KB files actually require 68 KB.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文