Win7下,获取文件夹C:\Users 大小时遇到的问题

最近在负责数据备份产品的时候遇到一个问题:在Win7系统下,用户选择“C:\Users” 作为备份源,发现产品UI上显示的文件夹大小和负责备份的Service进程里的文件夹大小不一致。


起先,我怀疑是获取文件夹大小的方法不对,但是查看代码之后发现代码是一样的。都是枚举文件夹和文件大小,然后累加。后来才发现,UI进程获取该文件夹大小的时候,很多目录不能访问;而Service进程能访问该目录下的所有文件夹,所以得到的大小比UI上显示的大很多。这样确认是由于两个进程的权限不一致导致的。


该产品的框架是:UI进程是在当前用户状态下运行的,故只有当前用户的权限;而后台Service进程是运行在System状态下的,所以有最高权限,梦访问所有目录。


问题本身:

首先,我们看看Win7下 目录 C:\Users的内容(把 Hide和System都是设置为可见)

Win7下,获取文件夹C:\Users 大小时遇到的问题_第1张图片


然后在C:\Users\All Users 目录下,有个“Application Data” 目录,这个目录在资源管理器里是不能访问。



因为资源管理器实际上也是运行在当前用户权限下,所以UI进程取得的目录大小和通过资源管理器查看属性的方法看到的目录大小是一致的。


如何解决问题:

然后我进一步对比这种目录的属性,发现“Application Data” 目录除了具有FILE_ATTRIBUTE_DIRECTORY之外,还有FILE_ATTRIBUTE_SYSTEM、FILE_ATTRIBUTE_REPARSE_POINT以及FILE_ATTRIBUTE_NOT_CONTENT_INDEXED等属性。但是我们又不能通过属性来判断为当前用户无权访问,因为有些类似目录当前用户是可以访问的,比如用户自己的“Application Data”目录。

所以最完美的方案是:把Service进程的权限从System降为当前用户权限。但是本人查了很多资料,还是不得要领,加上实施风险比较高,所以放弃了。


由于本案例中只要保持两边目录大小显示一直,所以最后想办法把这个目录大小通过UI进程传给Service进程,而不是让Service进程自己再获取一次。


获取目录大小的方法:

下面是我们常用的获取文件夹大小的函数,仅供参考。


bool GetFolderSize(LPCWSTR szPath,  UInt64 *totalSize,   UInt64 *totalFiles,  UInt64 *totalFolders)
{
    if (NULL == szPath)
    {
        return false;
    }
    static const int MAX_PATH_LEN = 512;

    WCHAR szFileFilter[MAX_PATH_LEN] = {0};
    TCHAR szFilePath[MAX_PATH_LEN] = {0};
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA fileinfo;

    wcsncpy_s(szFilePath,szPath,MAX_PATH_LEN);
    wcscat_s(szFilePath,L"\\");
    wcsncpy_s(szFileFilter,szFilePath, MAX_PATH_LEN);
    wcscat_s(szFileFilter,L"*.*");

    hFind = FindFirstFile(szFileFilter,&fileinfo);
    if (INVALID_HANDLE_VALUE == hFind)
    {
        return false;
    }
    do
    {
        if(fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            if (!wcscmp(fileinfo.cFileName,L".") || !wcscmp(fileinfo.cFileName,L".."))
            {
                //Do nothing for "." and ".." folders
            }
            else
            {
                WCHAR sztmp[MAX_PATH_LEN];
                wcsncpy_s(sztmp,szFilePath,MAX_PATH_LEN);
                wcscat_s(sztmp,fileinfo.cFileName);

                GetFolderSize(sztmp, totalSize, totalFiles, totalFolders);
                if(totalFolders != NULL)
                {
                    ++(*totalFolders);
                }
            }
        }
        else
        {
            if(totalFiles != NULL)
            {
                ++(*totalFiles);
            }
        }

        if(totalSize != NULL)
        {
            (*totalSize) += ((UInt64)MAXDWORD+1) * fileinfo.nFileSizeHigh + fileinfo.nFileSizeLow;
        }
    }while(FindNextFile(hFind,&fileinfo));

    FindClose(hFind);
    hFind = INVALID_HANDLE_VALUE;
    return true;
}

你可能感兴趣的:(Win7下,获取文件夹C:\Users 大小时遇到的问题)