Recover owned encrypted attachment temporaries in both storage trees
This commit is contained in:
1 parent
4350b54769
commit
f09d76e3fd
2 files changed
+44
-8
No files matched your search
@@ -96,10 +96,8 @@ invalid:
|
||||
|
||||
/* Разделённые деревья исключают раздачу plaintext и удаление его обходом orphan media. */
|
||||
static int ak_paths(struct ak_file* job) {
|
||||
const char* slash = strrchr(CC(job->inst)->db_path, '/');
|
||||
char base[512], hex[33]; ak_hex(job->id, hex);
|
||||
if (slash) snprintf(base, sizeof(base), "%.*s", (int)(slash - CC(job->inst)->db_path), CC(job->inst)->db_path);
|
||||
else snprintf(base, sizeof(base), ".");
|
||||
if (media_index_get_base(CC(job->inst)->db, base)) return -1;
|
||||
int a = snprintf(job->cipher, sizeof(job->cipher), "%s/media/%s/%s.uenc", base, job->channel, hex);
|
||||
int b = snprintf(job->plain, sizeof(job->plain), "%s/decrypted/%s/%s.file", base, job->channel, hex);
|
||||
if (a < 0 || b < 0 || (size_t)a >= sizeof(job->cipher) || (size_t)b >= sizeof(job->plain)) {
|
||||
@@ -553,9 +551,50 @@ static void ak_tick(void* arg) {
|
||||
if (!CC(inst)->attachment_timer) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: timer allocation failed");
|
||||
}
|
||||
|
||||
struct ak_temp_cleanup { const char* root; const char* extension; unsigned removed; };
|
||||
|
||||
/* Только <channel>/<UUID>.<uenc|file>.tmp.<UUID>; чужие имена и активные owners сохраняются. */
|
||||
static void ak_remove_temp(void* arg, const char* path, int64_t size) {
|
||||
(void)size;
|
||||
struct ak_temp_cleanup* cleanup = arg;
|
||||
size_t prefix = strlen(cleanup->root);
|
||||
if (strncmp(path, cleanup->root, prefix) || path[prefix] != '/') return;
|
||||
const char* relative = path + prefix + 1;
|
||||
const char* slash = strchr(relative, '/');
|
||||
if (!slash || slash - relative >= 20) return;
|
||||
char channel[20]; memcpy(channel, relative, (size_t)(slash - relative)); channel[slash - relative] = 0;
|
||||
if (!ak_channel(channel)) return;
|
||||
const char* name = slash + 1;
|
||||
const char* hex = "0123456789abcdef";
|
||||
if (strlen(name) != 74 || strspn(name, hex) != 32 || memcmp(name + 32, cleanup->extension, 5) ||
|
||||
memcmp(name + 37, ".tmp.", 5) || strspn(name + 42, hex) != 32) return;
|
||||
int removed = file_io_remove_orphan(path);
|
||||
if (removed > 0) cleanup->removed++;
|
||||
else if (removed < 0) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: temporary recovery failed path=%s", path);
|
||||
}
|
||||
|
||||
/* И при crash до публикации, и при прерванной расшифровке temp не является готовым вложением. */
|
||||
static void ak_recover_temps(struct UTUN_INSTANCE* inst) {
|
||||
char base[MEDIA_BASE_MAX];
|
||||
if (media_index_get_base(CC(inst)->db, base)) return;
|
||||
const char* trees[] = {"media", "decrypted"};
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
char root[MEDIA_BASE_MAX + 16]; snprintf(root, sizeof(root), "%s/%s", base, trees[i]);
|
||||
struct file_io_info info;
|
||||
int status = file_io_inspect(root, 0, &info);
|
||||
if (status == 1) continue;
|
||||
if (status < 0) { DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: cannot inspect temporary tree path=%s", root); continue; }
|
||||
struct ak_temp_cleanup cleanup = {.root = root, .extension = i ? ".file" : ".uenc"};
|
||||
if (ma_dir_walk(root, ak_remove_temp, &cleanup))
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: temporary recovery incomplete path=%s removed=%u", root, cleanup.removed);
|
||||
else DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "attachment keys: temporary recovery path=%s removed=%u", root, cleanup.removed);
|
||||
}
|
||||
}
|
||||
|
||||
/* После crash/отмены убрать только собственные подготовки, не имеющие сообщения.
|
||||
* Вызывается до запуска workers либо после их полного завершения. */
|
||||
static void ak_recover_preparations(struct UTUN_INSTANCE* inst) {
|
||||
ak_recover_temps(inst);
|
||||
char** channels = NULL; int count = 0, columns = 0;
|
||||
if (sqlite3_get_table(CC(inst)->db, "SELECT channel_id FROM channels", &channels, &count, &columns, NULL) != SQLITE_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: recovery channel scan failed: %s", sqlite3_errmsg(CC(inst)->db)); return;
|
||||
@@ -575,8 +614,7 @@ static void ak_recover_preparations(struct UTUN_INSTANCE* inst) {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int field = 0; field < fields; field++) {
|
||||
const char* path = paths[(row + 1) * fields + field];
|
||||
char temporary[1040]; snprintf(temporary, sizeof(temporary), "%s.part", path);
|
||||
if ((remove(path) && errno != ENOENT) || (remove(temporary) && errno != ENOENT)) {
|
||||
if (remove(path) && errno != ENOENT) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: unfinished file removal failed path=%s: %s", path, strerror(errno)); failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1683,7 +1683,7 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) {
|
||||
for (int i = 0; i < rels.count; i++) u_free(rels.items[i]);
|
||||
u_free(rels.items); return;
|
||||
}
|
||||
/* Ещё не опубликованные контейнеры и их временные файлы принадлежат crypto worker. */
|
||||
/* Конечные контейнеры принадлежат attachment_keys; активные temp защищены file_io-реестром. */
|
||||
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) {
|
||||
@@ -1693,8 +1693,6 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) {
|
||||
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);
|
||||
|
||||
Reference in new issue
Block a user