From 7b8e2cd96c4616bdc566671adcf19dc8f5e84c34 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 1 Oct 2026 17:40:49 +0300 Subject: [PATCH] Transfer temporary source ownership before launching PM workers --- src/dm/dm_media.c | 31 ++++++++++++++++++++++--------- src/dm/dm_media.h | 3 ++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/dm/dm_media.c b/src/dm/dm_media.c index c604039e..95ee341d 100644 --- a/src/dm/dm_media.c +++ b/src/dm/dm_media.c @@ -365,8 +365,11 @@ static void dm_file_work(void* arg) { if (!dm_file_remove(job->cipher) && !dm_file_remove(job->temp)) job->error = dm_dir_sync(job->cipher); return; } - if (job->work == DM_FILE_PREPARE && dm_file_copy(job->input, job->plain)) return; - if (job->work == DM_FILE_PREPARE && job->remove_source && dm_file_remove(job->input)) return; + if (job->work == DM_FILE_PREPARE) { + int copied = dm_file_copy(job->input, job->plain); + if (job->remove_source && dm_file_remove(job->input)) return; + if (copied) return; + } FILE* in = fopen(job->work == DM_FILE_PREPARE ? job->plain : job->cipher, "rb"); FILE* out = job->work == DM_FILE_CUSTODY ? NULL : fopen(job->temp, "wb"); if (!in || (job->work != DM_FILE_CUSTODY && !out)) { @@ -569,7 +572,8 @@ static int dm_file_lookup(void* arg, uint64_t group, uint64_t peer, const uint8_ } /* Путь исходника копируется; caller может освободить строку после возврата. */ -int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info) { +int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info, + int remove_source) { struct dm_media_state* media = inst ? inst->dm_media : NULL; if (!media || media->closing || !inst->media_async || !conv || !path || attachment_validate(info) || strlen(path) >= 1024) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: invalid file send arguments/state"); @@ -581,7 +585,7 @@ int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, struct dm_file_job* job = u_calloc(1, sizeof(*job)); if (!job) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: preparation allocation failed"); return -1; } job->media = media; job->work = DM_FILE_PREPARE; job->author = inst->node_id; - snprintf(job->conv, sizeof(job->conv), "%s", conv); job->info = *info; + snprintf(job->conv, sizeof(job->conv), "%s", conv); job->info = *info; job->remove_source = remove_source; snprintf(job->input, sizeof(job->input), "%s", path); sqlite3_stmt* st = dm_media_prepare(inst, "SELECT peer_x25519 FROM dm_conversations WHERE conv_id=?"); if (!st) { u_free(job); return -1; } @@ -603,14 +607,23 @@ int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, return 0; } +/* Удаление непринятого временного файла тоже выполняется вне uasync. */ +static void dm_source_cleanup(void* arg) { + struct dm_file_req* req = arg; + dm_file_remove(req->path); +} + +static void dm_source_cleaned(void* arg, int error) { + if (error) DEBUG_WARN(DEBUG_CATEGORY_DM, "dm_media: source cleanup cancelled error=%d", error); + u_free(arg); +} + void dm_send_file_trampoline(void* arg) { struct dm_file_req* req = arg; if (!req) return; - /* Передача source во владение возможна только при принятой задаче. */ - if (!dm_send_file(req->inst, req->conv, req->path, &req->info)) { - struct dm_media_state* media = req->inst->dm_media; - if (media->jobs && media->jobs->work == DM_FILE_PREPARE && !strcmp(media->jobs->input, req->path)) - media->jobs->remove_source = req->remove_source; + if (dm_send_file(req->inst, req->conv, req->path, &req->info, req->remove_source) && req->remove_source) { + media_async_submit(req->inst->media_async, req->inst->ua, dm_source_cleanup, req, dm_source_cleaned, req); + return; } u_free(req); } diff --git a/src/dm/dm_media.h b/src/dm/dm_media.h index 121debaa..b902836a 100644 --- a/src/dm/dm_media.h +++ b/src/dm/dm_media.h @@ -32,7 +32,8 @@ void dm_media_quiesce(struct UTUN_INSTANCE* inst); void dm_media_destroy(struct UTUN_INSTANCE* inst); /* Подготовить копию и enqueue file-сообщение асинхронно. 0=задача принята. */ -int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info); +int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info, + int remove_source); struct dm_file_req { struct UTUN_INSTANCE* inst; char conv[64];