系统:x86_64 Linux 5.13.19-2-MANJARO。
我在“~/.local/share/Trash/expunged”中有一个奇怪的目录,其中包含用户拥有的一些目录没有人。我尝试以 root 身份执行以下命令:
rm -rf pathToWeirdDirectory
这会产生以下错误消息
rm:无法删除“pathToWeirdDirectory”:对于定义的数据类型来说值太大
使用更改目录所有权后
chown me:me pathToWeirdDirectory
我终于成功删除了该目录。还有一些这种类型的目录,其中有几个包含多个文件的子目录。我尝试执行以下命令:
chown -R me:me pathToSecondWeirdDirectory
这会产生以下错误消息:
chown:无法读取目录“pathToSeconWeirdDirectory/subdirectory1/subdirectory2”:权限被拒绝
就我而言,“-R”标志会递归地更改给定目录的所有权,因此我创建了以下测试用例:
directory/
file
subdirectory/
file2
由用户拥有我。我使用“chown -R root:根目录”成功更改了其所有权,包括预期的所有子目录和文件。
问题:为什么“chown”命令不能对用户拥有的目录使用“-R”标志递归地工作没有人?为什么无法删除用户拥有的文件没有人作为根?
编辑:作为对评论的回应,我想提供“pathToSecondWeirdDirectory”的全名。
〜/.local/share/Trash/expunged/294376611/5e5a7b41-3df4-4b2f-b7ac-f57d09ed1823/.sage/matplotlib-1.5.1
另一个例子
〜/.local/share/Trash/expunged/294376611/5e5a7b41-3df4-4b2f-b7ac-f57d09ed1823/.sage/R
编辑2:在马库斯给出了一个很好的答案之后,我使用相同的技术做了一些更多的调试。 chown 单个目录可以按预期工作。使用 -R 进行 chown 失败。我比较了输出,直到最后几行都是相同的。他们是这样的:
庄:
close(8) = 0
close(5) = 0
close(6) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
newfstatat(AT_FDCWD, "security", {st_mode=S_IFDIR|0700, st_size=4096, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchownat(AT_FDCWD, "security", 60202, 60202, 0) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
乔恩-R
close(8) = 0
close(5) = 0
close(6) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
newfstatat(AT_FDCWD, "startup", {st_mode=S_IFDIR|0700, st_size=4096, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "startup", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = -1 EACCES (Permission denied)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2998, ...}, AT_EMPTY_PATH) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
read(3, "", 4096) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, "chown: ", 7) = 7
write(2, "cannot read directory 'startup'", 31) = 31
openat(AT_FDCWD, "/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Permission denied", 19) = 19
write(2, "\n", 1) = 1
close(1) = 0
close(2) = 0
exit_group(1) = ?
+++ exited with 1 +++
答案1
如果没有更多的调试,就不可能确定,但这确实看起来像 Linux 曾经遇到的 stat/stat64 问题(现在仍然如此)。
基本上,fstat
系统调用用于查询“这个文件是目录吗?”之类的事情。 (如果你想递归地删除东西,知道这一点非常重要),“它是一个符号链接吗?”,“它的大小是多少?”。
最后一点正是有趣的地方:该系统调用需要一个指向 a 的指针struct stat
,其中包含所有这些类型信息的字段。最初,文件大小整数为 32 位。现在,文件可以比这个更大。因此,需要一个新的调用来为您提供 64 位数字的信息。
现在,当您在大于 32 位变量可以容纳的文件上使用 32 位 stat 变体时该怎么办?显然,需要有一个错误条件,这样您就不会意外地认为 65 GB 的文件只有 1 GB 大小。当该错误传递给error
//时,strerror
会perror
准确打印您所看到的错误消息。
当然,当文件统计信息的其他部分不适合您想要返回的类型时(或者超出最大页数时,可能还有其他几种情况),也适用相同的机制。
所以,现在有趣的部分来了:这不太可能是你相对现代的
/usr/bin/rm:ELF 64 位 LSB 饼可执行文件,x86-64,版本 1 (SYSV),动态链接,解释器 /lib64/ld-linux-x86-64.so.2,BuildID[sha1]=5d1d8b77d21f9362855e93f8cff5fc685127a26f ,对于 GNU/Linux 4.4.0,已删除
正在使用老的 fstat[at]
系统调用。你可以试试:
cd /tmp
touch base
strace -o log.strace -e /stat rm base
grep '"base"' log.strace
应该大概yield 调用newfstatat
,它肯定处理 64 位数字。
因此,有了这些知识,我们现在尝试删除一个奇怪的目录:
strace -o /tmp/log.strace rm -r /path/to/one/single_one/of/the/undeletable_directories
并滚动到日志底部:打印错误消息需要几行调用,但上面应该是一个产生的调用EOVERFLOW
(提示:搜索该字符串!)。我的假设是这是不是一个通常的统计调用,但很可能是一个openat
调用或由于不同原因而失败的东西。
¹ 我会运行gdb --args rm /path/to/weirddirectory
,在对 的任何调用上设置断点error
,如果这不起作用,则对 的任何调用设置断点write
。
² 甚至还有 Coreutils常见问题解答入口,archive.org 链接,因为我不相信 FSF 能够永远运行可靠的基础设施
答案2
请考虑您可能会在递归路径中遍历软链接。
建议尝试:
chown -L -R me:me pathToSecondWeirdDirectory
可以用find
命令删除遍历符号链接
find -L <target dir1> <target dir2> ... -delete