summaryrefslogtreecommitdiffstats
path: root/src/util/backup_file.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/util/backup_file.c
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/util/backup_file.c')
-rw-r--r--src/util/backup_file.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/util/backup_file.c b/src/util/backup_file.c
new file mode 100644
index 0000000..a164a86
--- /dev/null
+++ b/src/util/backup_file.c
@@ -0,0 +1,120 @@
+/*
+ SSSD
+
+ Backup files
+
+ Copyright (C) Simo Sorce 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#define BUFFER_SIZE 65536
+
+int backup_file(const char *src_file, int dbglvl)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char buf[BUFFER_SIZE];
+ int src_fd = -1;
+ int dst_fd = -1;
+ char *dst_file;
+ ssize_t numread;
+ ssize_t written;
+ int ret, i;
+
+ src_fd = open(src_file, O_RDONLY);
+ if (src_fd < 0) {
+ ret = errno;
+ DEBUG(dbglvl, "Error (%d [%s]) opening source file %s\n",
+ ret, strerror(ret), src_file);
+ goto done;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* try a few times to come up with a new backup file, then give up */
+ for (i = 0; i < 10; i++) {
+ if (i == 0) {
+ dst_file = talloc_asprintf(tmp_ctx, "%s.bak", src_file);
+ } else {
+ dst_file = talloc_asprintf(tmp_ctx, "%s.bak%d", src_file, i);
+ }
+ if (!dst_file) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ errno = 0;
+ dst_fd = open(dst_file, O_CREAT|O_EXCL|O_WRONLY, 0600);
+ ret = errno;
+
+ if (dst_fd >= 0) break;
+
+ if (ret != EEXIST) {
+ DEBUG(dbglvl, "Error (%d [%s]) opening destination file %s\n",
+ ret, strerror(ret), dst_file);
+ goto done;
+ }
+ }
+ if (ret != 0) {
+ DEBUG(dbglvl, "Error (%d [%s]) opening destination file %s\n",
+ ret, strerror(ret), dst_file);
+ goto done;
+ }
+
+ /* copy file contents */
+ while (1) {
+ errno = 0;
+ numread = sss_atomic_read_s(src_fd, buf, BUFFER_SIZE);
+ if (numread < 0) {
+ ret = errno;
+ DEBUG(dbglvl, "Error (%d [%s]) reading from source %s\n",
+ ret, strerror(ret), src_file);
+ goto done;
+ }
+ if (numread == 0) break;
+
+ errno = 0;
+ written = sss_atomic_write_s(dst_fd, buf, numread);
+ if (written == -1) {
+ ret = errno;
+ DEBUG(dbglvl, "Error (%d [%s]) writing to destination %s\n",
+ ret, strerror(ret), dst_file);
+ goto done;
+ }
+
+ if (written != numread) {
+ DEBUG(dbglvl, "Wrote %zd bytes expected %zd bytes\n",
+ written, numread);
+ ret = EIO;
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (src_fd != -1) close(src_fd);
+ if (dst_fd != -1) close(dst_fd);
+ talloc_free(tmp_ctx);
+ return ret;
+}