Nasıl rm -rf dir
çalışır:
- Açılır
dir
ve içeriğini listeler.
- Her giriş için, eğer bir dizinse, aynı işlemi tekrarlayın, eğer değilse, çağırın
unlink
.
Dizin listeleme için önce özel bir dosya adı döndürdüyseniz ve unlink
bu dosya üzerinde bir işlem yaparak ölüme neden olabilirseniz , bu sorunu çözecektir. Bu bir sigorta dosya sistemi kullanılarak yapılabilir.
Örneğin, adapte olabilir loopback.pl
örnek gelen perl Fuse modülü şöyle bir gerçek dosya sistemi ve alt kısımda geçiyorsa geçiş sadece sadece bir kukla dosya sistemini uygulayan (ayrıca aşağıda yama bakın):
- bir dizini listelerken, adında bir girdi içeriyorsa
.{{do-not-delete}}.
, iki dosya içeren girdilerin başına ekleyin: .{{do-not-delete}}!error
ve.{{do-not-delete}}!kill
unlink
birincisine çalışırken , bir hata mesajı görüntüleyecek şekilde EPERM
kodu rm
döndürün
unlink
ikincisine çalışırken , süreç öldürülür.
$ 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
İşte bir kavram kanıtı olarak bu loopback.pl
örneğin üstüne uygulanacak bir yama :
--- 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
hiçrm -i
:> -i istemi önce her kaldırma veya> -I üçten fazla dosyaları kaldırarak veya yinelemeli çıkartırken önce bir kez istemi. Çoğu hataya karşı koruma sağlarken -i'den daha az müdahaleci olabilir. Başka bayraklara sahip olanları istediğiniz zaman yazabilirsiniz.