Skip to content

Commit 746a207

Browse files
committed
Update
1 parent c205462 commit 746a207

4 files changed

Lines changed: 54 additions & 67 deletions

File tree

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414

1515

1616
def str_to_selinux(s: str) -> str:
17-
# Escape dấu . cho đúng định dạng regex file_contexts, giữ nguyên / và -
17+
# Escape dấu . đúng chuẩn regex file_contexts, giữ nguyên / và -
1818
escaped = re.escape(s).replace(r"\-", "-").replace(r"\/", "/")
1919
return escaped.replace(r"\@", "@")
2020

2121

22+
def clean_permission(perm: List[str]) -> List[str]:
23+
"""Lọc bỏ các cờ file type modifier như --, -d, -l, -p,... để tránh gán nhầm cờ của file cho thư mục"""
24+
modifiers = {"--", "-d", "-c", "-b", "-l", "-p", "-s"}
25+
return [p for p in perm if p not in modifiers]
26+
27+
2228
def scan_context(file_path: str) -> List[ContextEntry]:
23-
"""Đọc file gốc và GIỮ NGUYÊN thứ tự xuất hiện của từng dòng."""
2429
entries: List[ContextEntry] = []
2530
with open(file_path, "r", encoding="utf-8", errors="ignore") as fp:
2631
for line in fp:
@@ -60,15 +65,11 @@ def scan_dir(folder: str) -> list:
6065

6166
def _default_permission(entries: List[ContextEntry]) -> list:
6267
if entries:
63-
return entries[0][1]
68+
return clean_permission(entries[0][1])
6469
return ["u:object_r:system_file:s0"]
6570

6671

6772
def find_insert_index(entries: List[ContextEntry], raw_path: str) -> Tuple[int, list]:
68-
"""
69-
Tìm vị trí xuất hiện cuối cùng của thư mục cha trong file gốc
70-
để chèn item mới vào ngay bên cạnh/dưới nó. Đồng thời trả về permission kế thừa.
71-
"""
7273
tmp_path = os.path.dirname(raw_path)
7374

