From f40479bd763c0f60967ec5cd7141caa213544d5d Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Tue, 8 Oct 2024 18:29:01 +0200 Subject: [PATCH] Atomic copy_from in files promise Changes to `files` promise in `copy_from` attribute: - The new file (i.e., `.cfnew`) is now created with correct permission during remote copy. Previously it would be created with default permissions. - The destination file (i.e., ``) is no longer deleted on backup during file copy. Previously it would be renamed to `.cfsaved`, causing the original file to dissappear. Now an actual copy of the original file with the same permissions is created instead. As a result, there will no longer be a brief moment where the original file is inaccessible. Ticket: ENT-11988 Changelog: Commit Signed-off-by: Lars Erik Wik (cherry picked from commit 224ccc33652c2c97923ab97a29317f6c930671e1) --- cf-agent/verify_files_utils.c | 4 ++-- libcfnet/client_code.c | 4 ++-- libcfnet/client_code.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cf-agent/verify_files_utils.c b/cf-agent/verify_files_utils.c index db18da5091..22ee22a18a 100644 --- a/cf-agent/verify_files_utils.c +++ b/cf-agent/verify_files_utils.c @@ -1552,7 +1552,7 @@ bool CopyRegularFile(EvalContext *ctx, const char *source, const char *dest, con } if (!CopyRegularFileNet(source, ToChangesPath(new), - sstat->st_size, attr->copy.encrypt, conn)) + sstat->st_size, attr->copy.encrypt, conn, sstat->st_mode)) { RecordFailure(ctx, pp, attr, "Failed to copy file '%s' from '%s'", source, conn->remoteip); @@ -1712,7 +1712,7 @@ bool CopyRegularFile(EvalContext *ctx, const char *source, const char *dest, con } } - if (rename(dest, changes_backup) == 0) + if (CopyRegularFileDisk(dest, changes_backup)) { RecordChange(ctx, pp, attr, "Backed up '%s' as '%s'", dest, backup); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); diff --git a/libcfnet/client_code.c b/libcfnet/client_code.c index f31463c385..7dccb88324 100644 --- a/libcfnet/client_code.c +++ b/libcfnet/client_code.c @@ -750,7 +750,7 @@ static void FlushFileStream(int sd, int toget) /* TODO finalise socket or TLS session in all cases that this function fails * and the transaction protocol is out of sync. */ bool CopyRegularFileNet(const char *source, const char *dest, off_t size, - bool encrypt, AgentConnection *conn) + bool encrypt, AgentConnection *conn, mode_t mode) { char *buf, workbuf[CF_BUFSIZE], cfchangedstr[265]; const int buf_size = 2048; @@ -774,7 +774,7 @@ bool CopyRegularFileNet(const char *source, const char *dest, off_t size, unlink(dest); /* To avoid link attacks */ - int dd = safe_open_create_perms(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, CF_PERMS_DEFAULT); + int dd = safe_open_create_perms(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, mode); if (dd == -1) { Log(LOG_LEVEL_ERR, diff --git a/libcfnet/client_code.h b/libcfnet/client_code.h index d926541721..4aaaa5ff4c 100644 --- a/libcfnet/client_code.h +++ b/libcfnet/client_code.h @@ -48,7 +48,7 @@ void DisconnectServer(AgentConnection *conn); bool CompareHashNet(const char *file1, const char *file2, bool encrypt, AgentConnection *conn); bool CopyRegularFileNet(const char *source, const char *dest, off_t size, - bool encrypt, AgentConnection *conn); + bool encrypt, AgentConnection *conn, mode_t mode); Item *RemoteDirList(const char *dirname, bool encrypt, AgentConnection *conn); int TLSConnectCallCollect(ConnectionInfo *conn_info, const char *username);