diff --git a/src/dm/dm_media.c b/src/dm/dm_media.c index a348125e..01003e06 100644 --- a/src/dm/dm_media.c +++ b/src/dm/dm_media.c @@ -112,42 +112,6 @@ fail: return -1; } -/* Сделать создание/удаление имён durable на POSIX. */ -static int dm_dir_sync(const char* path) { -#ifndef _WIN32 - char parent[1024]; - snprintf(parent, sizeof(parent), "%s", path); - char* slash = strrchr(parent, '/'); - if (!slash) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: path without parent: %s", path); return -1; } - *slash = '\0'; - int fd = open(parent, O_RDONLY | O_DIRECTORY); - if (fd < 0) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: directory open failed: %s: %s", parent, strerror(errno)); return -1; } - int rc = fsync(fd); - if (rc) DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: directory sync failed: %s: %s", parent, strerror(errno)); - close(fd); - return rc ? -1 : 0; -#else - (void)path; - return 0; -#endif -} - -/* Windows MoveFileEx обеспечивает замену и write-through существующего артефакта. */ -static int dm_file_publish(const char* temp, const char* path) { -#ifdef _WIN32 - if (!MoveFileExA(temp, path, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { - DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: publish failed %s -> %s winerr=%lu", temp, path, GetLastError()); - return -1; - } -#else - if (rename(temp, path) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: publish failed %s -> %s: %s", temp, path, strerror(errno)); - return -1; - } -#endif - return dm_dir_sync(path); -} - static int dm_file_remove(const char* path) { if (remove(path) != 0 && errno != ENOENT) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: remove failed path=%s: %s", path, strerror(errno)); @@ -189,7 +153,7 @@ static void dm_cleanup_pump(struct dm_media_state* media); static void dm_cleanup_work(void* arg) { struct dm_cleanup_job* job = arg; job->error = dm_file_remove(job->path); - if (!job->error) job->error = dm_dir_sync(job->path); + if (!job->error) job->error = encrypted_file_sync_directory(job->path); } static void dm_cleanup_done(void* arg, int error) { @@ -523,7 +487,7 @@ static void dm_file_work(void* arg) { struct dm_file_job* job = arg; job->error = -1; if (job->work == DM_FILE_DELETE) { - if (!dm_file_remove(job->cipher) && !dm_file_remove(job->temp)) job->error = dm_dir_sync(job->cipher); + if (!dm_file_remove(job->cipher) && !dm_file_remove(job->temp)) job->error = encrypted_file_sync_directory(job->cipher); return; } if (job->work == DM_FILE_PREPARE) { @@ -565,9 +529,9 @@ done: if (out && fclose(out)) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: worker output close failed"); job->error = -1; } if (!job->error) { if (job->work == DM_FILE_PREPARE) { - job->error = dm_file_publish(job->temp, job->cipher); - if (!job->error) job->error = dm_dir_sync(job->plain); - } else job->error = dm_file_publish(job->work == DM_FILE_CUSTODY ? job->cipher : job->temp, job->output); + job->error = encrypted_file_publish(job->temp, job->cipher); + if (!job->error) job->error = encrypted_file_sync_directory(job->plain); + } else job->error = encrypted_file_publish(job->work == DM_FILE_CUSTODY ? job->cipher : job->temp, job->output); } } diff --git a/src/media_async/encrypted_file.c b/src/media_async/encrypted_file.c index 049c5de8..268b58b0 100644 --- a/src/media_async/encrypted_file.c +++ b/src/media_async/encrypted_file.c @@ -10,10 +10,47 @@ #include #include #include +#include #ifdef _WIN32 #include #endif +/* Сделать создание/удаление имён durable на POSIX. */ +int encrypted_file_sync_directory(const char* path) { +#ifndef _WIN32 + char parent[1024]; + snprintf(parent, sizeof(parent), "%s", path); + char* slash = strrchr(parent, '/'); + if (!slash) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: path without parent: %s", path); return -1; } + *slash = '\0'; + int fd = open(parent, O_RDONLY | O_DIRECTORY); + if (fd < 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: directory open failed: %s: %s", parent, strerror(errno)); return -1; } + int rc = fsync(fd); + if (rc) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: directory sync failed: %s: %s", parent, strerror(errno)); + close(fd); + return rc ? -1 : 0; +#else + (void)path; + return 0; +#endif +} + +/* Windows MoveFileEx обеспечивает замену и write-through существующего артефакта. */ +int encrypted_file_publish(const char* temp, const char* path) { +#ifdef _WIN32 + if (!MoveFileExA(temp, path, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: publish failed %s -> %s winerr=%lu", temp, path, GetLastError()); + return -1; + } +#else + if (rename(temp, path) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: publish failed %s -> %s: %s", temp, path, strerror(errno)); + return -1; + } +#endif + return encrypted_file_sync_directory(path); +} + #define EF_HEADER 66 #define EF_META (32 + ATTACHMENT_WIRE_MAX) diff --git a/src/media_async/encrypted_file.h b/src/media_async/encrypted_file.h index 1033c847..7afc3438 100644 --- a/src/media_async/encrypted_file.h +++ b/src/media_async/encrypted_file.h @@ -15,6 +15,9 @@ int encrypted_file_read(const char* source, const char* destination, const uint8 const uint8_t id[16], const uint8_t hash[32], struct attachment_info* info, char type[32]); /* Flush/fsync и close проверяет владелец; этот примитив сохраняет уже закрытый файл. */ int encrypted_file_sync(const char* path); +/* Durable rename (write-through на Windows) и сохранение каталога на POSIX. */ +int encrypted_file_publish(const char* temporary, const char* path); +int encrypted_file_sync_directory(const char* path); #ifdef __cplusplus } #endif