Đây là cách rm -rf dir
hoạt động:
- Nó mở
dir
, và liệt kê nội dung của nó.
- Đối với mỗi mục, nếu đó là một thư mục, hãy lặp lại quy trình tương tự cho nó, nếu không, hãy gọi
unlink
nó.
Nếu bạn có thể, đối với danh sách thư mục, trước tiên hãy trả lại tên tệp đặc biệt và nếu bạn có thể gây ra quá trình thực hiện unlink
trên tệp đó bị chết, điều đó sẽ giải quyết vấn đề. Điều đó có thể được thực hiện bằng cách sử dụng một hệ thống tập tin cầu chì.
Chẳng hạn, bạn có thể điều chỉnh loopback.pl
ví dụ từ mô-đun Fuse perl , chỉ thực hiện một hệ thống tập tin giả chỉ là một hệ thống tập tin thực bên dưới như vậy (xem thêm bản vá bên dưới):
- khi liệt kê một thư mục, nếu nó chứa một mục có tên
.{{do-not-delete}}.
, hãy thêm vào danh sách các mục có hai tệp: .{{do-not-delete}}!error
và.{{do-not-delete}}!kill
- Khi cố gắng
unlink
đầu tiên, trả lại EPERM
mã đểrm
hiển thị thông báo lỗi
- Khi cố gắng đến
unlink
cái thứ hai, quá trình bị giết.
$ 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
Đây là một bản vá để áp dụng trên loopback.pl
ví dụ đó như một bằng chứng về khái niệm:
--- 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 -i
:> -i nhắc trước mỗi loại bỏ hoặc> -Tôi nhắc một lần trước khi tháo hơn ba tác phẩm, hoặc khi loại bỏ đệ quy. Ít xâm phạm hơn -i, trong khi vẫn bảo vệ chống lại hầu hết các lỗi Bạn có thể ghi lại những điều đó bằng các cờ khác bất cứ lúc nào.