Account decrypted copies in media quota and protect active containers

This commit is contained in:
evgeny committed 2026-10-18 10:39:29 +02:00
1 parent feb327afc7
commit 5d2522b8de
1 file changed
+39 -2
+39 -2
View File
@@ -34,7 +34,6 @@ void chat_core_submit_media_message(struct UTUN_INSTANCE* inst, struct chat_msg_
static void wh_transcribe_done_cb(void* arg, const char* ch_id, const char* text, int err,
const uint8_t reply_id[32]);
static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst);
static void chat_media_cache_enforce(struct UTUN_INSTANCE* inst);
static void chat_media_cache_reconcile(struct UTUN_INSTANCE* inst);
/* ─── счётчик объёма медиакеша (сумма файлов, соответствующих сообщениям) ─── */
@@ -1514,6 +1513,25 @@ static void chat_media_foreach_media_message(struct chat_core_ctx* cc, const cha
cb(&f, arg);
if (cc->attachment_initialized && !strcmp(content_type, ENCRYPTED_ATTACHMENT_TYPE)) {
uint8_t crypto_id[16];
sqlite3_stmt* local = NULL;
if (!chat_attachment_identity(body, dlen, crypto_id) && sqlite3_prepare_v2(cc->db,
"SELECT plain_path FROM attachment_keys WHERE channel=? AND crypto_id=? AND ready=1 AND decrypting=0",
-1, &local, NULL) == SQLITE_OK) {
sqlite3_bind_text(local, 1, ch_id, -1, SQLITE_STATIC); sqlite3_bind_blob(local, 2, crypto_id, 16, SQLITE_STATIC);
int rc = sqlite3_step(local);
if (rc == SQLITE_ROW) {
snprintf(f.full_path, sizeof(f.full_path), "%s", sqlite3_column_text(local, 0));
size_t prefix = strlen(media_base);
if (!strncmp(f.full_path, media_base, prefix) && f.full_path[prefix] == '/') {
snprintf(f.rel_path, sizeof(f.rel_path), "%s", f.full_path + prefix + 1); cb(&f, arg);
}
} else if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: scan failed rc=%d ch=%s", rc, ch_id);
sqlite3_finalize(local);
} else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: metadata lookup failed ch=%s: %s", ch_id, sqlite3_errmsg(cc->db));
}
u_free(body);
media_index_result_free(&result);
}
@@ -1638,6 +1656,24 @@ 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);
/* Ещё не опубликованные контейнеры и их временные файлы принадлежат crypto worker. */
if (cc->attachment_initialized) {
sqlite3_stmt* active = NULL;
if (sqlite3_prepare_v2(cc->db, "SELECT cipher_path FROM attachment_keys", -1, &active, NULL) == SQLITE_OK) {
int rc;
while ((rc = sqlite3_step(active)) == SQLITE_ROW) {
const char* path = (const char*)sqlite3_column_text(active, 0);
size_t prefix = strlen(media_base);
if (path && !strncmp(path, media_base, prefix) && path[prefix] == '/') {
cache_rel_add(&rels, path + prefix + 1);
char temporary[1040]; snprintf(temporary, sizeof(temporary), "%s.part", path + prefix + 1);
cache_rel_add(&rels, temporary);
}
}
if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: active scan failed rc=%d", rc);
sqlite3_finalize(active);
} else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: active query failed: %s", sqlite3_errmsg(cc->db));
}
if (rels.count > 1) qsort(rels.items, (size_t)rels.count, sizeof(char*), cache_str_cmp);
struct orphan_walk_ctx ow;
@@ -1653,10 +1689,11 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) {
u_free(rels.items);
}
static void chat_media_cache_enforce(struct UTUN_INSTANCE* inst) {
void chat_media_cache_enforce(struct UTUN_INSTANCE* inst) {
struct chat_core_ctx* cc = CC(inst);
if (!cc || !cc->initialized || !cc->db || !inst) return;
uint64_t limit = inst->config->global.chatserver_storage_total_size;
if (cc->attachment_initialized) cc->media_cache_bytes = chat_media_cache_scan_sum(cc);
if (limit == 0 || cc->media_cache_bytes <= limit) {
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "%s: cache limit ok bytes=%llu limit=%llu",