为什么“ rm -r”无法删除此文件夹?


12

我有一个文件夹-wx的权限称为folder1和里面的另一个文件夹名为folder2rwx权限。

我尝试folder1使用以下命令删除:

rm -r folder1

但是我收到以下错误:

rm: cannot remove 'folder1': Permission denied

我认为我收到此错误的原因是因为rm程序首先需要获取的内容folder1(获取其中的文件和文件夹的名称folder1)才能删除该内容(因为您无法删除文件)或文件夹,而我不知道它的名称),然后rm程序可以删除folder1自己。

但是由于folder1没有read权限,因此rm程序无法获取其内容,因此无法删除其内容,并且由于无法删除其内容,因此也无法删除它。

我对么?


1
执行“ ls -l”,然后告诉我们该目录的权限是什么。
jamesqf

Answers:


19

我认为您的分析是正确的:您不能删除目录,因为它是非空的,您也不能清空它,因为您看不到它的内容。

我只是尝试一下:

$ mkdir -p folder1/folder2
$ chmod -r folder1
$ rm -rf folder1
rm: cannot remove 'folder1': Permission denied
$ rmdir folder1/folder2
$ rm -rf folder1
$ 

当我写“你”时,我指的是你可以运行的任何程序。您的rm -r命令首先看到folder1一个目录,因此它尝试发现其内容以将其清空,但是由于缺少读取权限而失败,然后尝试删除它,但由于该目录不是空的而失败。“拒绝权限”具有误导性;我认为“目录不为空”(例如rmdir报告)会更合适。)


4
Directory not empty在这种情况下它无法报告,因为它不会知道它是否为空。尝试删除没有读取权限的目录时,仍然会出现相同的错误。(此外,请不要理会我之前的评论,但我没有思考的能力)。
库萨兰达

1
@Kusalananda听起来很理智,但rmdir可以报​​告“目录不为空”。而且,如果您阅读了我的测试,您会看到它接受了删除folder1目录,并且没有读取权限,一旦我将其清空。
user2233709 '19

2
您的测试显示了我们系统之间的有趣差异。我得到了Permission denied想要的时候rm -r folder1,当它是空的。我使用的是OpenBSD,而不是Linux。
库萨兰达

@Kusalananda这很有趣。我以为该行为是由Single Unix Specification指定的,因此Linux和{Free,Net,Open} BSD的行为将相同。(为记录起见,我将Debian Stretch 9.8与linux 4.9.144-3 x86_64内核一起使用。)
user2233709

嗯... POSIX唯一要说的是,如果操作数是一个目录并且-r已使用,则应删除每个目录项(.和除外..),就像它们是的文件操作数一样rm -r。如果它不可读,就好像GNU rm只是rmdir()在目录上执行一样,因为它将无法获取其中的内容。
库萨兰达

7

为了进行删除,系统必须能够读取内容并标识必须删除的内容。

我已经尝试模拟您的尝试:

[vagrant@desktop1 ~]$ sudo rm -rf folder1/ && mkdir -pv folder1/folder2 && sudo chmod 333 -v folder1/ && sudo chmod 777 -v folder1/folder2
mkdir: created directory 'folder1'
mkdir: created directory 'folder1/folder2'
mode of 'folder1/' changed from 0775 (rwxrwxr-x) to 0333 (-wx-wx-wx)
mode of 'folder1/folder2' changed from 0775 (rwxrwxr-x) to 0777 (rwxrwxrwx)
[vagrant@desktop1 ~]$ ls -lh
total 0
d-wx-wx-wx. 3 vagrant vagrant 21 Feb 24 10:40 folder1
[vagrant@desktop1 ~]$ 

如果我们尝试删除没有读取权限的文件,它将失败:

[vagrant@desktop1 ~]$ rm -r folder1/
rm: cannot remove 'folder1/': Permission denied
[vagrant@desktop1 ~]$ sudo chmod +r folder1/
[vagrant@desktop1 ~]$ rm -r folder1/
[vagrant@desktop1 ~]$ 

在两次尝试的strace中,区别在于无法读取目录内容(getdents):

newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0333, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "folder1/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = -1 EACCES (Permission denied)
geteuid()                               = 1000
newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0333, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0
faccessat(AT_FDCWD, "folder1/", W_OK)   = 0
openat(AT_FDCWD, "folder1/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = -1 EACCES (Permission denied)
newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0333, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0

具有读取权限:

newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0777, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "folder1/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFDIR|0777, st_size=21, ...}) = 0
fcntl(3, F_GETFL)                       = 0x38800 (flags O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_NOFOLLOW)
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents(3, /* 3 entries */, 32768)     = 80
close(3)                                = 0
geteuid()                               = 1000

要得出结论,即使您拥有目录并且具有可执行位,您仍然需要读取权限,以便您可以看到其内容并删除该文件夹。但是,对于文件而言,它并不相同。


0

好吧,我没有足够的声誉来评论ttaran7的答案,所以看来它必须是一个答案。由于声誉低下,我的投票也未公开显示。我投票赞成这个答案,因为它实际上包括系统调用跟踪,而不仅仅是推测。

回答OP的问题:是的,您的推理是正确的:由于无法读取目录而被阻止

我对他们(ttaran7)所做的工作进行了类似的跟踪,因为我怀疑是同样的道理:rm如果无法读取目录,则调用将失败,并且这将结束,没有机会抱怨目录为空。在仔细查看了我的跟踪记录后,我注意到进行了系统调用以尝试取消链接提供的文件名:

newfstatat(AT_FDCWD, "folder1", {st_mode=S_IFDIR|0311, st_size=4096, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "folder1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = -1 EACCES (Permission denied)
openat(AT_FDCWD, "folder1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = -1 EACCES (Permission denied)
unlinkat(AT_FDCWD, "folder1", AT_REMOVEDIR) = -1 ENOTEMPTY (Directory not empty)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2995, ...}) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2995
read(3, "", 4096)                       = 0
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale/en_AU/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)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_AU/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=45256, ...}) = 0
mmap(NULL, 45256, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8db25ca000
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale- langpack/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=578, ...}) = 0
mmap(NULL, 578, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8db25c9000
close(3)                                = 0
write(2, "rm: ", 4rm: )                     = 4
write(2, "cannot remove 'folder1'", 23cannot remove 'folder1') = 23
openat(AT_FDCWD, "/usr/share/locale/en_AU/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)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_AU/LC_MESSAGES/libc.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2893, ...}) = 0
mmap(NULL, 2893, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8db25c8000
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Permission denied", 19: Permission denied)     = 19
write(2, "\n", 1
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exitgroup(1)

看第四行:unlinkat...失败,因为目录不是空的。现在这就是我要考虑的意外行为,尽管它没有读取权限,但它实际上试图删除目录。


嗯,您是对的,当我接触到真正的键盘时,我会予以纠正。谢谢。
ojklan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.