यहां बताया गया है कि कैसे 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हटाने की कोशिश की :> -मैं हर हटाने से पहले या> -मैं एक बार में तीन से अधिक फ़ाइलों को हटाने से पहले या तुरंत हटाने पर। कम घुसपैठ से -आई, जबकि अभी भी सबसे गलतियों के खिलाफ सुरक्षा दे आप किसी भी समय अन्य झंडों के साथ उन पर अधिकार कर सकते हैं।