นี่คือวิธีการrm -rf dir
ทำงาน:
- มันเปิดขึ้น
dir
และแสดงรายการเนื้อหา
- สำหรับแต่ละรายการถ้าเป็นไดเรคทอรีให้ทำซ้ำกระบวนการเดียวกันหากไม่มีให้เรียก
unlink
ใช้
หากคุณทำได้ให้ส่งคืนชื่อไฟล์พิเศษก่อนและถ้าคุณสามารถทำให้กระบวนการทำunlink
ไฟล์นั้นตายได้นั่นจะช่วยแก้ปัญหาได้ สามารถทำได้โดยใช้ระบบไฟล์ฟิวส์
ตัวอย่างเช่นคุณสามารถปรับloopback.pl
ตัวอย่างจากโมดูล perl Fuseซึ่งเพิ่งใช้ระบบไฟล์จำลองที่เป็นเพียงการส่งผ่านไปยังระบบไฟล์จริงที่อยู่ด้านล่าง (เช่นดูแพทช์ด้านล่าง):
- เมื่อมีการระบุรายชื่อไดเรกทอรีหากมีรายการที่มีชื่อ
.{{do-not-delete}}.
ให้เพิ่มรายการรายการที่มีสองไฟล์: .{{do-not-delete}}!error
และ.{{do-not-delete}}!kill
- เมื่อลองรหัส
unlink
แรกให้ส่งคืนEPERM
รหัสเพื่อrm
แสดงข้อความแสดงข้อผิดพลาด
- เมื่อพยายาม
unlink
ที่สองกระบวนการถูกฆ่าตาย
$ 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
นี่คือแพทช์ที่ใช้บนloopback.pl
ตัวอย่างนั้นเป็นข้อพิสูจน์แนวคิด:
--- 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
torm -i
:> -i prompt ก่อนทุกการลบหรือ> -I prompt หนึ่งครั้งก่อนลบไฟล์มากกว่าสามไฟล์หรือเมื่อลบซ้ำ รบกวนน้อยกว่า -i ในขณะที่ยังคงป้องกันความผิดพลาดส่วนใหญ่คุณสามารถเขียนสิ่งที่มีค่าสถานะอื่นได้ตลอดเวลา