Conversation
Contributor
审阅者指南将 Magisk 模块重构为使用单一原生 新版 post-fs-data CSC 处理流水线的时序图sequenceDiagram
participant AndroidInit as AndroidInit
participant post_fs_data_sh as post_fs_data_sh
participant csc_tool as csc_tool
participant FileSystem as FileSystem
AndroidInit->>post_fs_data_sh: invoke post-fs-data.sh
activate post_fs_data_sh
post_fs_data_sh->>post_fs_data_sh: prepare_log()
post_fs_data_sh->>post_fs_data_sh: read_props(CSC, ARCH)
post_fs_data_sh->>post_fs_data_sh: compute TOOL path
post_fs_data_sh->>post_fs_data_sh: process_feature_file(csc, cscfeature.xml, csc.json)
activate post_fs_data_sh
post_fs_data_sh->>FileSystem: find_file(cscfeature.xml)
FileSystem-->>post_fs_data_sh: origin_path
post_fs_data_sh->>csc_tool: --decode origin_path decoded_csc
csc_tool-->>post_fs_data_sh: decoded_csc
post_fs_data_sh->>FileSystem: read CONFIG_PATH/csc.json
alt user_config exists
post_fs_data_sh->>csc_tool: --patch decoded_csc user_config patched_csc
csc_tool-->>post_fs_data_sh: patched_csc
else user_config missing
post_fs_data_sh->>post_fs_data_sh: copy decoded_csc to patched_csc
end
post_fs_data_sh->>csc_tool: --encode patched_csc final_csc
csc_tool-->>post_fs_data_sh: final_csc
post_fs_data_sh->>FileSystem: safe_mount(final_csc, origin_path)
post_fs_data_sh->>FileSystem: restorecon(origin_path)
deactivate post_fs_data_sh
post_fs_data_sh->>post_fs_data_sh: process_feature_file(carrier, customer_carrier_feature.json, carrier.json)
activate post_fs_data_sh
post_fs_data_sh->>FileSystem: find_file(customer_carrier_feature.json)
FileSystem-->>post_fs_data_sh: origin_path
post_fs_data_sh->>csc_tool: --decode origin_path decoded_carrier
csc_tool-->>post_fs_data_sh: decoded_carrier
post_fs_data_sh->>FileSystem: read CONFIG_PATH/carrier.json
alt user_config exists
post_fs_data_sh->>csc_tool: --patch decoded_carrier user_config patched_carrier
csc_tool-->>post_fs_data_sh: patched_carrier
else user_config missing
post_fs_data_sh->>post_fs_data_sh: copy decoded_carrier to patched_carrier
end
post_fs_data_sh->>csc_tool: --encode patched_carrier final_carrier
csc_tool-->>post_fs_data_sh: final_carrier
post_fs_data_sh->>FileSystem: safe_mount(final_carrier, origin_path)
post_fs_data_sh->>FileSystem: restorecon(origin_path)
deactivate post_fs_data_sh
post_fs_data_sh->>post_fs_data_sh: process_feature_file(ff, floating_feature.xml, ff.json)
activate post_fs_data_sh
post_fs_data_sh->>FileSystem: find_file(floating_feature.xml)
alt file_not_found_in_optics
post_fs_data_sh->>FileSystem: use /etc/floating_feature.xml as origin_path
end
post_fs_data_sh->>FileSystem: copy origin_path to decoded_ff
post_fs_data_sh->>FileSystem: read CONFIG_PATH/ff.json
alt user_config exists
post_fs_data_sh->>csc_tool: --patch decoded_ff user_config patched_ff
csc_tool-->>post_fs_data_sh: patched_ff
else user_config missing
post_fs_data_sh->>post_fs_data_sh: copy decoded_ff to patched_ff
end
post_fs_data_sh->>FileSystem: safe_mount(patched_ff, origin_path)
post_fs_data_sh->>FileSystem: restorecon(origin_path)
deactivate post_fs_data_sh
deactivate post_fs_data_sh
post_fs_data_sh-->>AndroidInit: CSC customization ready
新版 WebUI CSC 编辑器的类型与关系类图classDiagram
class App {
+FilterMode filterMode
+CSCEntry[] entries
+Record~string_string~ originEntries
+void loadData()
+void syncToDisk(newEntries)
+void toggleEnable(key)
+void removeEntry(key)
+void openModal(key, modified, originValue)
+void confirmModal()
}
class CSCEntry {
+string command
+string key
+string value
+string desc
+boolean enabled
}
class FilterModeEnum {
<<enumeration>>
ALL
ENABLED
DISABLED
UNSET
}
class KernelSUExec {
+Promise~ExecResult~ exec(command)
+void toast(message)
}
class FileConfig {
+string label
+string name
+string decoded
}
App --> CSCEntry : manages
App --> FilterModeEnum : uses
App --> KernelSUExec : calls_exec_and_toast
App --> FileConfig : selects_currentFile
class Paths {
+string CONFIG_PATH
+string MODULE_PATH
}
App --> Paths : builds_IO_paths
文件级变更
提示与命令与 Sourcery 交互
自定义你的体验访问你的控制台 以:
获取帮助Original review guide in EnglishReviewer's GuideRefactors the Magisk module to use a single native csc_tool plus a WebUI-based JSON configuration flow, replacing the previous multiple NDK binaries and text-based scripts, with updated post-fs-data/customize logic and CI/build pipelines to produce the new core and React WebUI. Sequence diagram for the new post-fs-data CSC processing pipelinesequenceDiagram
participant AndroidInit as AndroidInit
participant post_fs_data_sh as post_fs_data_sh
participant csc_tool as csc_tool
participant FileSystem as FileSystem
AndroidInit->>post_fs_data_sh: invoke post-fs-data.sh
activate post_fs_data_sh
post_fs_data_sh->>post_fs_data_sh: prepare_log()
post_fs_data_sh->>post_fs_data_sh: read_props(CSC, ARCH)
post_fs_data_sh->>post_fs_data_sh: compute TOOL path
post_fs_data_sh->>post_fs_data_sh: process_feature_file(csc, cscfeature.xml, csc.json)
activate post_fs_data_sh
post_fs_data_sh->>FileSystem: find_file(cscfeature.xml)
FileSystem-->>post_fs_data_sh: origin_path
post_fs_data_sh->>csc_tool: --decode origin_path decoded_csc
csc_tool-->>post_fs_data_sh: decoded_csc
post_fs_data_sh->>FileSystem: read CONFIG_PATH/csc.json
alt user_config exists
post_fs_data_sh->>csc_tool: --patch decoded_csc user_config patched_csc
csc_tool-->>post_fs_data_sh: patched_csc
else user_config missing
post_fs_data_sh->>post_fs_data_sh: copy decoded_csc to patched_csc
end
post_fs_data_sh->>csc_tool: --encode patched_csc final_csc
csc_tool-->>post_fs_data_sh: final_csc
post_fs_data_sh->>FileSystem: safe_mount(final_csc, origin_path)
post_fs_data_sh->>FileSystem: restorecon(origin_path)
deactivate post_fs_data_sh
post_fs_data_sh->>post_fs_data_sh: process_feature_file(carrier, customer_carrier_feature.json, carrier.json)
activate post_fs_data_sh
post_fs_data_sh->>FileSystem: find_file(customer_carrier_feature.json)
FileSystem-->>post_fs_data_sh: origin_path
post_fs_data_sh->>csc_tool: --decode origin_path decoded_carrier
csc_tool-->>post_fs_data_sh: decoded_carrier
post_fs_data_sh->>FileSystem: read CONFIG_PATH/carrier.json
alt user_config exists
post_fs_data_sh->>csc_tool: --patch decoded_carrier user_config patched_carrier
csc_tool-->>post_fs_data_sh: patched_carrier
else user_config missing
post_fs_data_sh->>post_fs_data_sh: copy decoded_carrier to patched_carrier
end
post_fs_data_sh->>csc_tool: --encode patched_carrier final_carrier
csc_tool-->>post_fs_data_sh: final_carrier
post_fs_data_sh->>FileSystem: safe_mount(final_carrier, origin_path)
post_fs_data_sh->>FileSystem: restorecon(origin_path)
deactivate post_fs_data_sh
post_fs_data_sh->>post_fs_data_sh: process_feature_file(ff, floating_feature.xml, ff.json)
activate post_fs_data_sh
post_fs_data_sh->>FileSystem: find_file(floating_feature.xml)
alt file_not_found_in_optics
post_fs_data_sh->>FileSystem: use /etc/floating_feature.xml as origin_path
end
post_fs_data_sh->>FileSystem: copy origin_path to decoded_ff
post_fs_data_sh->>FileSystem: read CONFIG_PATH/ff.json
alt user_config exists
post_fs_data_sh->>csc_tool: --patch decoded_ff user_config patched_ff
csc_tool-->>post_fs_data_sh: patched_ff
else user_config missing
post_fs_data_sh->>post_fs_data_sh: copy decoded_ff to patched_ff
end
post_fs_data_sh->>FileSystem: safe_mount(patched_ff, origin_path)
post_fs_data_sh->>FileSystem: restorecon(origin_path)
deactivate post_fs_data_sh
deactivate post_fs_data_sh
post_fs_data_sh-->>AndroidInit: CSC customization ready
Class diagram for new WebUI CSC editor types and relationshipsclassDiagram
class App {
+FilterMode filterMode
+CSCEntry[] entries
+Record~string_string~ originEntries
+void loadData()
+void syncToDisk(newEntries)
+void toggleEnable(key)
+void removeEntry(key)
+void openModal(key, modified, originValue)
+void confirmModal()
}
class CSCEntry {
+string command
+string key
+string value
+string desc
+boolean enabled
}
class FilterModeEnum {
<<enumeration>>
ALL
ENABLED
DISABLED
UNSET
}
class KernelSUExec {
+Promise~ExecResult~ exec(command)
+void toast(message)
}
class FileConfig {
+string label
+string name
+string decoded
}
App --> CSCEntry : manages
App --> FilterModeEnum : uses
App --> KernelSUExec : calls_exec_and_toast
App --> FileConfig : selects_currentFile
class Paths {
+string CONFIG_PATH
+string MODULE_PATH
}
App --> Paths : builds_IO_paths
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Hey - 我发现了 5 个问题,并留下了一些整体性反馈:
- 在
post-fs-data.sh中,当缺少$TOOL时,你只记录了一个致命错误日志但仍继续执行;建议要么尽早退出(或实现真正的回退逻辑),以避免后续 decode/patch 步骤默默失败。 csc_tool.c中有多处内存分配在所有错误路径上都没有被释放(例如在patch_xml/patch_json中解析失败的分支),并且有些read_file_to_memory的结果在提前返回时也没有释放;收紧这些清理逻辑可以提升多次调用时的健壮性。csc_tool中的 XML/JSON 检测依赖strstr(argv[2], ".json"),这可能会错误识别路径中其他位置包含.json的文件名;可以考虑使用更严格的后缀检查,或使用显式的模式标志来区分 JSON 和 XML 输入。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `post-fs-data.sh`, when `$TOOL` is missing you only log a fatal error but continue execution; consider exiting early (or implementing the actual fallback) to avoid subsequent decode/patch steps silently failing.
- `csc_tool.c` has several allocations that are not freed on all error paths (e.g., in `patch_xml`/`patch_json` when parsing fails) and some `read_file_to_memory` results are used without freeing on early returns; tightening up cleanup logic would improve robustness for repeated invocations.
- The XML/JSON detection in `csc_tool` relies on `strstr(argv[2], ".json")`, which may misclassify paths with `.json` elsewhere in the name; consider using a stricter suffix check or explicit mode flag to distinguish JSON vs XML inputs.
## Individual Comments
### Comment 1
<location path="src/core/jni/csc_tool.c" line_range="231-233" />
<code_context>
+ }
+ FILE *f = fopen(argv[3], "wb"); fwrite(enc, 1, cs, f); fclose(f);
+ free(d); free(comp); free(enc);
+ } else if (strcmp(argv[1], "--patch") == 0 && argc == 5) {
+ if (strstr(argv[2], ".json")) patch_json(argv[2], argv[3], argv[4]);
+ else patch_xml(argv[2], argv[3], argv[4]);
+ }
+ return 0;
</code_context>
<issue_to_address>
**issue (bug_risk):** 使用 `strstr(argv[2], ".json")` 来区分 JSON 和 XML 比较脆弱,而且当前和调用端的路径约定不一致。
在 `--patch` 分支中,仅根据 `argv[2]` 是否包含 `.json` 来决定路由。然而,`post-fs-data.sh` 传入的是 `decoded_$label`(无扩展名),因此诸如运营商配置这样的 JSON 输入会被错误地走到 `patch_xml`。即使未来更新了调用端路径,仅依赖文件名扩展名也依旧不够可靠。
可以考虑:
- 根据首个非空白字符检测格式(`{` / `[` → JSON,`<` → XML),或者
- 添加显式的 `--json` / `--xml` 标志,而不是从路径中推断。
这样可以避免在路径或命名约定改变时发生错误路由。
</issue_to_address>
### Comment 2
<location path="src/core/jni/csc_tool.c" line_range="130-134" />
<code_context>
+ }
+
+ cJSON* item;
+ cJSON_ArrayForEach(item, configs) {
+ const char* k = cJSON_GetObjectItem(item, "key")->valuestring;
+ const char* v = cJSON_GetObjectItem(item, "value") ? cJSON_GetObjectItem(item, "value")->valuestring : "";
+ const char* cmd = cJSON_GetObjectItem(item, "command")->valuestring;
+ if (!cJSON_IsTrue(cJSON_GetObjectItem(item, "enabled"))) continue;
+
+ int found = -1;
</code_context>
<issue_to_address>
**issue (bug_risk):** 当前补丁逻辑假设所有预期的 JSON 键都存在;缺失或格式错误的条目会导致崩溃。
在 `patch_xml` 和 `patch_json` 中,你通过直接解引用 `cJSON_GetObjectItem(...)` 的返回值来访问 `key`、`value`、`command` 和 `enabled` 等字段。对于格式错误或用户修改过的配置(字段缺失、类型错误、拼写错误等),`cJSON_GetObjectItem` 可能返回 `NULL`,在此基础上解引用或对其调用 `cJSON_IsTrue` 会导致未定义行为甚至崩溃。
请先将 `cJSON_GetObjectItem` 的结果保存到局部变量中,检查其合法性(`!= NULL`、`cJSON_IsString`、`cJSON_IsBool` 等),然后对非法条目进行跳过或记录日志,而不是假定所有键都存在且类型正确。
</issue_to_address>
### Comment 3
<location path="module_files/post-fs-data.sh" line_range="121-123" />
<code_context>
+prepare_log
+
+# 检查工具是否存在
+if [ ! -f "$TOOL" ]; then
+ log "致命错误: 未在 $TOOL 找到核心工具"
+ # 回退到尝试使用老的二进制(如果存在)或退出
fi
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 当找不到 csc_tool 时缺少回退/退出行为,使得错误处理不完整。
目前脚本在 `$TOOL` 缺失时会记录一个致命错误,但之后仍继续执行,并在后面调用 `process_feature_file`,这会尝试运行一个不存在的二进制并产生让人困惑的错误。请实现实际的回退逻辑(如果有旧版本二进制可用则使用它),或立即终止(例如 `exit 1`),这样失败是确定的,日志与行为也更加一致。
建议实现:
```
prepare_log
# 检查工具是否存在
if [ ! -f "$TOOL" ]; then
log "致命错误: 未在 $TOOL 找到核心工具,终止执行"
exit 1
fi
MODDIR=${0%/*}
LOG_FILE="$MODDIR/log.txt"
```
- 确保在这个检查之前已经定义好 `TOOL` 变量(例如指向期望的 csc_tool 二进制)。如果目前是在脚本后面才设置,请把赋值移到 `prepare_log` 和存在性检查之前。
- 如果以后决定对旧版二进制实现真实的回退逻辑,可以将 `exit 1` 分支替换为检查旧版路径的逻辑(例如 `[ -x "$LEGACY_TOOL" ] && TOOL="$LEGACY_TOOL" || exit 1`),同时保持日志输出的一致性。
</issue_to_address>
### Comment 4
<location path="src/core/jni/csc_tool.c" line_range="74-78" />
<code_context>
+ return strcmp(((Feature*)a)->key, ((Feature*)b)->key);
+}
+
+void patch_xml(const char* xml_path, const char* config_json, const char* dest_path) {
+ size_t xml_size, json_size;
+ char* xml_content = read_file_to_memory(xml_path, &xml_size);
+ char* json_content = read_file_to_memory(config_json, &json_size);
+ if (!xml_content || !json_content) return;
+
+ cJSON* configs = cJSON_Parse(json_content);
</code_context>
<issue_to_address>
**nitpick (bug_risk):** `patch_xml` / `patch_json` 中的提前返回会泄漏已分配的缓冲区;即便是短生命周期工具,也可以很容易整理好这部分逻辑。
`patch_xml` 和 `patch_json` 通过 `read_file_to_memory` 分配了 `xml_content` / `json_content`,但某些错误路径在返回前没有释放它们(例如 `if (!xml_content || !json_content) return;`,以及 `patch_json` 中类似的代码)。请确保所有提前返回的路径都会释放已经成功分配的缓冲区,或者通过统一的 `cleanup:` 标签集中处理清理逻辑再返回。
</issue_to_address>
### Comment 5
<location path="src/core/jni/csc_tool.c" line_range="207" />
<code_context>
+
+// --- Main ---
+
+int main(int argc, char **argv) {
+ if (argc < 4) return 1;
+ if (strcmp(argv[1], "--decode") == 0) {
</code_context>
<issue_to_address>
**issue (complexity):** 建议将编码/解码逻辑以及 XML/JSON 补丁流程拆分为一些可复用的小工具函数,并使用 `qsort` 对 JSON 排序,这样 `main` 和补丁函数只需要编排高层步骤。
在不改变行为的前提下,你可以通过以下方式减少复杂度和重复:
### 1. 将编码/解码核心逻辑抽取到辅助函数中
目前编码/解码位运算逻辑直接写在 `main` 里。可以将其移动到专用函数中;`main` 只负责 I/O 和模式选择。
```c
static void decode_buffer(const unsigned char *in, size_t len, unsigned char *out) {
for (size_t i = 0; i < len; i++) {
unsigned int b = in[i];
int s = shifts[i % num_shifts];
out[i] = (((b << s) | (b >> (8 - s))) & 0xFF) ^ salts[i % num_salts];
}
}
static void encode_buffer(const unsigned char *in, size_t len, unsigned char *out) {
for (size_t i = 0; i < len; i++) {
unsigned int x = (in[i] ^ salts[i % num_salts]) & 0xFF;
int s = shifts[i % num_shifts];
out[i] = ((x >> s) | (x << (8 - s))) & 0xFF;
}
}
```
然后 `main` 可以简化为:
```c
} else if (strcmp(argv[1], "--decode") == 0) {
size_t sz; unsigned char *d = (unsigned char*)read_file_to_memory(argv[2], &sz);
if (!d) return 1;
unsigned char *dec = malloc(sz);
decode_buffer(d, sz, dec);
decompress_gzip(dec, sz, argv[3]);
free(d); free(dec);
} else if (strcmp(argv[1], "--encode") == 0) {
size_t sz; unsigned char *d = (unsigned char*)read_file_to_memory(argv[2], &sz);
if (!d) return 1;
unsigned char *comp; size_t cs;
compress_gzip(d, sz, &comp, &cs);
unsigned char *enc = malloc(cs);
encode_buffer(comp, cs, enc);
FILE *f = fopen(argv[3], "wb"); fwrite(enc, 1, cs, f); fclose(f);
free(d); free(comp); free(enc);
}
```
这样也能将 `salts` / `shifts` / 魔数隔离在编码层中。
---
### 2. 将 XML 补丁流程拆分为更小的步骤
`patch_xml` 目前在一个函数里完成:读取 XML、查找块、解析 feature、应用配置、排序、写回。可以拆分为多个小的辅助函数,使每一部分都更易于理解和测试。
示例结构:
```c
static int find_feature_block(char *xml, const char **active_tag,
char **block_start, char **block_end) {
const char* tag_names[] = {"FeatureSet", "SecFloatingFeatureSet"};
for (int i = 0; i < 2; i++) {
char s_tag[128], e_tag[128];
sprintf(s_tag, "<%s>", tag_names[i]);
sprintf(e_tag, "</%s>", tag_names[i]);
char *s = strstr(xml, s_tag);
if (!s) continue;
s += strlen(s_tag);
char *e = strstr(s, e_tag);
if (!e) continue;
*active_tag = tag_names[i];
*block_start = s;
*block_end = e;
return 0;
}
return -1;
}
static int parse_features(char *block_start, char *block_end,
Feature *features, int *count) {
char *p = block_start;
*count = 0;
while (p < block_end && *count < MAX_FEATURES) {
/* existing parsing logic moved here */
}
return 0;
}
```
这样 `patch_xml` 就主要是编排逻辑:
```c
void patch_xml(const char* xml_path, const char* config_json, const char* dest_path) {
/* read xml/json ... */
const char *active_tag = NULL;
char *s_ptr = NULL, *e_ptr = NULL;
if (find_feature_block(xml_content, &active_tag, &s_ptr, &e_ptr) != 0) {
fprintf(stderr, "Error: No FeatureSet found\n");
/* free + return */
}
Feature *features = malloc(sizeof(Feature) * MAX_FEATURES);
int count = 0;
parse_features(s_ptr, e_ptr, features, &count);
apply_xml_config(configs, features, &count); // extracted from existing loop
qsort(features, count, sizeof(Feature), compare_features);
write_patched_xml(dest_path, xml_content, xml_size, s_ptr, e_ptr, features, count);
}
```
你几乎可以直接把现有代码挪进这些辅助函数,改动很少;行为保持不变,但主函数会更短。
---
### 3. 让 JSON 补丁结构与 XML 补丁结构对齐
类似地,`patch_json` 目前在一个地方做了很多事。可以抽取“加载并解析”和“应用配置”两个步骤,使其结构与 XML 更加对称:
```c
static int load_json_pair(const char *src_path, const char *cfg_path,
cJSON **src_root, cJSON **cfg_root) {
size_t s_sz, c_sz;
char *s_d = read_file_to_memory(src_path, &s_sz);
char *c_d = read_file_to_memory(cfg_path, &c_sz);
if (!s_d || !c_d) { free(s_d); free(c_d); return -1; }
*src_root = cJSON_Parse(s_d);
*cfg_root = cJSON_Parse(c_d);
free(s_d); free(c_d);
return (*src_root && *cfg_root) ? 0 : -1;
}
static void apply_json_config(cJSON *feat, cJSON *cfg_root) {
cJSON *it;
cJSON_ArrayForEach(it, cfg_root) {
/* move existing loop body here */
}
}
void patch_json(const char* src, const char* cfg, const char* dest) {
cJSON *s_r = NULL, *c_r = NULL;
if (load_json_pair(src, cfg, &s_r, &c_r) != 0) return;
cJSON *customer = cJSON_GetObjectItem(s_r, "customer");
cJSON *feat = cJSON_GetObjectItem(cJSON_GetArrayItem(customer, 0), "feature");
apply_json_config(feat, c_r);
sort_json(feat);
/* write + cleanup */
}
```
这样可以让 JSON/XML “补丁步骤”在概念上保持一致,从而在后续修改行为时减轻心智负担。
---
### 4. 用 `qsort` 替换 `sort_json` 中的冒泡排序
你已经在 feature 排序中使用了 `qsort`;可以复用它来对 JSON 排序,而不必维护一个自定义冒泡排序实现:
```c
static int compare_cjson_object(const void *a, const void *b) {
const cJSON *ca = *(const cJSON**)a;
const cJSON *cb = *(const cJSON**)b;
return strcmp(ca->string, cb->string);
}
void sort_json(cJSON *obj) {
int n = cJSON_GetArraySize(obj);
if (n <= 1) return;
cJSON **nodes = malloc(sizeof(cJSON*) * n);
cJSON *c = obj->child;
for (int i = 0; i < n; i++) { nodes[i] = c; c = c->next; }
qsort(nodes, n, sizeof(cJSON*), compare_cjson_object);
obj->child = nodes[0];
nodes[0]->prev = NULL;
for (int i = 0; i < n - 1; i++) {
nodes[i]->next = nodes[i+1];
nodes[i+1]->prev = nodes[i];
}
nodes[n-1]->next = NULL;
free(nodes);
}
```
这样可以移除自定义排序逻辑,并与 feature 排序的方式保持一致。
---
这些改动在保持现有功能不变的前提下,将职责拆分为更加聚焦的单元,使这个单文件更容易浏览和修改,也更安全。
</issue_to_address>帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've found 5 issues, and left some high level feedback:
- In
post-fs-data.sh, when$TOOLis missing you only log a fatal error but continue execution; consider exiting early (or implementing the actual fallback) to avoid subsequent decode/patch steps silently failing. csc_tool.chas several allocations that are not freed on all error paths (e.g., inpatch_xml/patch_jsonwhen parsing fails) and someread_file_to_memoryresults are used without freeing on early returns; tightening up cleanup logic would improve robustness for repeated invocations.- The XML/JSON detection in
csc_toolrelies onstrstr(argv[2], ".json"), which may misclassify paths with.jsonelsewhere in the name; consider using a stricter suffix check or explicit mode flag to distinguish JSON vs XML inputs.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `post-fs-data.sh`, when `$TOOL` is missing you only log a fatal error but continue execution; consider exiting early (or implementing the actual fallback) to avoid subsequent decode/patch steps silently failing.
- `csc_tool.c` has several allocations that are not freed on all error paths (e.g., in `patch_xml`/`patch_json` when parsing fails) and some `read_file_to_memory` results are used without freeing on early returns; tightening up cleanup logic would improve robustness for repeated invocations.
- The XML/JSON detection in `csc_tool` relies on `strstr(argv[2], ".json")`, which may misclassify paths with `.json` elsewhere in the name; consider using a stricter suffix check or explicit mode flag to distinguish JSON vs XML inputs.
## Individual Comments
### Comment 1
<location path="src/core/jni/csc_tool.c" line_range="231-233" />
<code_context>
+ }
+ FILE *f = fopen(argv[3], "wb"); fwrite(enc, 1, cs, f); fclose(f);
+ free(d); free(comp); free(enc);
+ } else if (strcmp(argv[1], "--patch") == 0 && argc == 5) {
+ if (strstr(argv[2], ".json")) patch_json(argv[2], argv[3], argv[4]);
+ else patch_xml(argv[2], argv[3], argv[4]);
+ }
+ return 0;
</code_context>
<issue_to_address>
**issue (bug_risk):** Using `strstr(argv[2], ".json")` to distinguish JSON from XML is brittle and currently inconsistent with caller paths.
In the `--patch` branch, routing is based solely on whether `argv[2]` contains `.json`. However, `post-fs-data.sh` passes `decoded_$label` (no extension), so JSON inputs like carrier config will incorrectly go through `patch_xml`. Even if caller paths are updated, relying on filename extensions is still fragile.
Consider either:
- detecting format from the first non‑whitespace character (`{`/`[` → JSON, `<` → XML), or
- adding an explicit `--json` / `--xml` flag instead of inferring from the path.
This avoids misrouting when paths or naming conventions change.
</issue_to_address>
### Comment 2
<location path="src/core/jni/csc_tool.c" line_range="130-134" />
<code_context>
+ }
+
+ cJSON* item;
+ cJSON_ArrayForEach(item, configs) {
+ const char* k = cJSON_GetObjectItem(item, "key")->valuestring;
+ const char* v = cJSON_GetObjectItem(item, "value") ? cJSON_GetObjectItem(item, "value")->valuestring : "";
+ const char* cmd = cJSON_GetObjectItem(item, "command")->valuestring;
+ if (!cJSON_IsTrue(cJSON_GetObjectItem(item, "enabled"))) continue;
+
+ int found = -1;
</code_context>
<issue_to_address>
**issue (bug_risk):** Patch logic assumes all expected JSON keys exist; missing or malformed entries can cause crashes.
In both `patch_xml` and `patch_json`, fields like `key`, `value`, `command`, and `enabled` are accessed via direct dereferences of `cJSON_GetObjectItem(...)` results. For malformed or user-edited configs (missing fields, wrong types, typos), `cJSON_GetObjectItem` can return `NULL`, leading to undefined behavior or crashes when you dereference or call `cJSON_IsTrue` on it.
Please first assign `cJSON_GetObjectItem` results to locals, validate them (`!= NULL`, `cJSON_IsString`, `cJSON_IsBool`, etc.), and then either skip or log invalid entries instead of assuming all keys are present and well-typed.
</issue_to_address>
### Comment 3
<location path="module_files/post-fs-data.sh" line_range="121-123" />
<code_context>
+prepare_log
+
+# 检查工具是否存在
+if [ ! -f "$TOOL" ]; then
+ log "致命错误: 未在 $TOOL 找到核心工具"
+ # 回退到尝试使用老的二进制(如果存在)或退出
fi
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Missing fallback/exit behavior if csc_tool is not found makes the error handling incomplete.
Right now the script logs a fatal error when `$TOOL` is missing but then continues and later calls `process_feature_file`, which will try to run a non‑existent binary and produce confusing errors. Please either implement the actual fallback (use the legacy binary if available) or abort immediately (e.g. `exit 1`) so the failure is deterministic and the logs match the behavior.
Suggested implementation:
```
prepare_log
# 检查工具是否存在
if [ ! -f "$TOOL" ]; then
log "致命错误: 未在 $TOOL 找到核心工具,终止执行"
exit 1
fi
MODDIR=${0%/*}
LOG_FILE="$MODDIR/log.txt"
```
- Ensure the `TOOL` variable is defined **before** this check (e.g. pointing to the expected csc_tool binary). If it's currently set later in the script, move its assignment above `prepare_log` and this existence check.
- If you later decide to implement a real fallback to a legacy binary, replace the `exit 1` branch with logic that checks for the legacy path (e.g. `[ -x "$LEGACY_TOOL" ] && TOOL="$LEGACY_TOOL" || exit 1`) while keeping the logging consistent.
</issue_to_address>
### Comment 4
<location path="src/core/jni/csc_tool.c" line_range="74-78" />
<code_context>
+ return strcmp(((Feature*)a)->key, ((Feature*)b)->key);
+}
+
+void patch_xml(const char* xml_path, const char* config_json, const char* dest_path) {
+ size_t xml_size, json_size;
+ char* xml_content = read_file_to_memory(xml_path, &xml_size);
+ char* json_content = read_file_to_memory(config_json, &json_size);
+ if (!xml_content || !json_content) return;
+
+ cJSON* configs = cJSON_Parse(json_content);
</code_context>
<issue_to_address>
**nitpick (bug_risk):** Early returns in patch_xml/patch_json leak allocated buffers; easy to tidy up even for a short-lived tool.
`patch_xml` and `patch_json` allocate `xml_content` / `json_content` via `read_file_to_memory`, but some error paths return without freeing them (e.g. `if (!xml_content || !json_content) return;`, and similar in `patch_json`). Please ensure all early returns free any successfully allocated buffers, or centralize cleanup via a common `cleanup:` label before returning.
</issue_to_address>
### Comment 5
<location path="src/core/jni/csc_tool.c" line_range="207" />
<code_context>
+
+// --- Main ---
+
+int main(int argc, char **argv) {
+ if (argc < 4) return 1;
+ if (strcmp(argv[1], "--decode") == 0) {
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the encoding/decoding logic and XML/JSON patch workflows into small reusable helpers and using qsort for JSON sorting so that main and patch functions only orchestrate high-level steps.
You can reduce complexity and duplication without changing behavior by:
### 1. Extract encode/decode core into helpers
Right now the encode/decode bit‑twiddling is inlined in `main`. Move it into dedicated functions; `main` then just orchestrates I/O and mode selection.
```c
static void decode_buffer(const unsigned char *in, size_t len, unsigned char *out) {
for (size_t i = 0; i < len; i++) {
unsigned int b = in[i];
int s = shifts[i % num_shifts];
out[i] = (((b << s) | (b >> (8 - s))) & 0xFF) ^ salts[i % num_salts];
}
}
static void encode_buffer(const unsigned char *in, size_t len, unsigned char *out) {
for (size_t i = 0; i < len; i++) {
unsigned int x = (in[i] ^ salts[i % num_salts]) & 0xFF;
int s = shifts[i % num_shifts];
out[i] = ((x >> s) | (x << (8 - s))) & 0xFF;
}
}
```
Then `main` becomes simpler:
```c
} else if (strcmp(argv[1], "--decode") == 0) {
size_t sz; unsigned char *d = (unsigned char*)read_file_to_memory(argv[2], &sz);
if (!d) return 1;
unsigned char *dec = malloc(sz);
decode_buffer(d, sz, dec);
decompress_gzip(dec, sz, argv[3]);
free(d); free(dec);
} else if (strcmp(argv[1], "--encode") == 0) {
size_t sz; unsigned char *d = (unsigned char*)read_file_to_memory(argv[2], &sz);
if (!d) return 1;
unsigned char *comp; size_t cs;
compress_gzip(d, sz, &comp, &cs);
unsigned char *enc = malloc(cs);
encode_buffer(comp, cs, enc);
FILE *f = fopen(argv[3], "wb"); fwrite(enc, 1, cs, f); fclose(f);
free(d); free(comp); free(enc);
}
```
This also isolates `salts`/`shifts`/magic into the encoding layer.
---
### 2. Decompose XML patching into smaller steps
`patch_xml` currently: read XML, find block, parse features, apply config, sort, write. Split into small helpers so each piece is easier to reason about and test.
Example structure:
```c
static int find_feature_block(char *xml, const char **active_tag,
char **block_start, char **block_end) {
const char* tag_names[] = {"FeatureSet", "SecFloatingFeatureSet"};
for (int i = 0; i < 2; i++) {
char s_tag[128], e_tag[128];
sprintf(s_tag, "<%s>", tag_names[i]);
sprintf(e_tag, "</%s>", tag_names[i]);
char *s = strstr(xml, s_tag);
if (!s) continue;
s += strlen(s_tag);
char *e = strstr(s, e_tag);
if (!e) continue;
*active_tag = tag_names[i];
*block_start = s;
*block_end = e;
return 0;
}
return -1;
}
static int parse_features(char *block_start, char *block_end,
Feature *features, int *count) {
char *p = block_start;
*count = 0;
while (p < block_end && *count < MAX_FEATURES) {
/* existing parsing logic moved here */
}
return 0;
}
```
Then `patch_xml` becomes mainly orchestration:
```c
void patch_xml(const char* xml_path, const char* config_json, const char* dest_path) {
/* read xml/json ... */
const char *active_tag = NULL;
char *s_ptr = NULL, *e_ptr = NULL;
if (find_feature_block(xml_content, &active_tag, &s_ptr, &e_ptr) != 0) {
fprintf(stderr, "Error: No FeatureSet found\n");
/* free + return */
}
Feature *features = malloc(sizeof(Feature) * MAX_FEATURES);
int count = 0;
parse_features(s_ptr, e_ptr, features, &count);
apply_xml_config(configs, features, &count); // extracted from existing loop
qsort(features, count, sizeof(Feature), compare_features);
write_patched_xml(dest_path, xml_content, xml_size, s_ptr, e_ptr, features, count);
}
```
You can literally move existing code into these helpers with minimal edits; behavior stays identical but the main function is short.
---
### 3. Mirror JSON patching structure with helpers
Similarly, `patch_json` does several things in one place. Extract “load and parse” and “apply config” so the structure parallels XML:
```c
static int load_json_pair(const char *src_path, const char *cfg_path,
cJSON **src_root, cJSON **cfg_root) {
size_t s_sz, c_sz;
char *s_d = read_file_to_memory(src_path, &s_sz);
char *c_d = read_file_to_memory(cfg_path, &c_sz);
if (!s_d || !c_d) { free(s_d); free(c_d); return -1; }
*src_root = cJSON_Parse(s_d);
*cfg_root = cJSON_Parse(c_d);
free(s_d); free(c_d);
return (*src_root && *cfg_root) ? 0 : -1;
}
static void apply_json_config(cJSON *feat, cJSON *cfg_root) {
cJSON *it;
cJSON_ArrayForEach(it, cfg_root) {
/* move existing loop body here */
}
}
void patch_json(const char* src, const char* cfg, const char* dest) {
cJSON *s_r = NULL, *c_r = NULL;
if (load_json_pair(src, cfg, &s_r, &c_r) != 0) return;
cJSON *customer = cJSON_GetObjectItem(s_r, "customer");
cJSON *feat = cJSON_GetObjectItem(cJSON_GetArrayItem(customer, 0), "feature");
apply_json_config(feat, c_r);
sort_json(feat);
/* write + cleanup */
}
```
This keeps JSON/XML “patch steps” conceptually aligned, which reduces mental overhead when you change behavior later.
---
### 4. Replace bubble sort in `sort_json` with `qsort`
You already use `qsort` for features; you can reuse it for JSON, instead of maintaining a custom bubble sort:
```c
static int compare_cjson_object(const void *a, const void *b) {
const cJSON *ca = *(const cJSON**)a;
const cJSON *cb = *(const cJSON**)b;
return strcmp(ca->string, cb->string);
}
void sort_json(cJSON *obj) {
int n = cJSON_GetArraySize(obj);
if (n <= 1) return;
cJSON **nodes = malloc(sizeof(cJSON*) * n);
cJSON *c = obj->child;
for (int i = 0; i < n; i++) { nodes[i] = c; c = c->next; }
qsort(nodes, n, sizeof(cJSON*), compare_cjson_object);
obj->child = nodes[0];
nodes[0]->prev = NULL;
for (int i = 0; i < n - 1; i++) {
nodes[i]->next = nodes[i+1];
nodes[i+1]->prev = nodes[i];
}
nodes[n-1]->next = NULL;
free(nodes);
}
```
This removes custom sorting logic and aligns with your feature sort pattern.
---
These changes keep functionality intact, but split responsibilities into focused units, making the single file easier to navigate and safer to modify.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Mzdyl
marked this pull request as draft
February 25, 2026 02:02
Mzdyl
marked this pull request as ready for review
February 25, 2026 02:53
Contributor
There was a problem hiding this comment.
Hey - 我发现了 3 个问题,并给出了一些整体性的反馈:
- 在
post-fs-data.sh中,当$TOOL缺失时你只记录日志但仍继续执行;建议在致命日志之后尽早以非零状态退出,这样可以避免后续流水线在半配置状态下继续运行。 csc_tool.c::patch_xml中对 XML 的处理依赖于对<FeatureSet>/<SecFloatingFeatureSet>块进行临时性的strstr/sprintf字符串解析;如果未来的 CSC 变体引入不同的包装标签或嵌套标签,这种方式很可能会失效,因此可能值得统一并强化 XML 结构检测逻辑,而不是仅对两个标签名做字符串搜索。
给 AI Agent 的提示
Please address the comments from this code review:
## Overall Comments
- In `post-fs-data.sh` you only log when `$TOOL` is missing but continue execution; consider exiting early (non‑zero) after the fatal log so the rest of the pipeline doesn’t run in a half‑configured state.
- The XML handling in `csc_tool.c::patch_xml` relies on ad‑hoc `strstr`/`sprintf` parsing of `<FeatureSet>`/`<SecFloatingFeatureSet>` blocks; if future CSC variants introduce different wrappers or nested tags this will likely break, so it may be worth centralizing and hardening the XML structure detection instead of string searching against only two tag names.
## Individual Comments
### Comment 1
<location path="module_files/post-fs-data.sh" line_range="189-17" />
<code_context>
+debug "CONFIG_PATH=$CONFIG_PATH"
+debug "TOOL=$TOOL"
+
+if [ ! -f "$TOOL" ]; then
+ log "致命错误: 未在 $TOOL 找到核心工具"
fi
-# 记录脚本结束
</code_context>
<issue_to_address>
**issue (bug_risk):** Missing early exit when core tool is unavailable may lead to confusing partial execution
Right now this guard only logs the fatal error but still lets the script continue, so `process_feature_file` will later try to invoke a missing binary and fail in a less obvious way. Add an `exit 1` (or `return 1` in a function) here so execution stops immediately when `$TOOL` is not found.
</issue_to_address>
### Comment 2
<location path="module_files/customize.sh" line_range="22" />
<code_context>
-REPLACE="
-"
+# 权限修正
+set_perm_recursive "$CONFIG_DIR" 0 0 0777 0777
+
+ui_print "------------------------"
</code_context>
<issue_to_address>
**🚨 suggestion (security):** World-writable config directory under /data/adb is risky and likely unnecessary
Using `0777` here makes all config files in `$CONFIG_DIR` world‑writable to anything that can access `/data/adb`, which is a larger trust surface than needed. Since only root/Magisk needs write access, consider restricting the directory to `0755` or `0700` and controlling write access via file‑level permissions instead.
</issue_to_address>
### Comment 3
<location path="src/core/jni/csc_tool.c" line_range="99-114" />
<code_context>
+ return (ret == Z_STREAM_END) ? 0 : -1;
+}
+
+int compress_gz(const unsigned char* src, size_t src_len, unsigned char** out, size_t* out_len) {
+ DEBUG_LOG("Starting zlib compression (input size: %zu)...", src_len);
+ z_stream strm = {0};
+ if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
+ size_t bound = deflateBound(&strm, src_len) + 100;
+ *out = malloc(bound);
+ if (!*out) { deflateEnd(&strm); return -1; }
+
+ strm.next_in = (Bytef*)src; strm.avail_in = src_len;
+ strm.next_out = *out; strm.avail_out = bound;
+ deflate(&strm, Z_FINISH);
+ *out_len = bound - strm.avail_out;
+ deflateEnd(&strm);
+ DEBUG_LOG("Compression successful (output size: %zu).", *out_len);
+ return 0;
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Compression path ignores deflate() return value and assumes single-call completion
In `compress_gz` you call `deflate(&strm, Z_FINISH)` once, ignore its return value, and assume completion. For larger inputs this can yield truncated output when `deflate` returns `Z_OK` or `Z_BUF_ERROR`. Consider looping on `deflate` until `Z_STREAM_END` (or an error) and handling unexpected statuses, similar to `inflate` in `decompress_gz`.
```suggestion
int compress_gz(const unsigned char* src, size_t src_len, unsigned char** out, size_t* out_len) {
DEBUG_LOG("Starting zlib compression (input size: %zu)...", src_len);
z_stream strm = {0};
int ret;
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
DEBUG_LOG("deflateInit2 failed.");
return -1;
}
size_t bound = deflateBound(&strm, src_len) + 100;
*out = malloc(bound);
if (!*out) {
DEBUG_LOG("Failed to allocate %zu bytes for compression buffer.", bound);
deflateEnd(&strm);
return -1;
}
strm.next_in = (Bytef*)src;
strm.avail_in = (uInt)src_len;
strm.next_out = *out;
strm.avail_out = (uInt)bound;
do {
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_ERROR) {
DEBUG_LOG("deflate encountered Z_STREAM_ERROR.");
deflateEnd(&strm);
free(*out);
*out = NULL;
return -1;
}
/* With deflateBound() the buffer should be large enough, so
* repeatedly returning Z_OK with no progress would be unexpected. */
if (ret == Z_OK && strm.avail_out == 0) {
DEBUG_LOG("deflate buffer exhausted before reaching Z_STREAM_END.");
deflateEnd(&strm);
free(*out);
*out = NULL;
return -1;
}
} while (ret == Z_OK);
if (ret != Z_STREAM_END) {
DEBUG_LOG("deflate did not reach Z_STREAM_END (ret=%d).", ret);
deflateEnd(&strm);
free(*out);
*out = NULL;
return -1;
}
*out_len = bound - strm.avail_out;
deflateEnd(&strm);
DEBUG_LOG("Compression successful (output size: %zu).", *out_len);
return 0;
}
```
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据这些反馈改进后续的评审。
Original comment in English
Hey - I've found 3 issues, and left some high level feedback:
- In
post-fs-data.shyou only log when$TOOLis missing but continue execution; consider exiting early (non‑zero) after the fatal log so the rest of the pipeline doesn’t run in a half‑configured state. - The XML handling in
csc_tool.c::patch_xmlrelies on ad‑hocstrstr/sprintfparsing of<FeatureSet>/<SecFloatingFeatureSet>blocks; if future CSC variants introduce different wrappers or nested tags this will likely break, so it may be worth centralizing and hardening the XML structure detection instead of string searching against only two tag names.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `post-fs-data.sh` you only log when `$TOOL` is missing but continue execution; consider exiting early (non‑zero) after the fatal log so the rest of the pipeline doesn’t run in a half‑configured state.
- The XML handling in `csc_tool.c::patch_xml` relies on ad‑hoc `strstr`/`sprintf` parsing of `<FeatureSet>`/`<SecFloatingFeatureSet>` blocks; if future CSC variants introduce different wrappers or nested tags this will likely break, so it may be worth centralizing and hardening the XML structure detection instead of string searching against only two tag names.
## Individual Comments
### Comment 1
<location path="module_files/post-fs-data.sh" line_range="189-17" />
<code_context>
+debug "CONFIG_PATH=$CONFIG_PATH"
+debug "TOOL=$TOOL"
+
+if [ ! -f "$TOOL" ]; then
+ log "致命错误: 未在 $TOOL 找到核心工具"
fi
-# 记录脚本结束
</code_context>
<issue_to_address>
**issue (bug_risk):** Missing early exit when core tool is unavailable may lead to confusing partial execution
Right now this guard only logs the fatal error but still lets the script continue, so `process_feature_file` will later try to invoke a missing binary and fail in a less obvious way. Add an `exit 1` (or `return 1` in a function) here so execution stops immediately when `$TOOL` is not found.
</issue_to_address>
### Comment 2
<location path="module_files/customize.sh" line_range="22" />
<code_context>
-REPLACE="
-"
+# 权限修正
+set_perm_recursive "$CONFIG_DIR" 0 0 0777 0777
+
+ui_print "------------------------"
</code_context>
<issue_to_address>
**🚨 suggestion (security):** World-writable config directory under /data/adb is risky and likely unnecessary
Using `0777` here makes all config files in `$CONFIG_DIR` world‑writable to anything that can access `/data/adb`, which is a larger trust surface than needed. Since only root/Magisk needs write access, consider restricting the directory to `0755` or `0700` and controlling write access via file‑level permissions instead.
</issue_to_address>
### Comment 3
<location path="src/core/jni/csc_tool.c" line_range="99-114" />
<code_context>
+ return (ret == Z_STREAM_END) ? 0 : -1;
+}
+
+int compress_gz(const unsigned char* src, size_t src_len, unsigned char** out, size_t* out_len) {
+ DEBUG_LOG("Starting zlib compression (input size: %zu)...", src_len);
+ z_stream strm = {0};
+ if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
+ size_t bound = deflateBound(&strm, src_len) + 100;
+ *out = malloc(bound);
+ if (!*out) { deflateEnd(&strm); return -1; }
+
+ strm.next_in = (Bytef*)src; strm.avail_in = src_len;
+ strm.next_out = *out; strm.avail_out = bound;
+ deflate(&strm, Z_FINISH);
+ *out_len = bound - strm.avail_out;
+ deflateEnd(&strm);
+ DEBUG_LOG("Compression successful (output size: %zu).", *out_len);
+ return 0;
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Compression path ignores deflate() return value and assumes single-call completion
In `compress_gz` you call `deflate(&strm, Z_FINISH)` once, ignore its return value, and assume completion. For larger inputs this can yield truncated output when `deflate` returns `Z_OK` or `Z_BUF_ERROR`. Consider looping on `deflate` until `Z_STREAM_END` (or an error) and handling unexpected statuses, similar to `inflate` in `decompress_gz`.
```suggestion
int compress_gz(const unsigned char* src, size_t src_len, unsigned char** out, size_t* out_len) {
DEBUG_LOG("Starting zlib compression (input size: %zu)...", src_len);
z_stream strm = {0};
int ret;
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
DEBUG_LOG("deflateInit2 failed.");
return -1;
}
size_t bound = deflateBound(&strm, src_len) + 100;
*out = malloc(bound);
if (!*out) {
DEBUG_LOG("Failed to allocate %zu bytes for compression buffer.", bound);
deflateEnd(&strm);
return -1;
}
strm.next_in = (Bytef*)src;
strm.avail_in = (uInt)src_len;
strm.next_out = *out;
strm.avail_out = (uInt)bound;
do {
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_ERROR) {
DEBUG_LOG("deflate encountered Z_STREAM_ERROR.");
deflateEnd(&strm);
free(*out);
*out = NULL;
return -1;
}
/* With deflateBound() the buffer should be large enough, so
* repeatedly returning Z_OK with no progress would be unexpected. */
if (ret == Z_OK && strm.avail_out == 0) {
DEBUG_LOG("deflate buffer exhausted before reaching Z_STREAM_END.");
deflateEnd(&strm);
free(*out);
*out = NULL;
return -1;
}
} while (ret == Z_OK);
if (ret != Z_STREAM_END) {
DEBUG_LOG("deflate did not reach Z_STREAM_END (ret=%d).", ret);
deflateEnd(&strm);
free(*out);
*out = NULL;
return -1;
}
*out_len = bound - strm.avail_out;
deflateEnd(&strm);
DEBUG_LOG("Compression successful (output size: %zu).", *out_len);
return 0;
}
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by Sourcery
将 Magisk 模块重构为单一统一的 CSC 工具流水线,并集成 WebUI,用以取代旧版原生工具,同时相应更新构建与安装流程。
New Features:
csc_tool可执行文件,用于处理 CSC/浮动特性(floating-feature)的解码、编码,以及 JSON/XML 补丁应用,并支持可选的调试日志。Enhancements:
post-fs-data.sh,采用结构化、带日志的工作流,动态定位 CSC 文件,并通过新的csc_tool应用补丁,同时实现更安全的绑定挂载(bind mount)和 SELinux 上下文恢复。/data/adb/csc_config下管理配置文件并设置合适的权限来简化模块自定义流程,并提供更清晰的面向用户的安装提示信息。Build:
src/core构建 WebUI 和新的核心csc_tool可执行文件,并相应调整分支与制品(artifact)内容。Original summary in English
Summary by Sourcery
Refactor the Magisk module into a single unified CSC tooling pipeline with an integrated WebUI, replacing the legacy native utilities and updating build and installation workflows accordingly.
New Features:
Enhancements:
Build:
Original summary in English
Summary by Sourcery
将 Magisk 模块重构为单一统一的 CSC 工具流水线,并集成 WebUI,用以取代旧版原生工具,同时相应更新构建与安装流程。
New Features:
csc_tool可执行文件,用于处理 CSC/浮动特性(floating-feature)的解码、编码,以及 JSON/XML 补丁应用,并支持可选的调试日志。Enhancements:
post-fs-data.sh,采用结构化、带日志的工作流,动态定位 CSC 文件,并通过新的csc_tool应用补丁,同时实现更安全的绑定挂载(bind mount)和 SELinux 上下文恢复。/data/adb/csc_config下管理配置文件并设置合适的权限来简化模块自定义流程,并提供更清晰的面向用户的安装提示信息。Build:
src/core构建 WebUI 和新的核心csc_tool可执行文件,并相应调整分支与制品(artifact)内容。Original summary in English
Summary by Sourcery
Refactor the Magisk module into a single unified CSC tooling pipeline with an integrated WebUI, replacing the legacy native utilities and updating build and installation workflows accordingly.
New Features:
Enhancements:
Build: