std::filesystem 即使在使用 skip_permission_denied 时,递归迭代器也会抛出 permission_denied
std::filesystem recursive iterator will throw permission_denied even when skip_permission_denied is in use
我正在编写一个 linux 命令行程序,它将 return 一个目录的大小。该程序按预期工作,除非专门处理根目录。我知道根目录中的许多文件没有大小,因为它们是用于表示系统信息的特殊文件(如 /proc/)或类似 /dev/null/ 的文件,所以我在 for 循环中使用了 std::filesystem::directory_options::skip_permission_denied
跳过权限问题,我使用多个 try/catch 块来捕获异常。
但是,即使这样,仍然会抛出权限被拒绝的异常。见以下代码:
byte_size_and_num_files find_recursive(const std::filesystem::path& path)
{
byte_size_and_num_files bsnf;
std::filesystem::path pa;
try
{
for(const auto& p: std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied))
{
pa = p.path();
if (std::filesystem::exists(p) && !std::filesystem::is_directory(p))
{
try
{
if(std::filesystem::is_regular_file(pa))
{
bsnf.size += std::filesystem::file_size(p);
bsnf.files++;
}
else
std::cout << "SKIPPED: size is not determinable: " << pa << "\n";
}
catch(std::filesystem::filesystem_error& e)
{
std::cout << "SKIPPED: size is not determinable: " << pa << "\n";
}
catch(std::bad_alloc)
{
std::cout << "Allocation error. Exiting..." << "\n";
byte_size_and_num_files err;
return err;
}
}
}
}
catch(std::filesystem::filesystem_error& e)
{
std::cout << "Unable to access file or path " << pa <<": " << e.what() << "\n";
}
catch(std::bad_alloc)
{
std::cout << "Allocation error. Exiting..." << "\n";
byte_size_and_num_files err;
return err;
}
return bsnf;
}
输出:
...
SKIPPED: size is not determinable: "/lib/systemd/system/motd.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountall-bootclean.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountall.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountdevsubfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountkernfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountnfs-bootclean.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountnfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/rc.service"
SKIPPED: size is not determinable: "/lib/systemd/system/rcS.service"
SKIPPED: size is not determinable: "/lib/systemd/system/reboot.service"
SKIPPED: size is not determinable: "/lib/systemd/system/rmnologin.service"
SKIPPED: size is not determinable: "/lib/systemd/system/sendsigs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/single.service"
SKIPPED: size is not determinable: "/lib/systemd/system/stop-bootlogd-single.service"
SKIPPED: size is not determinable: "/lib/systemd/system/stop-bootlogd.service"
SKIPPED: size is not determinable: "/lib/systemd/system/umountfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/umountnfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/umountroot.service"
SKIPPED: size is not determinable: "/lib/systemd/system/x11-common.service"
SKIPPED: size is not determinable: "/lib/systemd/system/lvm2.service"
Unable to access file or path "/proc/1/task/1/cwd": filesystem error: status: Permission denied [/proc/1/task/1/cwd]
/ is 262172.00 gigabytes with 143839 files.
什么给了?它的明确许可被拒绝应该总是被跳过,但它仍然会被抛出。同样清楚的是,无法确定大小的文件也被跳过,但似乎发现并使用了一些不正确的文件大小(262172.00 GB 当然不正确)。这仅在通过根目录时发生,而不会在任何其他目录(如 home)中发生。
这可能是实施错误吗?
编辑:
一些调试揭示了一些重要信息。
看起来好像 /dev/pts/ 专门破坏了文件大小。
我不明白为什么不跳过此目录中的文件,因为
它们不是常规文件,因此应跳过它们。我想
std::filesystem 错误地将这些文件识别为常规文件。
此外,std::filesystem::directory_options::skip_permission_denied 对除 /proc/1/task/1/cwd 以外的每个文件都有效。我不确定为什么没有跳过这个文件。
编辑 2
我已经找到了破坏 std::filesystem 的罪魁祸首目录。
一共有三个,
/dev/
/proc/
/var/cache/
/dev/ 会因为某种原因弄乱文件大小,我猜 std::filesystem 会考虑这些常规文件,所以当您尝试获取文件大小时,您会得到一个垃圾编号。即使使用跳过权限,/dev/ 的某些部分也会抛出权限异常。
/proc/ 也会因为与 /dev/
相同的原因而弄乱文件大小
/var/cache/ 似乎不会弄乱文件大小,但即使在使用跳过权限时也会抛出权限异常。
我认为这些是实施错误,因为这些目录中的文件不是常规文件,但 std::filesystem 将它们视为常规文件。
docs on cppreference 说 skip_permission_denied
是为了“跳过会导致权限被拒绝错误的目录。”。它只说目录,只说文件。该选项意味着如果您无法读取“/proc/sys/xyz”,则会跳过此目录并且不会抛出异常。在你的情况下,这是尊重的,你不会从 recursive_directory_iterator
得到 filesystem_error
异常。但这与此迭代器 returns.
的任何文件无关
但是在std::filesystem::exists(p)
和std::filesystem::is_directory(p)
中抛出异常。它由两个函数内部调用的 std::filesystem::status
抛出。 en.cppreference 表示在 status
中“符号链接指向它们的目标 ”。如果您不是 root
.
,这对 /proc/1/task/1/cwd
是不可能的
ls -alg /proc/1/task/1/cwd
向我显示文件模式 lrwxrwxrwx
但权限被拒绝消息。
$ ls -alg /proc/1/task/1/cwd
ls: Lesen der symbolischen Verknüpfung '/proc/1/task/1/cwd' nicht möglich: Keine Berechtigung
lrwxrwxrwx 1 root 0 Mär 11 08:53 /proc/1/task/1/cwd
我相信 recursive_directory_iterator
只是在查看文件模式,但 cwd
似乎很特殊,需要额外的访问规则。因此,您的解决方案可能是捕获 std::filesystem::exists
或 std::filesystem::is_directory
抛出的异常,忽略它们并继续。
我正在编写一个 linux 命令行程序,它将 return 一个目录的大小。该程序按预期工作,除非专门处理根目录。我知道根目录中的许多文件没有大小,因为它们是用于表示系统信息的特殊文件(如 /proc/)或类似 /dev/null/ 的文件,所以我在 for 循环中使用了 std::filesystem::directory_options::skip_permission_denied
跳过权限问题,我使用多个 try/catch 块来捕获异常。
但是,即使这样,仍然会抛出权限被拒绝的异常。见以下代码:
byte_size_and_num_files find_recursive(const std::filesystem::path& path)
{
byte_size_and_num_files bsnf;
std::filesystem::path pa;
try
{
for(const auto& p: std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied))
{
pa = p.path();
if (std::filesystem::exists(p) && !std::filesystem::is_directory(p))
{
try
{
if(std::filesystem::is_regular_file(pa))
{
bsnf.size += std::filesystem::file_size(p);
bsnf.files++;
}
else
std::cout << "SKIPPED: size is not determinable: " << pa << "\n";
}
catch(std::filesystem::filesystem_error& e)
{
std::cout << "SKIPPED: size is not determinable: " << pa << "\n";
}
catch(std::bad_alloc)
{
std::cout << "Allocation error. Exiting..." << "\n";
byte_size_and_num_files err;
return err;
}
}
}
}
catch(std::filesystem::filesystem_error& e)
{
std::cout << "Unable to access file or path " << pa <<": " << e.what() << "\n";
}
catch(std::bad_alloc)
{
std::cout << "Allocation error. Exiting..." << "\n";
byte_size_and_num_files err;
return err;
}
return bsnf;
}
输出:
...
SKIPPED: size is not determinable: "/lib/systemd/system/motd.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountall-bootclean.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountall.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountdevsubfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountkernfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountnfs-bootclean.service"
SKIPPED: size is not determinable: "/lib/systemd/system/mountnfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/rc.service"
SKIPPED: size is not determinable: "/lib/systemd/system/rcS.service"
SKIPPED: size is not determinable: "/lib/systemd/system/reboot.service"
SKIPPED: size is not determinable: "/lib/systemd/system/rmnologin.service"
SKIPPED: size is not determinable: "/lib/systemd/system/sendsigs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/single.service"
SKIPPED: size is not determinable: "/lib/systemd/system/stop-bootlogd-single.service"
SKIPPED: size is not determinable: "/lib/systemd/system/stop-bootlogd.service"
SKIPPED: size is not determinable: "/lib/systemd/system/umountfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/umountnfs.service"
SKIPPED: size is not determinable: "/lib/systemd/system/umountroot.service"
SKIPPED: size is not determinable: "/lib/systemd/system/x11-common.service"
SKIPPED: size is not determinable: "/lib/systemd/system/lvm2.service"
Unable to access file or path "/proc/1/task/1/cwd": filesystem error: status: Permission denied [/proc/1/task/1/cwd]
/ is 262172.00 gigabytes with 143839 files.
什么给了?它的明确许可被拒绝应该总是被跳过,但它仍然会被抛出。同样清楚的是,无法确定大小的文件也被跳过,但似乎发现并使用了一些不正确的文件大小(262172.00 GB 当然不正确)。这仅在通过根目录时发生,而不会在任何其他目录(如 home)中发生。
这可能是实施错误吗?
编辑: 一些调试揭示了一些重要信息。 看起来好像 /dev/pts/ 专门破坏了文件大小。 我不明白为什么不跳过此目录中的文件,因为 它们不是常规文件,因此应跳过它们。我想 std::filesystem 错误地将这些文件识别为常规文件。
此外,std::filesystem::directory_options::skip_permission_denied 对除 /proc/1/task/1/cwd 以外的每个文件都有效。我不确定为什么没有跳过这个文件。
编辑 2 我已经找到了破坏 std::filesystem 的罪魁祸首目录。 一共有三个,
/dev/
/proc/
/var/cache/
/dev/ 会因为某种原因弄乱文件大小,我猜 std::filesystem 会考虑这些常规文件,所以当您尝试获取文件大小时,您会得到一个垃圾编号。即使使用跳过权限,/dev/ 的某些部分也会抛出权限异常。
/proc/ 也会因为与 /dev/
相同的原因而弄乱文件大小/var/cache/ 似乎不会弄乱文件大小,但即使在使用跳过权限时也会抛出权限异常。
我认为这些是实施错误,因为这些目录中的文件不是常规文件,但 std::filesystem 将它们视为常规文件。
docs on cppreference 说 skip_permission_denied
是为了“跳过会导致权限被拒绝错误的目录。”。它只说目录,只说文件。该选项意味着如果您无法读取“/proc/sys/xyz”,则会跳过此目录并且不会抛出异常。在你的情况下,这是尊重的,你不会从 recursive_directory_iterator
得到 filesystem_error
异常。但这与此迭代器 returns.
但是在std::filesystem::exists(p)
和std::filesystem::is_directory(p)
中抛出异常。它由两个函数内部调用的 std::filesystem::status
抛出。 en.cppreference 表示在 status
中“符号链接指向它们的目标 ”。如果您不是 root
.
/proc/1/task/1/cwd
是不可能的
ls -alg /proc/1/task/1/cwd
向我显示文件模式 lrwxrwxrwx
但权限被拒绝消息。
$ ls -alg /proc/1/task/1/cwd
ls: Lesen der symbolischen Verknüpfung '/proc/1/task/1/cwd' nicht möglich: Keine Berechtigung
lrwxrwxrwx 1 root 0 Mär 11 08:53 /proc/1/task/1/cwd
我相信 recursive_directory_iterator
只是在查看文件模式,但 cwd
似乎很特殊,需要额外的访问规则。因此,您的解决方案可能是捕获 std::filesystem::exists
或 std::filesystem::is_directory
抛出的异常,忽略它们并继续。