Skip to content

Commit 4b8c489

Browse files
committed
Update
1 parent aba12e2 commit 4b8c489

3 files changed

Lines changed: 225 additions & 155 deletions

File tree

.github/module/termux/py/contextpatch.py

Lines changed: 103 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,139 +2,178 @@
22
# -*- coding: utf-8 -*-
33

44
import os
5+
import re
56
import sys
67

7-
# Key không có dấu "/" ở đầu để khớp hoàn chỉnh với cấu trúc sinh ra từ scan_dir
8-
fix_permission = {
9-
"vendor/bin/hw/android.hardware.wifi@1.0": ["u:object_r:hal_wifi_default_exec:s0"],
10-
"system/bin/init": ["u:object_r:init_exec:s0"],
8+
# Khai báo quy tắc gán context cứng (hỗ trợ cả đường dẫn tuyệt đối lẫn tên file/thư mục đặc biệt)
9+
FIX_PERMISSIONS = {
1110
"lost+found": ["u:object_r:rootfs:s0"],
11+
"system/bin/init": ["u:object_r:init_exec:s0"],
1212
"system/bin/idmap": ["u:object_r:idmap_exec:s0"],
1313
"system/bin/fsck": ["u:object_r:fsck_exec:s0"],
1414
"system/bin/e2fsck": ["u:object_r:fsck_exec:s0"],
15-
"system/bin/logcat": ["u:object_r:logcat_exec:s0"]
15+
"system/bin/logcat": ["u:object_r:logcat_exec:s0"],
16+
"vendor/bin/hw/android.hardware.wifi@1.0": ["u:object_r:hal_wifi_default_exec:s0"]
1617
}
1718

18-
def scan_context(file) -> tuple:
19-
"""Đọc file context, giữ nguyên cấu trúc Regex gốc và bảo toàn thứ tự dòng."""
19+
def escape_regex_path(path: str) -> str:
20+
"""
21+
Escape các ký tự đặc biệt Regex (+, .) cho file_contexts của Android,
22+
giữ nguyên dấu / và @ để make_ext4fs đọc chuẩn.
23+
"""
24+
# Escape dấu '+' chưa được escape trước đó
25+
path_escaped = re.sub(r'(?<!\\)\+', r'\+', path)
26+
return path_escaped
27+
28+
def scan_context(file_path: str) -> tuple:
29+
"""Đọc file context, lưu trữ dưới dạng dict và bảo toàn thứ tự dòng gốc."""
2030
context = {}
2131
original_order = []
2232

23-
with open(file, "r", encoding='utf-8') as file_:
24-
for i in file_:
25-
line = i.strip()
26-
if not line or line.startswith('#'):
33+
with open(file_path, "r", encoding='utf-8') as f:
34+
for line in f:
35+
line_str = line.strip()
36+
if not line_str or line_str.startswith('#'):
2737
continue
2838

29-
parts = line.split()
39+
parts = line_str.split()
3040
if not parts:
3141
continue
3242

33-
filepath, *other = parts
34-
filepath = filepath.replace(r'\@', '@')
35-
context[filepath] = other
36-
original_order.append(filepath)
43+
filepath = parts[0]
44+
# Chuẩn hóa đường dẫn bỏ escape @ nếu có
45+
filepath_clean = filepath.replace(r'\@', '@')
46+
47+
context[filepath_clean] = parts[1:]
48+
original_order.append(filepath_clean)
3749

3850
return context, original_order
3951

40-
def scan_dir(folder) -> list:
52+
def scan_dir(folder: str) -> list:
4153
"""
42-
Quét thư mục thực tế và chuyển đổi sang định dạng path chuẩn của Android.
43-
HỖ TRỢ DYNAMIC PARTITIONS.
54+
Quét thư mục thực tế và chuyển đổi sang định dạng path chuẩn của Android SELinux.
55+
Hỗ trợ Dynamic Partitions (system, vendor, product, system_ext, cust...).
4456
"""
4557
folder_abs = os.path.abspath(folder).replace('\\', '/')
4658
part_name = os.path.basename(os.path.normpath(folder))
47-
48-
# Xây dựng các root path chuẩn
49-
allfiles = ['/', f'/{part_name}/lost+found', f'/{part_name}', f'/{part_name}/']
59+
60+
allfiles = [
61+
'/',
62+
f'/{part_name}',
63+
f'/{part_name}/',
64+
f'/{part_name}/lost+found'
65+
]
5066

5167
for root, dirs, files in os.walk(folder, topdown=True):
52-
# Chuẩn hóa root path hiện tại về dạng gạch chéo xuôi
5368
root_clean = os.path.abspath(root).replace('\\', '/')
5469

55-
for dir_ in dirs:
56-
full_path = f"{root_clean}/{dir_}"
70+
for dir_name in dirs:
71+
full_path = f"{root_clean}/{dir_name}"
5772
target_path = full_path.replace(folder_abs, '/' + part_name)
5873
allfiles.append(target_path)
5974

60-
for file in files:
61-
full_path = f"{root_clean}/{file}"
75+
for file_name in files:
76+
full_path = f"{root_clean}/{file_name}"
6277
target_path = full_path.replace(folder_abs, '/' + part_name)
6378
allfiles.append(target_path)
6479

6580
return sorted(set(allfiles), key=allfiles.index)
6681

67-
def context_patch(fs_file, filename) -> tuple:
68-
"""Vá context thông minh dựa trên luật cứng hoặc thừa kế từ thư mục cha."""
82+
def context_patch(fs_file: dict, filename_list: list) -> tuple:
83+
"""Vá context thông minh dựa trên luật cứng, quy tắc tương thích hoặc thừa kế thư mục cha."""
6984
new_fs = {}
7085
added_keys = []
7186

72-
permission_d = ['u:object_r:system_file:s0']
87+
# Context mặc định cho file/folder không xác định
88+
default_permission = ['u:object_r:system_file:s0']
7389
if fs_file:
74-
permission_d = fs_file.get(next(iter(fs_file)), permission_d)
90+
default_permission = fs_file.get(next(iter(fs_file)), default_permission)
7591

76-
for i in filename:
77-
actual_i = i if i.isprintable() else ''.join(c if c.isprintable() else '*' for c in i)
92+
for path in filename_list:
93+
actual_path = path if path.isprintable() else ''.join(c if c.isprintable() else '*' for c in path)
7894

79-
if fs_file.get(actual_i):
80-
new_fs[actual_i] = fs_file[actual_i]
95+
# 1. Khớp chính xác với file_contexts gốc
96+
if actual_path in fs_file:
97+
new_fs[actual_path] = fs_file[actual_path]
8198
continue
8299

83-
if actual_i in new_fs:
100+
if actual_path in new_fs:
84101
continue
85102

86-
permission = permission_d
87-
clean_i = actual_i.lstrip('/')
88-
89-
if clean_i in fix_permission:
90-
permission = fix_permission[clean_i]
91-
elif actual_i in fix_permission:
92-
permission = fix_permission[actual_i]
103+
permission = None
104+
clean_path = actual_path.lstrip('/')
105+
base_name = os.path.basename(actual_path)
106+
107+
# 2. Khớp theo FIX_PERMISSIONS (Tên file/thư mục hoặc đuôi path)
108+
if clean_path in FIX_PERMISSIONS:
109+
permission = FIX_PERMISSIONS[clean_path]
110+
elif base_name in FIX_PERMISSIONS:
111+
permission = FIX_PERMISSIONS[base_name]
93112
else:
94-
# Thuật toán tìm ngược lên thư mục cha có thêm điều kiện chặn lặp vô hạn
95-
tmp_path = os.path.dirname(actual_i)
96-
while tmp_path and tmp_path != "/":
113+
# 3. Thừa kế context từ thư mục cha gần nhất
114+
tmp_path = os.path.dirname(actual_path)
115+
while tmp_path:
97116
if tmp_path in fs_file:
98117
permission = fs_file[tmp_path]
99118
break
119+
if tmp_path in new_fs:
120+
permission = new_fs[tmp_path]
121+
break
122+
if tmp_path in ('/', ''):
123+
break
124+
100125
prev_path = tmp_path
101126
tmp_path = os.path.dirname(tmp_path)
102-
if tmp_path == prev_path: # Chặn lỗi lặp cấu trúc lạ
127+
if tmp_path == prev_path:
103128
break
104129

105-
print(f"ADD [{actual_i}:{permission}]")
106-
new_fs[actual_i] = permission
107-
added_keys.append(actual_i)
130+
# Nếu vẫn chưa tìm thấy context -> Dùng default
131+
if not permission:
132+
permission = default_permission
133+
134+
print(f"ADD [{actual_path} : {' '.join(permission)}]")
135+
new_fs[actual_path] = permission
136+
added_keys.append(actual_path)
108137

109138
return new_fs, added_keys
110139

111-
def main(dir_path, fs_config) -> None:
140+
def main(dir_path: str, fs_config: str) -> None:
112141
origin, orig_order = scan_context(os.path.abspath(fs_config))
113142
allfiles = scan_dir(os.path.abspath(dir_path))
114143

115144
new_fs, added_keys = context_patch(origin, allfiles)
116145

117146
with open(fs_config, "w", encoding='utf-8', newline='\n') as f:
118-
# Ghi lại các key cũ theo đúng thứ tự ban đầu
147+
written_keys = set()
148+
149+
# Ghi các key cũ theo đúng thứ tự gốc
119150
for key in orig_order:
120151
if key in new_fs:
121-
f.write(f"{key} {' '.join(new_fs[key])}\n")
122-
del new_fs[key]
152+
formatted_key = escape_regex_path(key)
153+
f.write(f"{formatted_key} {' '.join(new_fs[key])}\n")
154+
written_keys.add(key)
123155

124-
# Ghi các key mới được thêm vào cuối file
156+
# Ghi các key mới được bổ sung
125157
for key in sorted(added_keys):
126-
if key in new_fs:
127-
f.write(f"{key} {' '.join(new_fs[key])}\n")
158+
if key in new_fs and key not in written_keys:
159+
formatted_key = escape_regex_path(key)
160+
f.write(f"{formatted_key} {' '.join(new_fs[key])}\n")
161+
written_keys.add(key)
128162

129-
print("Load origin %d entries" % (len(origin.keys())))
130-
print("Detect total %d entries" % (len(allfiles)))
131-
print("Add %d entries thành công" % (len(added_keys)))
163+
print("---")
164+
print(f"Load origin: {len(origin)} entries")
165+
print(f"Detect total: {len(allfiles)} entries")
166+
print(f"Added new: {len(added_keys)} entries successfully")
132167

133168
if __name__ == "__main__":
134169
if len(sys.argv) < 3:
135-
print("Insufficient parameters")
170+
print("Usage: python script.py <dir_path> <file_contexts_path>")
136171
sys.exit(1)
137-
if not os.path.exists(sys.argv[1]) or not os.path.exists(sys.argv[2]):
138-
print("File does not exist")
172+
173+
dir_arg, context_arg = sys.argv[1], sys.argv[2]
174+
175+
if not os.path.exists(dir_arg) or not os.path.exists(context_arg):
176+
print("Error: Target directory or file_contexts path does not exist.")
139177
sys.exit(1)
140-
main(sys.argv[1], sys.argv[2])
178+
179+
main(dir_arg, context_arg)

0 commit comments

Comments
 (0)