-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathlk.py
More file actions
126 lines (112 loc) · 3.62 KB
/
lk.py
File metadata and controls
126 lines (112 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python
# file: lk.py
# vim:fileencoding=utf-8:ft=python
#
# Copyright © 2016-2018 R.F. Smith <rsmith@xs4all.nl>.
# SPDX-License-Identifier: MIT
# Created: 2016-10-09T11:59:41+02:00
# Last modified: 2022-11-21T07:26:40+0100
"""
Lock down files or directories.
This makes files read-only for the owner and inaccessible for the group and
others. Then it sets the user immutable and user undeletable flag on the files
if the filesystem supports that. For directories, it recursively treats the
files as mentioned above. It then sets the sets the directories to
read/execute only for the owner and inaccessible for the group and others.
Then it sets the user immutable and undeletable flag on the directories as
well, again if the filesystem supports that.
Using the -u flag unlocks the files or directories, making them writable for
the owner only.
"""
import argparse
import logging
import os
import sys
import stat
__version__ = "2022.11.19"
def main():
"""
Entry point for lk.py.
"""
args = setup()
fmod = stat.S_IRUSR
dmod = stat.S_IRUSR | stat.S_IXUSR
if args.unlock:
logging.info("unlocking files")
fmod = stat.S_IRUSR | stat.S_IWUSR
dmod = stat.S_IRWXU
action = unlock_path
else:
action = lock_path
logging.info("locking files")
for p in args.paths:
if os.path.isfile(p):
action("", p, fmod)
elif os.path.isdir(p):
if args.unlock:
action("", p, dmod)
for root, dirs, files in os.walk(p, topdown=False):
for fn in files:
action(root, fn, fmod)
for d in dirs:
action(root, d, dmod)
if not args.unlock:
action("", p, dmod)
def setup():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"-u",
"--unlock",
action="store_true",
help="unlock the files instead of locking them",
)
parser.add_argument(
"--log",
default="warning",
choices=["debug", "info", "warning", "error"],
help="logging level (defaults to 'warning')",
)
parser.add_argument("-v", "--version", action="version", version=__version__)
parser.add_argument(
"paths", nargs="*", metavar="path", help="files or directories to work on"
)
args = parser.parse_args(sys.argv[1:])
logging.basicConfig(
level=getattr(logging, args.log.upper(), None),
format="%(levelname)s: %(message)s",
)
logging.debug(f"Command line arguments = {sys.argv}")
logging.debug(f"Parsed arguments = {args}")
if not args.paths:
parser.print_help()
sys.exit(0)
return args
def lock_path(root, name, mode):
"""Lock down a path"""
addflags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK
p = os.path.join(root, name)
pst = os.stat(p)
if pst.st_flags & stat.UF_IMMUTABLE:
# Temporarily remove user immutable flag, so we can chmod.
try:
os.chflags(p, pst.st_flags ^ stat.UF_IMMUTABLE)
except OSError as e:
logging.info(e)
logging.info(f"locking path “{p}”")
os.chmod(p, mode)
try:
os.chflags(p, pst.st_flags | addflags)
except OSError as e:
logging.info(e)
def unlock_path(root, name, mode):
rmflags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK
p = os.path.join(root, name)
pst = os.stat(p)
logging.info(f"unlocking path “{p}”")
try:
os.chflags(p, pst.st_flags & ~rmflags)
except OSError as e:
logging.info(e)
os.chmod(p, mode)
if __name__ == "__main__":
main()