【问题标题】:How can GetFreeDiskSpaceEx return the (seemingly) wrong amount of disk space?GetFreeDiskSpaceEx 如何返回(看似)错误的磁盘空间量?
【发布时间】:2023-04-01 00:18:01
【问题描述】:

所以我在一个输出大图像(从 30MB 到 2GB+)的设备上工作。在我们开始创建这些映像之一之前,我们通过GetDiskFreeSpaceEx 检查是否有足够的磁盘空间。通常(在这种情况下)我们正在写入同一网络上的共享文件夹。磁盘空间上没有用户配额。

昨晚,为了准备演示,我们开始了试运行。在运行过程中,我们遇到了失败。我们需要327391776 字节,并被告知我们只有186580992 可用。 GetDiskFreeSpaceEx 的数字是:

用户可用空间:186580992

总可用空间:186580992

这些对应于lpFreeBytesAvailablelpTotalNumberOfFreeBytesGetDiskFreeSpaceAvailable 的两个(输出)参数中的QuadPart 变量。

此代码已使用多年,我从未见过假阴性。这是完整的功能:

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 的可用空间,远远超过所报告的。再次开始测试后没有改变任何工作。

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

我检查了远程机器的事件日志,在发生故障的时候没有发现任何有趣的东西。我希望有人以前见过类似的东西,在此先感谢。

【问题讨论】:

  • 可能在您遇到故障的那一刻磁盘空间较小。例如,备份进程(或恶意软件扫描程序)可能保留了一堆磁盘空间,然后在完成后再次释放。
  • @AdrianMcCarthy:谢谢阿德里安。这是我希望在事件日志中找到的那种东西,但如果有类似的事情发生,它就不会被记录下来。我正在努力想出一个解释,但我找不到任何有趣的证据。
  • 您认为问题可能是整数签名问题吗? GetDiskFreeSpaceEx 的返回值是一个无符号整数 (ULONGLONG),它是 'typedef'ed 到 'unsigned __int64'。通过将其视为有符号值(即通过您的返回值),您不会将其可以存储的数量减半吗?
  • @AdrianConlon:是的,是的,但看起来它仍然是 2^63,我认为我不必担心一段时间。

标签: c++ windows winapi diskspace


【解决方案1】:

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

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。

【讨论】:

  • 你知道我也注意到了这一点,而且过去一天我一直在寻找那条轨道。很难想象这会在这么长时间后如此巧妙地弹出,但当然这是可能的,我同意这样一个干净的数字是可疑的。代码确实需要一个浮点数,因为压缩率并不总是整数,为了简单起见,我只是硬编码了在失败情况下使用的值(它实际上是由函数返回的。)。这是在 PC 上,所以没有移动设备,但我感谢您的回复。
  • 啊...压缩比是 0.1(而不是 10)吗?这可能是一个简单的调试错误,误解了数字。
  • 关于“Mobile”版本,其实NTFS也允许压缩,所以如果驱动被压缩,返回的数字很可能是错误的。
  • 在本例中为 10,但在其他情况下(取决于所使用的压缩类型)可能为 7.5、1.5 等。
猜你喜欢
  • 2014-08-06
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 2012-02-17
  • 2016-03-14
  • 1970-01-01
  • 2018-07-06
  • 1970-01-01
相关资源
最近更新 更多