7475
while tmp_path and tmp_path != "/":
@@ -77,24 +78,24 @@ def find_insert_index(entries: List[ContextEntry], raw_path: str) -> Tuple[int,
7778
found_perm = None
7879

7980
for idx, (path, perm) in enumerate(entries):
80-
# Khớp với đường dẫn gốc hoặc dạng đã escape
81-
if path == tmp_path or path == tmp_selinux or path.startswith(tmp_selinux + "/"):
81+
# So sánh linh hoạt cả dạng raw lẫn dạng đã escape regex
82+
clean_entry_path = path.replace("\\.", ".").replace("\\", "")
83+
if path in (tmp_path, tmp_selinux) or clean_entry_path == tmp_path or path.startswith(tmp_selinux + "/"):
8284
last_idx = idx
83-
found_perm = perm
85+
found_perm = clean_permission(perm)
8486

8587
if last_idx is not None:
8688
return last_idx + 1, found_perm
8789

8890
tmp_path = os.path.dirname(tmp_path)
8991

90-
# Nếu không tìm thấy cha, chèn vào cuối file
9192
return len(entries), None
9293

9394

9495
def context_patch(fs_entries: List[ContextEntry], filename: list) -> Tuple[List[ContextEntry], int]:
9596
entries = list(fs_entries)
9697

97-
# Tập hợp các đường dẫn đã tồn tại để tránh chèn trùng
98+
# Chuẩn hóa tập hợp kiểm tra trùng lặp
9899
existing_paths = {path for path, _ in entries}
99100
permission_d = _default_permission(entries)
100101

@@ -111,23 +112,19 @@ def context_patch(fs_entries: List[ContextEntry], filename: list) -> Tuple[List[
111112

112113
selinux_path = str_to_selinux(raw_path)
113114

114-
# Bỏ qua nếu dòng đã tồn tại trong file gốc hoặc đã được thêm trước đó
115115
if raw_path in existing_paths or selinux_path in existing_paths or selinux_path in seen_new:
116116
continue
117117

118-
# Xử lý quy tắc đè thủ công trong fix_permission
119118
if raw_path in fix_permission:
120119
permission = fix_permission[raw_path]
121120
insert_at, _ = find_insert_index(entries, raw_path)
122121
elif selinux_path in fix_permission:
123122
permission = fix_permission[selinux_path]
124123
insert_at, _ = find_insert_index(entries, raw_path)
125124
else:
126-
# Tìm vị trí thích hợp (sau thư mục cha) và lấy permission kế thừa
127125
insert_at, parent_perm = find_insert_index(entries, raw_path)
128126
permission = parent_perm if parent_perm else permission_d
129127

130-
# Chèn trực tiếp vào vị trí tìm được mà KHÔNG làm xáo trộn các dòng khác
131128
entries.insert(insert_at, (selinux_path, permission))
132129
seen_new.add(selinux_path)
133130
existing_paths.add(selinux_path)

.github/module/termux/py/fspatch.py

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def scanfs(fs_path: str) -> List[FsEntry]:
3333

3434
def scan_dir(folder: str):
3535
folder = os.path.abspath(folder)
36-
base = os.path.basename(os.path.normpath(folder))
36+
base = os.path.basename(folder)
3737
yield base
3838
yield "/"
3939
yield f"{base}/lost+found"
@@ -62,6 +62,8 @@ def islink(file_path: str) -> Optional[str]:
6262

6363
def make_config(i: str, filepath: str) -> List[str]:
6464
path_norm = i.replace("\\", "/")
65+
66+
# 1. Thư mục
6567
if os.path.isdir(filepath):
6668
uid = "0"
6769
gid = (
@@ -72,9 +74,11 @@ def make_config(i: str, filepath: str) -> List[str]:
7274
mode = "0755"
7375
return [uid, gid, mode]
7476

77+
# 2. File không tồn tại thực tế
7578
if not os.path.exists(filepath):
7679
return ["0", "0", "0755"]
7780

81+
# 3. Liên kết mềm (Symlink)
7882
link = islink(filepath)
7983
if link:
8084
uid = "0"
@@ -93,40 +97,23 @@ def make_config(i: str, filepath: str) -> List[str]:
9397

9498
return [uid, gid, mode, link]
9599

100+
# 4. File thực thi trong bin/xbin
96101
if "/bin/" in path_norm or "/xbin/" in path_norm:
97102
uid = "0"
98103
gid = (
99104
"2000"
100105
if path_norm.startswith(("system/bin/", "system/xbin/", "vendor/bin/"))
101106
else "0"
102107
)
103-
mode = "0755"
104-
105-
if path_norm.endswith(".sh"):
106-
mode = "0750"
107-
else:
108-
for s in [
109-
"/bin/su",
110-
"/xbin/su",
111-
"disable_selinux.sh",
112-
"daemon",
113-
"ext/.su",
114-
"install-recovery",
115-
"installed_su",
116-
"bin/rw-system.sh",
117-
"bin/getSPL",
118-
]:
119-
if s in path_norm:
120-
mode = "0755"
121-
break
122-
108+
mode = "0750" if path_norm.endswith(".sh") else "0755"
123109
return [uid, gid, mode]
124110

111+
# 5. File thông thường
125112
return ["0", "0", "0644"]
126113

127114

128115
def find_insert_index(entries: List[FsEntry], new_path: str) -> int:
129-
norm = new_path.replace("\\", "/")
116+
norm = new_path.replace("\\", "/").strip("/")
130117
parts = [p for p in norm.split("/") if p]
131118
if len(parts) <= 1:
132119
return len(entries)
@@ -137,24 +124,13 @@ def find_insert_index(entries: List[FsEntry], new_path: str) -> int:
137124

138125
last_idx = None
139126
for idx, (path, _) in enumerate(entries):
140-
p = path.replace("\\", "/")
127+
p = path.replace("\\", "/").strip("/")
141128
if p == prefix or p.startswith(prefix_slash):
142129
last_idx = idx
143130

144131
if last_idx is not None:
145132
return last_idx + 1
146133

147-
top = parts[0]
148-
top_slash = top + "/"
149-
last_idx = None
150-
for idx, (path, _) in enumerate(entries):
151-
p = path.replace("\\", "/")
152-
if p == top or p.startswith(top_slash):
153-
last_idx = idx
154-
155-
if last_idx is not None:
156-
return last_idx + 1
157-
158134
return len(entries)
159135

160136

@@ -165,20 +141,23 @@ def fs_patch(fs_entries: List[FsEntry], dir_path: str) -> Tuple[List[FsEntry], i
165141
new_add = 0
166142
print("FsPatcher: Load origin %d entries" % len(entries))
167143

168-
base = os.path.basename(os.path.normpath(os.path.abspath(dir_path)))
144+
target_dir = os.path.abspath(dir_path)
145+
base = os.path.basename(target_dir)
169146

170-
for i in scan_dir(os.path.abspath(dir_path)):
147+
for i in scan_dir(target_dir):
171148
if not i.isprintable():
172149
i = "".join(c if c.isprintable() else "*" for c in i)
173150

174-
# Không tự sinh dòng root như: vendor 0 0 0755
175151
if i == base and i not in existing:
176152
continue
177153

178154
if i in existing or i in seen_new:
179155
continue
180156

181-
filepath = os.path.abspath(os.path.join(dir_path, "..", i))
157+
# Tính đường dẫn thực tế chính xác trên ổ đĩa
158+
rel_path = i[len(base) + 1:] if i.startswith(base + "/") else i
159+
filepath = os.path.abspath(os.path.join(target_dir, rel_path))
160+
182161
config = make_config(i, filepath)
183162

184163
insert_at = find_insert_index(entries, i)

app/src/main/assets/home/bin/repack_img

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ if [[ "$partition" =~ ^(erofs|f2fs|ext)$ ]]; then
319319
[ "$img_size" ] && text_sizes="$img_size" || text_sizes=$(stat -c %s "$saved")
320320
echo "$sizes_text: ${saved##*/} $(coverbyte $text_sizes) ($text_sizes)"
321321
echo
322-
if [ "$partition" == "ext4" ]; then
322+
if [ "$partition" == "ext" ]; then
323323
tune2fs -l "$saved" | awk '/Free blocks:/{f=$3}/Block size:/{b=$3}END{print "Free: " int(f*b/1048576) " MB"}'
324324
echo
325325
fi

app/src/main/java/com/omarea/krscript/ui/DialogLogFragment.kt

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import android.view.KeyEvent
1717
import android.view.LayoutInflater
1818
import android.view.View
1919
import android.view.ViewGroup
20+
import android.view.ViewTreeObserver
2021
import android.view.WindowManager
2122
import android.view.inputmethod.EditorInfo
2223
import android.view.inputmethod.InputMethodManager
@@ -610,18 +611,28 @@ class DialogLogFragment : DialogFragment() {
610611
logView.append(chunk)
611612
}
612613

613-
// Tối ưu cuộn ScrollView xuống cuối
614-
// Dùng findScrollViewAncestor() thay vì cast trực tiếp logView.parent, vì khi tắt soft wrap
615-
// logView được bọc thêm trong 1 HorizontalScrollView trung gian.
614+
// Tối ưu cuộn ScrollView xuống cuối.
615+
// Dùng OnPreDrawListener thay vì gọi fullScroll() ngay lập tức: onPreDraw() được gọi
616+
// ngay TRƯỚC khi frame kế tiếp được vẽ, tức là chắc chắn measure()/layout() cho nội
617+
// dung mới (kể cả khi setText() toàn bộ do \r ghi đè dòng) đã hoàn tất. Nhờ vậy
618+
// fullScroll() luôn tính đúng theo chiều cao mới nhất, không còn bị "nhảy lên đầu"
619+
// do dùng số đo cũ (stale) như khi gọi trực tiếp ngay sau logView.text = chunk.
616620
findScrollViewAncestor(logView)?.let { scrollView ->
617-
scrollView.fullScroll(ScrollView.FOCUS_DOWN)
618-
619-
// Giữ focus thông minh không cần lồng post{} nhiều tầng
620-
val inputRow = inputRowRef.get()
621-
val input = shellInputRef.get()
622-
if (inputRow != null && inputRow.visibility == View.VISIBLE && input != null) {
623-
if (!input.isFocused) input.requestFocus()
624-
}
621+
if (!scrollView.isAttachedToWindow) return@let
622+
scrollView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
623+
override fun onPreDraw(): Boolean {
624+
scrollView.viewTreeObserver.removeOnPreDrawListener(this)
625+
scrollView.fullScroll(ScrollView.FOCUS_DOWN)
626+
627+
// Giữ focus thông minh không cần lồng post{} nhiều tầng
628+
val inputRow = inputRowRef.get()
629+
val input = shellInputRef.get()
630+
if (inputRow != null && inputRow.visibility == View.VISIBLE && input != null) {
631+
if (!input.isFocused) input.requestFocus()
632+
}
633+
return true
634+
}
635+
})
625636
}
626637
}
627638
}
@@ -672,4 +683,4 @@ class DialogLogFragment : DialogFragment() {
672683
return fragment
673684
}
674685
}
675-
}
686+
}

0 commit comments

Comments
 (0)