Preserve indexed and unfinished files during orphan cleanup

This commit is contained in:
evgeny committed 2026-10-22 14:49:11 +02:00
1 parent 15fafc42c9
commit 9117813c4d
2 files changed
+29 -19

No files matched your search

+25 -17
View File
@@ -1341,10 +1341,8 @@ void chat_media_autodownload_backfill(struct UTUN_INSTANCE* inst) {
uint64_t now_ms = (uint64_t)ntp_time_get_seconds(inst) * 1000ULL;
uint64_t cutoff_ms = now_ms - (uint64_t)days * 86400ULL * 1000ULL;
char media_base[512];
const char* last_slash = strrchr(cc->db_path, '/');
if (last_slash) snprintf(media_base, sizeof(media_base), "%.*s", (int)(last_slash - cc->db_path), cc->db_path);
else snprintf(media_base, sizeof(media_base), "%s", cc->db_path);
char media_base[MEDIA_BASE_MAX];
if (media_index_get_base(cc->db, media_base)) return;
struct bf_list list = {0};
bf_collect(cc, media_base, NULL, &list);
@@ -1411,10 +1409,8 @@ void chat_media_autodownload_backfill_channel(struct UTUN_INSTANCE* inst, const
uint64_t now_ms = (uint64_t)ntp_time_get_seconds(inst) * 1000ULL;
uint64_t cutoff_ms = now_ms - (uint64_t)days * 86400ULL * 1000ULL;
char media_base[512];
const char* last_slash = strrchr(cc->db_path, '/');
if (last_slash) snprintf(media_base, sizeof(media_base), "%.*s", (int)(last_slash - cc->db_path), cc->db_path);
else snprintf(media_base, sizeof(media_base), "%s", cc->db_path);
char media_base[MEDIA_BASE_MAX];
if (media_index_get_base(cc->db, media_base)) return;
struct bf_list list = {0};
bf_collect(cc, media_base, ch_id, &list);
@@ -1454,12 +1450,6 @@ struct media_msg_file {
typedef void (*media_msg_file_cb)(const struct media_msg_file* f, void* arg);
static void chat_media_base(struct chat_core_ctx* cc, char* out, size_t out_sz) {
const char* ls = strrchr(cc->db_path, '/');
if (ls) snprintf(out, out_sz, "%.*s", (int)(ls - cc->db_path), cc->db_path);
else snprintf(out, out_sz, "%s", cc->db_path);
}
/* Итератор по всем медиасообщениям всех каналов (без фильтра по node_id/времени). */
static void chat_media_foreach_media_message(struct chat_core_ctx* cc, const char* media_base, media_msg_file_cb cb, void* arg) {
if (!cc->db || !cb) return;
@@ -1604,7 +1594,8 @@ static void cache_file_collect_cb(const struct media_msg_file* f, void* arg) {
/* Фактическая сумма размеров файлов, соответствующих сообщениям. */
static uint64_t chat_media_cache_scan_sum(struct chat_core_ctx* cc) {
char media_base[512]; chat_media_base(cc, media_base, sizeof(media_base));
char media_base[MEDIA_BASE_MAX];
if (media_index_get_base(cc->db, media_base)) return;
struct cache_file_list files = {0};
chat_media_foreach_media_message(cc, media_base, cache_file_collect_cb, &files);
uint64_t sum = 0;
@@ -1661,7 +1652,8 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) {
struct chat_core_ctx* cc = CC(inst);
if (!cc || !cc->initialized || !cc->db || !inst) return;
char media_base[512]; chat_media_base(cc, media_base, sizeof(media_base));
char media_base[MEDIA_BASE_MAX];
if (media_index_get_base(cc->db, media_base)) return;
char media_dir[600]; snprintf(media_dir, sizeof(media_dir), "%s/media", media_base);
struct file_io_info directory;
@@ -1671,6 +1663,21 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) {
struct cache_rel_list rels = {0};
chat_media_foreach_media_message(cc, media_base, cache_rel_collect_cb, &rels);
sqlite3_stmt* preparations = NULL;
int prep_rc = sqlite3_prepare_v2(cc->db, "SELECT location FROM media_preparations UNION SELECT location FROM media_files",
-1, &preparations, NULL);
if (prep_rc == SQLITE_OK) {
while ((prep_rc = sqlite3_step(preparations)) == SQLITE_ROW) {
const char* location = (const char*)sqlite3_column_text(preparations, 0);
if (location) cache_rel_add(&rels, location);
}
}
int prep_finish = preparations ? sqlite3_finalize(preparations) : SQLITE_OK;
if (prep_rc != SQLITE_DONE || prep_finish != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media orphan scan cannot protect indexed/preparing files rc=%d", prep_rc);
for (int i = 0; i < rels.count; i++) u_free(rels.items[i]);
u_free(rels.items); return;
}
/* Ещё не опубликованные контейнеры и их временные файлы принадлежат crypto worker. */
if (cc->attachment_initialized) {
sqlite3_stmt* active = NULL;
@@ -1719,7 +1726,8 @@ void chat_media_cache_enforce(struct UTUN_INSTANCE* inst) {
return;
}
char media_base[512]; chat_media_base(cc, media_base, sizeof(media_base));
char media_base[MEDIA_BASE_MAX];
if (media_index_get_base(cc->db, media_base)) return;
struct cache_file_list files = {0};
chat_media_foreach_media_message(cc, media_base, cache_file_collect_cb, &files);
+4 -2
View File
@@ -103,7 +103,8 @@ int media_index_get_base(sqlite3* db, char base[MEDIA_BASE_MAX]) {
sqlite3_stmt* st = NULL;
int rc = db && base ? sqlite3_prepare_v2(db, "SELECT value FROM ui_state WHERE key='media_base'", -1, &st, NULL) : SQLITE_MISUSE;
if (rc == SQLITE_OK) rc = sqlite3_step(st);
int valid = rc == SQLITE_ROW && !mi_clean_path((const char*)sqlite3_column_text(st, 0), base, MEDIA_BASE_MAX);
const char* value = rc == SQLITE_ROW ? (const char*)sqlite3_column_text(st, 0) : NULL;
int valid = value && sqlite3_column_bytes(st, 0) == (int)strlen(value) && !mi_clean_path(value, base, MEDIA_BASE_MAX);
if (st && sqlite3_finalize(st) != SQLITE_OK) valid = 0;
if (valid) return 0;
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index cannot read media_base rc=%d: %s", rc, db ? sqlite3_errmsg(db) : "no DB");
@@ -256,7 +257,8 @@ static int mi_remove(const char* path) {
}
int media_index_delete_channel(sqlite3* db, const char* chat_id, const char* media_base) {
if (!db || !chat_id || !*chat_id || !sqlite3_get_autocommit(db)) {
char checked_base[MEDIA_BASE_MAX];
if (!db || !chat_id || !*chat_id || !sqlite3_get_autocommit(db) || mi_clean_path(media_base, checked_base, sizeof(checked_base))) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index delete invalid args/external transaction"); return -1;
}
struct mi_delete_file { char location[MEDIA_PATH_MAX]; char path[MEDIA_PATH_MAX]; int shared; };