यहां बताया गया है कि कैसे rm -rf dir
काम करता है:
- यह खुलता है
dir
, और इसकी सामग्री को सूचीबद्ध करता है।
- प्रत्येक प्रविष्टि के लिए, यदि यह एक निर्देशिका है, तो इसके लिए उसी प्रक्रिया को दोहराएं, यदि यह नहीं है, तो उस
unlink
पर कॉल करें ।
यदि आप निर्देशिका सूचीकरण के लिए, पहले एक विशेष फ़ाइल नाम लौटा सकते हैं, और यदि आप unlink
मरने के लिए उस फ़ाइल पर एक प्रक्रिया कर सकते हैं , तो समस्या का समाधान होगा। यह एक फ्यूज फाइलसिस्टम का उपयोग करके किया जा सकता है।
उदाहरण के लिए, आप पर्ल फ्यूज मॉड्यूल से loopback.pl
उदाहरण को अनुकूलित कर सकते हैं जो सिर्फ एक डमी फाइल सिस्टम को लागू करता है जो कि केवल एक पास-थ्रू एक वास्तविक फ़ाइल सिस्टम के नीचे से गुजरता है (इसलिए नीचे भी देखें):
- निर्देशिका को सूचीबद्ध करते समय, यदि इसमें एक प्रविष्टि नाम है
.{{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
कोrm -i
हटाने की कोशिश की :> -मैं हर हटाने से पहले या> -मैं एक बार में तीन से अधिक फ़ाइलों को हटाने से पहले या तुरंत हटाने पर। कम घुसपैठ से -आई, जबकि अभी भी सबसे गलतियों के खिलाफ सुरक्षा दे आप किसी भी समय अन्य झंडों के साथ उन पर अधिकार कर सकते हैं।