Чому "rm -r" не може видалити цю папку?


12

У мене папка з -wxдозволами, що викликається, folder1а інша папка всередині неї називається folder2з rwxдозволами.

Я намагався видалити folder1за допомогою цієї команди:

rm -r folder1

Але я отримав таку помилку:

rm: cannot remove 'folder1': Permission denied

Причиною, на яку я вважаю, що я отримав цю помилку, є те, що rmпрограмі потрібно спочатку отримати вміст folder1(отримати назви файлів і папок всередині folder1), щоб можна було видалити цей вміст (тому що ви не можете видалити файл або папку, не знаючи її назви, я думаю), і тоді rmпрограма може видалити folder1себе.

Але оскільки folder1не має readдозволу, rmпрограма не може отримати її вміст, а значить, не може видалити її вміст, а оскільки не може видалити його вміст, то не може видалити його.

Я прав?


1
Зробіть "ls -l" і скажіть нам, що таке дозволи ДИРЕКТОРІЇ.
jamesqf

Відповіді:


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цьому випадку він не може повідомити, оскільки не знатиме, чи він порожній чи ні. Ви все одно отримаєте ту саму помилку при спробі видалити порожній каталог, на який у вас немає прав на читання. (Крім того, будь ласка, ігноруйте мій попередній коментар, у мене не було шапки для мислення).
Kusalananda

1
@Kusalananda Це звучить здорово, але rmdirможе повідомити "Каталог не порожній". І якщо ви прочитаєте мій тест, ви побачите, що він приймає видалення folder1каталогу, не маючи дозволу на читання , як тільки я його очищую.
користувач2233709

2
Ваш тест показує цікаву різницю між нашими системами. Я отримую, Permission deniedколи намагаюся, rm -r folder1коли він порожній. Я на OpenBSD, а не на Linux.
Kusalananda

@Kusalananda Це цікаво. Я б подумав, що така поведінка була визначена специфікацією Single Unix, так що Linux і {Free, Net, Open} BSD поводитимуться однаково. (Для запису я використовую Debian Stretch 9.8 з ядром linux 4.9.144-3 x86_64.)
user2233709

Хм ... Єдине, що говорить POSIX - це те, що якщо операнд є каталогом і -rвикористовується, кожен запис каталогу (крім .і ..) повинен бути видалений так, ніби вони були операндом файлів rm -r. Схоже, GNU rmпросто робить a rmdir()в каталозі, якщо він не читабельний, тому що у нього не буде можливості отримати вміст.
Kusalananda

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

У напрузі для двох спроб різниця полягає в тому, що вміст каталогів не може бути прочитаний (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, тому схоже, що відповідь доведеться мати. Мій підсумковий голосування також не є загальнодоступним через низьку репутацію. Я проголосував за цю відповідь за те, що фактично включав слід системного дзвінка, а не просто міркування.

Щоб відповісти на питання ОП: Так, ваші міркування були правильними: вас заблокували, якщо не читати каталог

Я провів схожий слід з тим, що вони (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)

Подивіться на 4-й рядок: unlinkat... який не вдається, тому що каталог НЕ порожній. Тепер це те, що я вважав би несподіваною поведінкою, факт, що він намагається видалити каталог взагалі, незважаючи на те, що не читав дозволів, що це є.


Ага, ти маєш рацію, я виправлю це, коли перейду до справжньої клавіатури. Дякую.
ojklan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.