Apakah 'rm. *' Pernah menghapus direktori induk?

53

Ekspresi .*diperluas oleh bash untuk memasukkan direktori saat ini dan direktori induk:

$ ls -la
total 2600
drwxrwxrwx   2 terdon terdon 2162688 Sep 10 16:22 .
drwxr-xr-x 142 terdon terdon  491520 Sep 10 15:34 ..
-rw-r--r--   1 terdon terdon       0 Sep 10 16:22 foo
$ echo .*
. ..

Jika saya menjalankan rm -rf .*Debian menggunakan bash GNU, version 4.2.36(1)-releasedan rmdari rm (GNU coreutils) 8.13, saya menerima pesan ini:

$ rm -rf .*
rm: cannot remove directory: `.'
rm: cannot remove directory: `..'

Apakah ini masalah GNU atau POSIX? Apakah ada sistem * nix di mana perintah di atas akan dihapus .dan ..?

Juga, apakah ini fitur keamanan shell atau dari rmperintah itu sendiri?

terdon
sumber
4
Aku tahu pertanyaan ini adalah dalam konteks rm, tapi saya pikir itu menyebutkan layak bahwa Anda masih dapat memiliki hasil yang tak terduga dengan chmod, chown, dll ketika pencocokan .*.
Aaron Copley

Jawaban:

59

Versi POSIX spec terbaru untuk per rmutilitas ada di sini (dan yang sebelumnya ada ) dan melarang penghapusan .dan ...

Jika salah satu dari file dot atau dot-dot ditentukan sebagai bagian nama dasar dari operan (yaitu, komponen pathname akhir) atau jika operan memutuskan ke direktori root, rm harus menulis pesan diagnostik untuk kesalahan standar dan tidak melakukan apa pun. lebih banyak dengan operan tersebut.

Seperti dicatat oleh @jlliagre, bagian tentang /adalah tambahan di SUSv4.

Spesifikasi Unix tertua yang tersedia untuk umum yang dapat saya temukan ( XPF4 CAE rev2 (1994)), sudah menentukan itu .dan ..tidak dapat dihapus, meskipun komentar dalam fileel GNU changelog menyarankan itu sudah menjadi kasus dalam spesifikasi POSIX yang lebih lama.

Perhatikan bahwa ini berlaku untuk dir/..dan ../juga, tetapi beberapa implementasi (termasuk yang disertifikasi UNIX seperti Solaris 11 dan macOS) masih tidak melindungi terhadap rm -rf ../atau rm -rf .*/).

sejarah

Unifikasi awal

The -rpilihan untuk rmditambahkan pada Unix V3 (1973) meskipun hanya menghapus isi dari direktori, Anda masih perlu menggunakan rmdiruntuk menghapus direktori.

Itu berubah di Unix V7 (1979, rilis yang juga memperkenalkan shell Bourne dan dari mana sebagian besar Unives berasal). rm -rdirektori sekarang dihapus juga dan tidak akan menghapus ..pohon direktori. The man page negara:

Dilarang menghapus file ..hanya untuk menghindari konsekuensi antisosial dari melakukan sesuatu secara tidak sengaja rm -r .*.

(Meskipun orang mungkin berpendapat bahwa rm -r .*itu masih antisosial karena menghapus semuanya karena .sudah termasuk).

Itu masih menerima untuk menghapus .meskipun itu tidak akan membatalkan tautan .atau ..entri. Maka, rm -r .merupakan cara yang efektif untuk mengosongkan direktori saat ini.

Perhatikan juga bahwa perlindungan hanya untuk ..argumen literal , bukan untuk dir/..atau ./... Jadi, rm -rf ./.*masih akan menghapus semua yang ada di direktori induk secara rekursif.

Sangat menarik untuk melihat bahwa itu sudah bisa diatasi dengan bug / misfeature dimana glob dapat memasukkan .dan ..dalam ekspansi mereka. Itu diperbaiki di shell Forsyth (dasar untuk shell Minix asli dan pdksh) pada akhir 80-an, zsh(1990) dan fish(2005) tetapi tidak pada shell lain dan khususnya bukan shbahasa POSIX yang memerlukan perluasan .*untuk memasukkan .dan ..jika mereka dikembalikan oleh readdir()( bashmengatasi masalah sebagian hanya dengan di shopt -s dotglobmana gumpalan (kecuali .xxxyang) tidak termasuk .atau .., dan dengan ksh, Anda dapat memperbaikinya dengan melakukan FIGNORE='@(.|..)').

