/* * extract.c -- Mass Storage Extractor module * * SPDX-License-Identifier: GPL-2.0-or-later * * Mass storage extractor. Recursively copies /mnt/target_media to * /data/loot_drop/extracted/. Skips symlinks, copies regular files * in 4KB chunks. Displays file/dir/byte counts. */ #include #include #include #include #include #include #include #include #include "h2_ui.h" #include "log_manager.h" #define SRC_PATH "/mnt/target_media" #define DST_PATH "/data/loot_drop/extracted" #define LINE_BUF 128 static int total_files; static int total_dirs; static long long total_bytes; static void copy_tree(const char *src, const char *dst) { DIR *dir = opendir(src); if (!dir) return; mkdir(dst, 0755); struct dirent *ent; while ((ent = readdir(dir)) != NULL) { if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) continue; char src_path[512], dst_path[512]; snprintf(src_path, sizeof(src_path), "%s/%s", src, ent->d_name); snprintf(dst_path, sizeof(dst_path), "%s/%s", dst, ent->d_name); struct stat st; if (lstat(src_path, &st) < 0) continue; if (S_ISLNK(st.st_mode)) continue; if (S_ISDIR(st.st_mode)) { total_dirs++; copy_tree(src_path, dst_path); } else if (S_ISREG(st.st_mode)) { FILE *in = fopen(src_path, "rb"); FILE *out = fopen(dst_path, "wb"); if (!in || !out) { if (in) fclose(in); if (out) fclose(out); continue; } char buf[4096]; size_t n; while ((n = fread(buf, 1, sizeof(buf), in)) > 0) { fwrite(buf, 1, n, out); total_bytes += n; } fclose(in); fclose(out); total_files++; } } closedir(dir); } int main(void) { init_h2_graphics_runtime("DATA ASSET EXTRACTION"); LOG_INF("extract module started"); lv_obj_t *scr = lv_scr_act(); lv_obj_t *title = lv_label_create(scr); lv_label_set_text(title, "MASS STORAGE EXTRACTOR"); lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 15); lv_obj_set_style_text_color(title, COLOR_PRIMARY, LV_PART_MAIN); lv_obj_t *list = lv_list_create(scr); lv_obj_set_size(list, 280, 160); lv_obj_align(list, LV_ALIGN_CENTER, 0, 15); struct stat st; if (stat(SRC_PATH, &st) != 0 || !S_ISDIR(st.st_mode)) { lv_list_add_text(list, "[IDLE] No target mounted at /mnt/target_media"); } else { mkdir(DST_PATH, 0755); lv_list_add_text(list, "[ACTIVE] Copying target media..."); lv_timer_handler(); total_files = 0; total_dirs = 0; total_bytes = 0; copy_tree(SRC_PATH, DST_PATH); sync(); char buf[LINE_BUF]; snprintf(buf, sizeof(buf), "Files: %d Dirs: %d", total_files, total_dirs); lv_list_add_text(list, buf); snprintf(buf, sizeof(buf), "Bytes copied: %lld", total_bytes); lv_obj_t *entry = lv_list_add_text(list, buf); lv_obj_set_style_text_color(entry, COLOR_ACCENT, LV_PART_MAIN); lv_list_add_text(list, "[DONE] Assets in /data/loot_drop/extracted/"); LOG_INF("extraction complete: %d files, %d dirs, %lld bytes", total_files, total_dirs, total_bytes); } int input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK); struct input_event ev; while (1) { lv_timer_handler(); if (input_fd >= 0 && read(input_fd, &ev, sizeof(struct input_event)) > 0) { if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) break; } usleep(20000); } if (input_fd >= 0) close(input_fd); LOG_INF("extract module exited"); return 0; }