web-dev-qa-db-fra.com

Pourquoi "rm -r" ne peut-il pas supprimer ce dossier?

J'ai un dossier avec -wx autorisations appelées folder1 et un autre dossier à l'intérieur appelé folder2 avec les autorisations rwx.

J'ai essayé de supprimer folder1 en utilisant cette commande:

rm -r folder1

Mais j'ai eu l'erreur suivante:

rm: cannot remove 'folder1': Permission denied

La raison pour laquelle je pense avoir obtenu cette erreur est que le programme rm doit d'abord obtenir le contenu de folder1 (récupère les noms des fichiers et dossiers dans folder1 c'est-à-dire) afin de pouvoir supprimer ce contenu (car vous ne pouvez pas supprimer un fichier ou un dossier sans connaître son nom, je pense), puis le programme rm peut supprimer folder1 lui-même.

Mais depuis folder1 n'a pas l'autorisation read, alors le programme rm ne peut pas obtenir son contenu, et donc il ne peut pas supprimer son contenu, et puisqu'il ne peut pas supprimer son contenu , il ne peut pas le supprimer.

Ai-je raison?

12
John

Je pense que votre analyse est correcte: vous ne pouvez pas supprimer le répertoire car il n'est pas vide, et vous ne pouvez pas le vider car vous ne pouvez pas voir son contenu.

Je viens de l'essayer:

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

Quand j'ai écrit "vous", je voulais dire n'importe quel programme que vous pourriez exécuter. Votre rm -r la commande voit d'abord que folder1 est un répertoire, il essaie donc de découvrir son contenu pour le vider, mais échoue pour une autorisation de lecture manquante, puis il essaie de le supprimer mais échoue car il n'est pas vide. La "permission refusée" est trompeuse; Je pense que "Répertoire non vide" (comme les rapports rmdir) serait plus approprié.)

19
user2233709

Pour que la suppression se produise, le système doit être capable de lire le contenu et d'identifier ce qui doit être supprimé.

J'ai essayé de simuler ce que vous tentez:

[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 ~]$ 

Si nous essayons de supprimer sans autorisations de lecture, il échoue:

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

Dans une séquence pour les deux tentatives, la différence est que le contenu du répertoire ne peut pas être lu (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

Avec des autorisations de lecture:

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

Pour conclure même si vous possédez un répertoire et qu'il a le bit exécutable, vous avez toujours besoin d'autorisations de lecture pour que vous puissiez voir son contenu et supprimer le dossier. Ce n'est pas la même chose pour un fichier.

7
ttaran7

Eh bien, je n'ai pas assez de réputation pour commenter la réponse de ttaran7, donc cela devrait être une réponse. Mon vote positif n'est pas non plus visible publiquement, en raison de sa faible réputation. J'ai voté en faveur de cette réponse pour avoir réellement inclus une trace d'appel système, plutôt que simplement de la spéculation.

Pour répondre à la question de l'OP: oui, votre raisonnement était correct: vous êtes bloqué à défaut de lecture du répertoire

J'ai exécuté une trace similaire à ce qu'ils (ttaran7) avaient fait parce que je soupçonnais le même raisonnement: l'appel rm échouerait en ne lisant pas le répertoire et ce serait la fin de cela, aucune chance de se plaindre le répertoire étant vide. En jetant un deuxième coup d'œil à la trace que j'ai prise, j'ai remarqué qu'un appel système a été effectué pour tenter de dissocier le nom de fichier fourni de toute façon:

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)

Regardez la 4ème ligne: unlinkat... qui échoue car le répertoire n'est PAS vide. Maintenant, c'est ce que je considérerais comme un comportement inattendu, le fait qu'il essaie de supprimer le répertoire, bien qu'il n'ait pas d'autorisations de lecture.

0
ojklan