Skip to content

Commit

Permalink
Merge pull request #7 from alanzchen/recursive-protection
Browse files Browse the repository at this point in the history
Recursive protection
  • Loading branch information
alanzchen authored Feb 21, 2017
2 parents c635719 + f856ec5 commit 9a5a9f4
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The disaster could have been avoided.

`pip install rm-protection` and optionally, `alias rm="rm-p"` for your daily user and **root** (so that it works for `sudo`).

2. Protect your files using `protect`.
2. Protect your files using `protect`. If you want to protect everything inside, `protect -R`.

3. Happy rm-ing!

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Quick Start
``pip install rm-protection``

1. Install from PyPi and make an alias for ``rm-p``.
2. Protect your files using ``protect``.
2. Protect your files using ``protect``. If you want to protect everything inside, ``protect -R``.
3. Happy rm-ing!

How does it work?
Expand Down
2 changes: 2 additions & 0 deletions rm_protection/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ class Config():
def __init__(self):
self.suffix = ".rm-protection"
self.invalid = ['.', '..', './', '../']
self.protect_prefix = 'protect: '
self.rm_prefix = 'rm-p: '
24 changes: 19 additions & 5 deletions rm_protection/protect.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,36 @@
from rm_protection.config import Config


c = Config()


def pprint(msg):
global c
print(c.protect_prefix + msg)


def protect(protect_args=None):
c = Config()
global c
flags = ''
option_end = False
if not protect_args:
protect_args = argv[1:]
for arg in protect_args:
if arg in c.invalid:
print("\".\" and \"..\" may not be protected")
if arg == '--':
option_end = True
elif (arg.startswith("-") and not option_end):
flags = flags + arg[arg.rfind('-') + 1:]
elif arg in c.invalid:
pprint('"." and ".." may not be protected')
else:
path = abspath(expv(expu(arg)))
evalpath = dirname(path) + "/." + basename(path) + c.suffix
if not exists(path):
print("Warning: " + path + " does not exist")
pprint("Warning: " + path + " does not exist")
with open(evalpath, "w") as f:
question = input("Question for " + path + ": ")
answer = input("Answer: ")
f.write(question + "\n" + answer)
f.write(question + "\n" + answer + "\n" + flags.upper())


if __name__ == "__main__":
Expand Down
115 changes: 91 additions & 24 deletions rm_protection/rm_p.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,93 @@
from rm_protection.config import Config


def ask(evalpath, path=""):
with open(evalpath, "r") as f:
if path:
print(path + ": " + f.readline().rstrip("\n"))
else:
print("A file is protected by " + evalpath)
print(f.readline().rstrip("\n"))
if input("Answer: ") == f.readline().rstrip("\n"):
return True
elif path:
print("Wrong answer! " + path + " will not be removed")
print("The answer is stored in " + evalpath)
return False
else:
print("Wrong answer! File/directory protected by " + evalpath + " will not be removed")
return False
c = Config()
evaledpaths = []


def pprint(msg):
global c
print(c.rm_prefix + msg)


def ask(evalpath, parent=False):
global evaledpaths
if evalpath in evaledpaths:
return True
else:
with open(evalpath, "r") as f:
question = f.readline().rstrip("\n")
answer = f.readline().rstrip("\n")
try:
flags = f.readline().rstrip("\n")
except:
flags = ''
if parent and 'R' not in flags:
pprint(original_path(evalpath) + ' is protected but flag "R" is missing')
evaledpaths.append(evalpath)
return True
else:
if parent:
pprint('The parent directory ' + original_path(evalpath) + ' is protected')
pprint(original_path(evalpath) + ": " + question)
if input("Answer: ") == answer:
evaledpaths.append(evalpath)
return True
else:
if parent:
return False
else:
pprint("Wrong answer! " + original_path(evalpath) + " will not be removed")
pprint("The answer is stored in " + evalpath)
return False


def original_path(evalpath):
global c
basepath = dirname(evalpath)
filename = basename(evalpath)[1:-len(c.suffix)]
if basepath == '/':
return basepath + filename
else:
return basepath + '/' + filename


def ask_in(q, a):
return bool(input(q) in a)


def gen_evalpaths(path):
paths = {}
path = dirname(path)
while path != '/':
evalpath = gen_eval(path)
paths[path] = evalpath
path = dirname(path)
return paths


def gen_eval(path):
global c
basedir = dirname(path)
if basedir == '/':
basedir = ''
return basedir + "/." + basename(path) + c.suffix


def parent_clear(file_evalpaths, path):
for filepath in file_evalpaths:
parent_eval = file_evalpaths[filepath]
if exists(parent_eval):
if not ask(parent_eval, parent=True):
pprint(path + ' will not be removed')
return False
return True


def rm(rm_args=None):
global c
global evaledpaths
args = ''
c = Config()
paths = []
evalpaths = []
option_end = False
Expand All @@ -43,26 +105,30 @@ def rm(rm_args=None):
pass
else:
path = abspath(expv(expu(arg)))
evalpath = dirname(path) + "/." + basename(path) + c.suffix
file_evalpaths = gen_evalpaths(path)
evalpath = gen_eval(path)
if c.suffix in arg:
print(path + " is a protection file")
pprint(path + " is a protection file")
if ask_in(q="Do you want to remove it? (y/n) ", a="Yesyes"):
args += arg + ' '
else:
print(path + " will not be removed")
pprint(path + " will not be removed")
continue
if exists(evalpath):
if ask(evalpath, path):
if ask(evalpath):
paths.append(path)
evalpaths.append(evalpath)
else:
continue
elif isdir(path):
if not parent_clear(file_evalpaths, path):
continue
if isdir(path):
find_exec = "find " + path + " -name " + "\".*" + c.suffix + "\"" + " -print"
out, err = Popen(find_exec, shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True).communicate()
for pfile in iter(out.splitlines()):
pprint("A protected file or directory is found inside " + path)
if not ask(pfile):
print("Terminated due to potentially dangerous action")
pprint("Terminated due to potentially dangerous action")
exit(1)
args += arg + ' '
Popen("rm " + args, shell=True).wait()
Expand All @@ -71,7 +137,8 @@ def rm(rm_args=None):
if exists(evalpath) and not exists(path):
remove_protection_files += evalpath + ' '
if remove_protection_files:
Popen("rm " + remove_protection_files, shell=True)
Popen("rm " + remove_protection_files, shell=True).wait()
evaledpaths = []


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setup(
name="rm_protection",
version="0.1.1.1",
version="0.1.2",
license='MIT',
description="A safe alternative for \"rm\" with minimum difference.",
author='Alan Chen',
Expand Down

0 comments on commit 9a5a9f4

Please sign in to comment.