So rm -rf dirfunktioniert es:
- Es wird geöffnet
dirund der Inhalt aufgelistet.
- Wenn es sich um ein Verzeichnis handelt, wiederholen Sie für jeden Eintrag den gleichen Vorgang. Wenn dies nicht der Fall ist, rufen
unlinkSie ihn auf.
Wenn Sie für die Verzeichnisliste zuerst einen speziellen Dateinamen zurückgeben könnten und wenn Sie einen Prozess, der eine unlinkDatei ausführt, zum Erliegen bringen könnten , würde dies das Problem lösen. Dies könnte mit einem Sicherungsdateisystem erfolgen.
Zum Beispiel könnten Sie das loopback.plBeispiel aus dem Perl-Fuse-Modul anpassen, das nur ein Dummy-Dateisystem implementiert, das nur ein Durchgang zu einem realen Dateisystem darunter ist (siehe auch Patch unten):
- Wenn Sie ein Verzeichnis auflisten und einen Eintrag mit dem Namen enthalten
.{{do-not-delete}}., stellen Sie der Liste der Einträge zwei Dateien voran: .{{do-not-delete}}!errorund.{{do-not-delete}}!kill
- Wenn Sie zum
unlinkersten versuchen , geben Sie den EPERMCode zurück, sodass rmeine Fehlermeldung angezeigt wird
- Beim Versuch zum
unlinkzweiten wird der Prozess abgebrochen.
$ ls -Ff dir/test
./ .{{do-not-delete}}. foo/ ../ bar
$ ./rm-rf-killer dir
$ ls -Ff dir/test
.{{do-not-delete}}!error .{{do-not-delete}}!kill ./ .{{do-not-delete}}. foo/ ../ bar
$ rm -rf dir/test
rm: cannot remove `dir/test/.{{do-not-delete}}!error': Operation not permitted
zsh: terminated rm -rf dir/test
$ ls -Ff dir/test
.{{do-not-delete}}!error .{{do-not-delete}}!kill ./ .{{do-not-delete}}. foo/ ../ bar
Hier ein Patch, der als Proof of Concept auf dieses loopback.plBeispiel angewendet werden soll:
--- loopback.pl 2013-06-03 22:35:00.577316063 +0100
+++ rm-rf-killer 2013-06-03 22:33:41.523328427 +0100
@@ -7,2 +7,4 @@
my $has_threads = 0;
+my $flag = ".{{do-not-delete}}";
+
eval {
@@ -42,3 +44,4 @@
-use blib;
+#use blib;
+use File::Basename;
use Fuse;
@@ -49,3 +52,3 @@
-my %extraopts = ( 'threaded' => 0, 'debug' => 0 );
+my %extraopts = ( 'threaded' => 0, 'debug' => 0, 'mountopts' => 'nonempty' );
my($use_real_statfs, $pidfile);
@@ -64,3 +67,7 @@
-sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
+sub fixup {
+ my $f = shift;
+ $f =~ s#(/\Q$flag\E)!(error|kill)$#$1.#s;
+ return ".$f";
+}
@@ -78,3 +85,9 @@
}
- my (@files) = readdir(DIRHANDLE);
+ my @files;
+
+ while (my $f = readdir(DIRHANDLE)) {
+ unshift @files, "$flag!error", "$flag!kill"
+ if ($f eq "$flag.");
+ push @files, $f;
+ }
closedir(DIRHANDLE);
@@ -121,3 +134,12 @@
sub x_readlink { return readlink(fixup(shift)); }
-sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!; }
+sub x_unlink {
+ my $f = shift;
+ if (basename($f) eq "$flag!error") {return -EPERM()}
+ if (basename($f) eq "$flag!kill") {
+ my $caller_pid = Fuse::fuse_get_context()->{"pid"};
+ kill("TERM", $caller_pid);
+ return -EPERM();
+ }
+ return unlink(".$f") ? 0 : -$!;
+}
@@ -203,3 +225,2 @@
sub daemonize {
- chdir("/") || die "can't chdir to /: $!";
open(STDIN, "< /dev/null") || die "can't read /dev/null: $!";
@@ -236,2 +257,3 @@
+chdir($mountpoint) or die("chdir: $!");
daemonize();
@@ -239,3 +261,3 @@
Fuse::main(
- 'mountpoint' => $mountpoint,
+ 'mountpoint' => '.',
'getattr' => 'main::x_getattr',
rm,rm -ivor jedem Entfernen einen Alias zu erstellen:> -i Eingabeaufforderung oder> -I einmal vor dem Entfernen von mehr als drei Dateien oder beim rekursiven Entfernen. Weniger aufdringlich als -i, bietet aber dennoch Schutz vor den meisten Fehlern. Sie können diese jederzeit mit anderen Flags überschreiben.