/* app/progress.c — 进度持久化(实现见 app/progress.h)。 */ #include "progress.h" #include "meow_ui.h" /* meow_config_dir() */ #include #include #include #include #include /* 从 MEOW_DATA_DIR(/MeowData//data)剥掉尾 "/data",得到 /MeowData/。 */ static void strip_data_suffix(const char *d, char *out, int outsz) { if (!d || !d[0]) { strncpy(out, "/tmp", (size_t)outsz - 1); out[outsz - 1] = 0; return; } size_t n = strlen(d); const char *suffix = "/data"; size_t sl = strlen(suffix); size_t keep; if (n >= sl && strcmp(d + n - sl, suffix) == 0) keep = n - sl; else keep = n; if (keep >= (size_t)outsz) keep = (size_t)outsz - 1; memcpy(out, d, keep); out[keep] = 0; } int rdprog_dir(char *out, int outsz) { if (!out || outsz <= 0) return -1; const char *data = meow_config_dir(); char base[360]; strip_data_suffix(data ? data : "", base, sizeof base); if (snprintf(out, (size_t)outsz, "%s/progress", base) >= outsz) return -2; /* mkdir -p */ char tmp[400]; strncpy(tmp, out, sizeof tmp - 1); tmp[sizeof tmp - 1] = 0; for (char *p = tmp + 1; *p; p++) { if (*p == '/') { *p = 0; mkdir(tmp, 0755); *p = '/'; } } mkdir(tmp, 0755); return 0; } void rdprog_hash(const char *book_path, char *out, int outsz) { uint32_t h = 2166136261u; for (const unsigned char *p = (const unsigned char *)book_path; *p; p++) { h ^= *p; h *= 16777619u; } snprintf(out, (size_t)outsz, "%08x.prog", h); } static int rdprog_path(const char *book_path, char *out, int outsz, int *created_dir) { char dir[400]; if (rdprog_dir(dir, sizeof dir) != 0) return -1; char name[24]; rdprog_hash(book_path, name, sizeof name); if (snprintf(out, (size_t)outsz, "%s/%s", dir, name) >= outsz) return -2; if (created_dir) *created_dir = 1; return 0; } int rdprog_load(const char *book_path, rdprog *p) { if (!book_path || !p) return -1; char path[440]; if (rdprog_path(book_path, path, sizeof path, NULL) != 0) return -1; FILE *f = fopen(path, "rb"); if (!f) return 0; char line[256]; int seg = 0, fs = 0, ls = 0; int32_t ch = 0; uint64_t ts = 0; int v = 0, found = 0; while (fgets(line, sizeof line, f)) { if (sscanf(line, "v=%d", &v) == 1) { if (v == 1) found = 1; } else if (sscanf(line, "seg=%d", &seg) == 1) { /* no-op */ } else if (sscanf(line, "ch=%d", &ch) == 1) { /* no-op */ } else if (sscanf(line, "fs=%d", &fs) == 1) { /* no-op */ } else if (sscanf(line, "ls=%d", &ls) == 1) { /* no-op */ } else if (sscanf(line, "ts=%llu", (unsigned long long *)&ts) == 1) { /* no-op */ } } fclose(f); if (!found) return 0; p->valid = 1; p->seg = seg; p->ch = ch; p->fs = fs; p->ls = ls; p->ts = ts; return 1; } int rdprog_save(const char *book_path, const rdprog *p) { if (!book_path || !p) return -1; char path[440]; if (rdprog_path(book_path, path, sizeof path, NULL) != 0) return -1; FILE *f = fopen(path, "wb"); if (!f) return -1; /* 先写临时再改原子(exFAT 无 rename+replace 语义保证,直接写亦可接受) */ fprintf(f, "v=1\n"); fprintf(f, "seg=%d\n", p->seg); fprintf(f, "ch=%d\n", (int)p->ch); fprintf(f, "fs=%d\n", p->fs); fprintf(f, "ls=%d\n", p->ls); fprintf(f, "ts=%llu\n", (unsigned long long)p->ts); fclose(f); return 0; }