Kapan tepatnya melarang .juga ditambahkan tidak selalu jelas dan bervariasi dengan setiap Unix. Beberapa temuan di bawah ini.

BSD

The melarang dari .ditambahkan kira antara 2.9BSD (1983) dan 2.10BSD (1987) dan antara 4.2BSD (1983) dan 4.3BSD (1986) (lihat perubahan ini timestamped 1985 di unix-sejarah-repo ).

$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.9BSD/root.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `..'
$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.10bsd.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `.' or `..'
rm: cannot remove `.' or `..'\n");

Untuk dir/.dan dir/.., lihat perubahan ini pada tahun 1988 (BSD 4.3 Net / 1).

Sampai saat ini, rmFreeBSD (dan turunannya seperti macOS) masih mengosongkan direktori saat ini atau induk pada rm -rf ./atau rm -rf ../meskipun (penting untuk rm -rf .*/).

Sistem V

Saya tidak punya banyak informasi karena tidak ada sumber atau biner yang tersedia untuk umum untuk turunan AT&T Unix setelah V7. Dalam manual online-nya, HPUX (berdasarkan Sistem III) masih menyebutkan bahwa itu hanya melarang ..sementara secara efektif melarang keduanya yang merupakan indikasi bahwa mungkin setidaknya SysIII tidak melarang penghapusan .( sunting : Sekarang melihat kode sumber SysIIIrm , itu hampir tidak berubah sejak Unix V7).

Semua manual online lain yang telah saya periksa menyebutkan penghapusan .atau ..dilarang yang diharapkan sesuai dengan POSIX.

Solaris rmmasih mengosongkan direktori saat ini atau induk pada rm -rf ./atau rm -rf ../.

GNU

The changelog awal untuk fileutils GNU memiliki semua informasi sejarah.

Meskipun awalnya tidak menghapus .atau ..dilarang, ..pertama-tama dilarang dan kemudian keduanya (termasuk dir/.), semua antara tahun 1990 dan 1991.

lain

Seperti yang kita lihat, zshekspansi .*(atau bola dunia apa pun) tidak pernah menyertakan .atau ..(bahkan dalam shmode emulasi). Oleh karena itu rmbuiltin (yang Anda dapatkan jika Anda zmodload zsh/files) tidak memperlakukan .atau ..khusus. Jadi, dengan zshbuiltin itu, Anda bisa rm -rf .atau rm -rf ..mengosongkan .atau .., tetapi rm -rf .*tidak akan menghapus .atau ...

Dalam busybox rm, larangan penghapusan .dan ..ditambahkan pada 0.52 (2001)

Stéphane Chazelas
sumber
Aneh, itu sepertinya menentukan bahwa rm -rf . /(perhatikan spasi) harus mencetak dua peringatan (untuk .dan /) dan keluar, tetapi kami sepertinya mendapatkan pertanyaan yang menanyakan bagaimana memulihkan dari itu setiap beberapa bulan.
Kevin
6
@Kevin Tidak semua sistem kompatibel dengan POSIX dan pembatasan direktori root hanya ditambahkan secara eksplisit dalam rilis POSIX terbaru.
jlliagre
@ jlliagre saya mengerti. GNU umumnya mencoba menerapkan POSIX (+ ekstensi, tentu saja), dan saya membayangkan mereka ingin memasukkan yang ini, tetapi jika itu cukup baru yang akan menjelaskannya.
Kevin
2
@Stephane: Anda benar, tapi saya masih menambahkan "Ya, itu bisa terjadi! Tapi ..." di awal jawaban Anda, sehingga orang pasti tahu itu, pada beberapa (lebih tua atau hanya non -POSIX compliant) sistem, mereka bisa menghapus direktori induk. Saya mencoba untuk selalu menunjukkan kemungkinan itu (yaitu, saya mencoba untuk tetap berada di sisi yang aman, bahkan jika itu membuat jawaban kadang-kadang lebih sulit untuk dibaca / diingat) ^^
Olivier Dulac
1
@ MartinSchröder, Pada BSD, ditambahkan antara 2.8BSD dan 2.10BSD (sebelumnya hanya ".." dilarang seperti di UnixV7) dan antara 3BSD dan 4.3RENO. Pada sistem SysV, itu kurang jelas. Manual HPUX misalnya mengklaimnya hanya melarang ".." tetapi pada dasarnya itu melarang keduanya "." dan "..", itu hanya manual yang tidak mutakhir.
Stéphane Chazelas