Mengapa "rm -r" tidak dapat menghapus folder ini?

12

Saya memiliki folder dengan -wxizin yang dipanggil folder1dan folder lain di dalamnya disebut folder2dengan rwxizin.

Saya mencoba menghapus folder1menggunakan perintah ini:

rm -r folder1

Tapi saya mendapat kesalahan berikut:

rm: cannot remove 'folder1': Permission denied

Alasan saya pikir saya mendapatkan kesalahan ini adalah karena rmprogram harus terlebih dahulu mendapatkan konten folder1(dapatkan nama file dan folder di dalamnya folder1) agar dapat menghapus konten itu (karena Anda tidak dapat menghapus file) atau folder tanpa mengetahui namanya saya pikir), dan kemudian rmprogram dapat menghapus folder1sendiri.

Tetapi karena folder1tidak memiliki readizin, maka rmprogram tidak bisa mendapatkan kontennya, dan karenanya tidak bisa menghapus kontennya, dan karena tidak bisa menghapus kontennya, maka tidak bisa menghapus kontennya.

Apakah saya benar?

John
sumber
1
Lakukan "ls-l" dan beri tahu kami apa izin dari DIRECTORY.
jamesqf

Jawaban:

19

Saya pikir analisis Anda benar: Anda tidak dapat menghapus direktori karena tidak kosong, dan Anda tidak dapat mengosongkannya karena Anda tidak dapat melihat isinya.

Saya baru saja mencobanya:

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

Ketika saya menulis "Anda", saya maksudkan program apa pun yang Anda jalankan. rm -rPerintah Anda pertama-tama melihat itu folder1adalah direktori, jadi ia mencoba menemukan isinya untuk mengosongkannya, tetapi gagal karena izin baca yang hilang, kemudian mencoba untuk menghapusnya tetapi gagal karena tidak kosong. "Izin ditolak" menyesatkan; Saya pikir "Direktori tidak kosong" (seperti rmdirlaporan) akan lebih sesuai.)

pengguna2233709
sumber
4
Tidak dapat melaporkan Directory not emptydalam kasus ini karena tidak akan tahu itu kosong atau tidak. Anda masih akan mendapatkan kesalahan yang sama ketika mencoba menghapus direktori kosong yang belum Anda baca izinnya. (Juga, tolong abaikan komentar saya sebelumnya, saya tidak punya topi berpikir saya pada).
Kusalananda
1
@ Kusalananda Kedengarannya waras, tetapi rmdirmampu melaporkan "Direktori tidak kosong". Dan jika Anda membaca tes saya, Anda akan melihat bahwa itu menerima untuk menghapus folder1direktori, tanpa izin baca , setelah saya mengosongkannya.
user2233709
2
Tes Anda menunjukkan perbedaan yang menarik antara sistem kami. Saya mendapatkan Permission deniedketika mencoba rm -r folder1ketika itu kosong. Saya menggunakan OpenBSD, bukan Linux.
Kusalananda
@ Kusalananda Itu menarik. Saya akan berpikir bahwa perilaku ini ditentukan oleh Spesifikasi Single Unix, sehingga Linux dan {Free, Net, Open} BSD akan berperilaku identik. (Sebagai catatan, saya menggunakan Debian Stretch 9.8 dengan kernel linux 4.9.144-3 x86_64.)
user2233709
Hmm ... Satu-satunya hal yang POSIX katakan adalah bahwa jika operan adalah direktori dan -rdigunakan, setiap entri direktori (kecuali untuk .dan ..) harus dihapus seolah-olah mereka adalah operan file rm -r. Tampaknya seolah-olah GNU rmhanya melakukan rmdir()pada direktori jika itu tidak dapat dibaca, karena itu tidak akan memiliki cara untuk mendapatkan isinya.
Kusalananda
7

Agar penghapusan terjadi, sistem harus dapat membaca konten dan mengidentifikasi apa yang harus dihapus.

Saya sudah mencoba mensimulasikan apa yang Anda coba:

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

Jika kami mencoba menghapus tanpa izin baca itu gagal:

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

Dalam strace untuk dua upaya perbedaannya adalah bahwa isi direktori tidak dapat dibaca (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

Dengan izin baca:

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

Untuk menyimpulkan bahkan jika Anda memiliki direktori dan memiliki bit yang dapat dieksekusi, Anda masih perlu izin baca sehingga Anda dapat melihat isinya dan menghapus folder. Ini tidak sama untuk sebuah file.

ttaran7
sumber
0

Yah, saya tidak punya reputasi yang cukup untuk mengomentari jawaban oleh ttaran7, jadi sepertinya itu adalah jawaban. Pilihan saya juga tidak dapat dilihat oleh publik, karena reputasi yang rendah. Saya memilih jawaban itu untuk benar-benar menyertakan jejak panggilan sistem, bukan hanya spekulasi.

Untuk menjawab pertanyaan OP: Ya, alasan Anda benar: Anda diblokir karena gagal membaca direktori

Saya menjalankan jejak yang sama dengan apa yang telah mereka (ttaran7) lakukan karena saya curiga alasan yang sama: rmPanggilan akan gagal setelah gagal membaca direktori dan itu akan menjadi akhir dari itu, tidak ada kesempatan untuk mengeluh tentang direktori yang kosong. Setelah melihat kedua jejak yang saya ambil, saya perhatikan bahwa panggilan sistem dibuat untuk mencoba memutuskan tautan nama file yang disediakan:

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)

Lihatlah baris ke-4: unlinkat... yang gagal karena direktori TIDAK kosong. Sekarang itulah yang saya anggap sebagai perilaku tak terduga, faktanya ia mencoba menghapus direktori sama sekali, meski tidak memiliki izin baca.

ojklan
sumber
Ah, Anda benar, saya akan memperbaikinya ketika saya mendapatkan keyboard yang sebenarnya. Terima kasih.
ojklan