changeset 4406:18c7c5215b53 HEAD

Added file_copy().
author Timo Sirainen <tss@iki.fi>
date Sat, 17 Jun 2006 19:24:55 +0300
parents fe17f63521ea
children 2e4857a2b858
files src/lib/Makefile.am src/lib/file-copy.c src/lib/file-copy.h
diffstat 3 files changed, 91 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/Makefile.am	Sat Jun 17 19:01:14 2006 +0300
+++ b/src/lib/Makefile.am	Sat Jun 17 19:24:55 2006 +0300
@@ -13,6 +13,7 @@
 	fd-set-nonblock.c \
 	fdpass.c \
 	file-cache.c \
+	file-copy.c \
 	file-dotlock.c \
 	file-lock.c \
 	file-set-size.c \
@@ -98,6 +99,7 @@
 	fd-set-nonblock.h \
 	fdpass.h \
 	file-cache.h \
+	file-copy.h \
 	file-dotlock.h \
 	file-lock.h \
 	file-set-size.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/file-copy.c	Sat Jun 17 19:24:55 2006 +0300
@@ -0,0 +1,77 @@
+/* Copyright (c) 2006 Timo Sirainen */
+
+#include "lib.h"
+#include "istream.h"
+#include "ostream.h"
+#include "file-copy.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int file_copy(const char *srcpath, const char *destpath, bool try_hardlink)
+{
+	const char *tmppath;
+	struct istream *input;
+	struct ostream *output;
+	int fd_in, fd_out;
+	off_t ret;
+
+	if (try_hardlink) {
+		/* see if hardlinking works */
+		if (link(srcpath, destpath) == 0 || errno == EEXIST)
+			return 1;
+		if (errno == ENOENT)
+			return 0;
+		if (!ECANTLINK(errno)) {
+			i_error("link(%s, %s) failed: %m", srcpath, destpath);
+			return -1;
+		}
+
+		/* fallback to manual copying */
+	}
+
+	fd_in = open(srcpath, O_RDONLY);
+	if (fd_in == -1) {
+		if (errno == ENOENT)
+			return 0;
+		i_error("open(%s) failed: %m", srcpath);
+		return -1;
+	}
+
+	t_push();
+	tmppath = t_strconcat(destpath, ".tmp", NULL);
+	fd_out = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	if (fd_out == -1) {
+		i_error("open(%s, O_CREAT) failed: %m", tmppath);
+		(void)close(fd_in);
+		t_pop();
+		return -1;
+	}
+	input = i_stream_create_file(fd_in, default_pool, 0, FALSE);
+	output = o_stream_create_file(fd_out, default_pool, 0, FALSE);
+
+	while ((ret = o_stream_send_istream(output, input)) > 0) ;
+
+	i_stream_destroy(&input);
+	o_stream_destroy(&output);
+
+	if (close(fd_in) < 0) {
+		i_error("close(%s) failed: %m", srcpath);
+		ret = -1;
+	}
+	if (close(fd_out) < 0) {
+		i_error("close(%s) failed: %m", tmppath);
+		ret = -1;
+	}
+	if (ret == 0) {
+		if (rename(tmppath, destpath) < 0) {
+			i_error("rename(%s, %s) failed: %m", tmppath, destpath);
+			ret = -1;
+		}
+	}
+	if (ret < 0)
+		(void)unlink(tmppath);
+	t_pop();
+	return ret < 0 ? -1 : 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/file-copy.h	Sat Jun 17 19:24:55 2006 +0300
@@ -0,0 +1,12 @@
+#ifndef __FILE_COPY_H
+#define __FILE_COPY_H
+
+/* Copy file atomically. First try hardlinking, then fallback to creating
+   a temporary file (destpath.tmp) and rename()ing it over srcpath.
+   If the destination file already exists, it may or may not be overwritten,
+   so that shouldn't be relied on.
+
+   Returns -1 = error, 0 = source file not found, 1 = ok */
+int file_copy(const char *srcpath, const char *destpath, bool try_hardlink);
+
+#endif