Verify attachment recovery preserves active temp owners across restarts

This commit is contained in:
evgeny committed 2026-10-24 14:48:25 +02:00
1 parent 76ba7aae6a
commit 7caebc5a11
2 files changed
+46 -2

No files matched your search

+5 -1
View File
@@ -142,7 +142,11 @@ static int file_io_sync_descriptor(FILE *file, const char *path) {
#else
int result = fsync(fileno(file));
#endif
if (result) DEBUG_ERROR(DEBUG_CATEGORY_SYS, "file sync failed path=%s errno=%d", path, errno);
if (result) {
int error = errno ? errno : EIO;
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "file sync failed path=%s errno=%d", path, error);
errno = error;
}
return result ? -1 : 0;
}
+41 -1
View File
@@ -96,6 +96,46 @@ void __wrap_media_download_handle_chunk(struct UTUN_INSTANCE* inst, uint64_t gro
static void hex(const uint8_t* p, size_t len, char* out) {
for (size_t i = 0; i < len; i++) snprintf(out + i * 2, 3, "%02x", p[i]);
}
/* Startup/restart удаляет только строгие собственные stale temp; живые owners обоих деревьев сохраняются. */
static int start_with_recovery(struct UTUN_INSTANCE* inst, const char* base) {
struct file_io_temp live[2] = {0};
char target[2][1024], stale[2][1100], foreign[2][1100];
const char* trees[] = {"media", "decrypted"};
const char* extensions[] = {"uenc", "file"};
int result = -1;
for (unsigned i = 0; i < 2; i++) {
char directory[900]; snprintf(directory, sizeof(directory), "%s/%s", base, trees[i]);
if (utun_mkdir(directory, 0700) && errno != EEXIST) goto done;
snprintf(directory, sizeof(directory), "%s/%s/123", base, trees[i]);
if (utun_mkdir(directory, 0700) && errno != EEXIST) goto done;
snprintf(target[i], sizeof(target[i]), "%s/00000000000000000000000000000001.%s", directory, extensions[i]);
snprintf(stale[i], sizeof(stale[i]), "%s.tmp.00000000000000000000000000000002", target[i]);
snprintf(foreign[i], sizeof(foreign[i]), "%s.tmp.foreign", target[i]);
const char* paths[] = {target[i], stale[i], foreign[i]};
for (unsigned j = 0; j < 3; j++) {
FILE* file = fopen(paths[j], "wb");
if (!file) goto done;
int failed = fputs("retained", file) < 0;
if (fclose(file)) failed = 1;
if (failed) goto done;
}
if (file_io_temp_open(&live[i], target[i], FILE_IO_DURABLE) || fputs("live", live[i].file) < 0) goto done;
if (i ? file_io_temp_finish(&live[i]) : fflush(live[i].file)) goto done;
}
if (utun_instance_init(inst)) goto done;
for (unsigned i = 0; i < 2; i++) {
if (ma_file_size(stale[i]) >= 0 || ma_file_size(target[i]) != 8 || ma_file_size(foreign[i]) != 8 ||
ma_file_size(live[i].temporary) != 4 || file_io_remove_orphan(live[i].temporary) != 0) goto done;
}
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS attachment restart recovery: both trees, open/finished owners, final and foreign files");
result = 0;
done:
for (unsigned i = 0; i < 2; i++) file_io_temp_discard(&live[i]);
if (result) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment recovery fixture failed base=%s errno=%d", base, errno);
return result;
}
static int start_node(struct media_test* t, int index) {
char path[768], pub[65], priv[65], server[65], db[768];
hex(t->keys[index].public_key, 32, pub); hex(t->keys[index].private_key, 32, priv);
@@ -117,7 +157,7 @@ static int start_node(struct media_test* t, int index) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "encrypted attachment fixture: node=%d port=%u retained for restart", index, t->ports[index]);
}
if (t->nodes[index] && index != S) test_etcp_set_peer(t->nodes[index], "to_s", t->nodes[S], "s1");
return t->nodes[index] ? utun_instance_init(t->nodes[index]) : -1;
return t->nodes[index] ? start_with_recovery(t->nodes[index], db) : -1;
}
/* Фикстура создаёт канал напрямую, поэтому сама снимает gate после реального Merkle round. */