summaryrefslogtreecommitdiffstats
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c
index 91954dd..ed93e6b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -6,6 +6,9 @@
#include <errno.h>
#include <limits.h>
#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
#include "util.h"
void statistics(DB *db) {
@@ -104,3 +107,151 @@ int isdirectory(const char *path) {
return !!S_ISDIR(st.st_mode);
}
+
+
+#define MMAPSIZE (100*1024*1024)
+#define BUFSIZE (1024*1024)
+
+int copy_fd(int sfd, int dfd, uint32_t l) {
+ off_t src_o, dst_o;
+ void *src_p, *dst_p;
+ void *buf = NULL;
+ int r = -1;
+ struct stat st;
+
+ if ((src_o = lseek(sfd, 0, SEEK_CUR)) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (fstat(sfd, &st) < 0) {
+ fprintf(stderr, "fstat(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (l == (uint32_t) -1 || l >= st.st_size - src_o)
+ l = st.st_size - src_o;
+
+ if ((dst_o = lseek(dfd, 0, SEEK_CUR)) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (fstat(dfd, &st) < 0) {
+ fprintf(stderr, "fstat(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (dst_o+l > st.st_size)
+ if (ftruncate(dfd, dst_o+l) < 0) {
+ fprintf(stderr, "ftruncate(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (l > BUFSIZE) {
+ uint32_t m = l < MMAPSIZE ? l : MMAPSIZE;
+
+ while (l > 0) {
+ if ((src_p = mmap(NULL, m, PROT_READ, MAP_SHARED, sfd, src_o)) == MAP_FAILED)
+ break;
+
+ if ((dst_p = mmap(NULL, m, PROT_READ|PROT_WRITE, MAP_SHARED, dfd, dst_o)) == MAP_FAILED) {
+ munmap(src_p, m);
+ break;
+ }
+
+ memcpy(dst_p, src_p, m);
+
+ munmap(src_p, m);
+ munmap(dst_p, m);
+
+ src_o += m;
+ dst_o += m;
+ l -= m;
+
+ m = l < MMAPSIZE ? l : MMAPSIZE;
+ }
+
+
+ if (lseek(sfd, src_o, SEEK_SET) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (lseek(dfd, dst_o, SEEK_SET) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+ }
+
+ if (l > 0) {
+ if (!(buf = malloc(BUFSIZE)))
+ goto finish;
+
+ for (;;) {
+ ssize_t m;
+
+ if ((m = read(sfd, buf, BUFSIZE)) < 0) {
+ fprintf(stderr, "read(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (!m)
+ break;
+
+ if (write(dfd, buf, m) < 0) {
+ fprintf(stderr, "write(): %s\n", strerror(errno));
+ goto finish;
+ }
+ }
+ }
+
+ r = 0;
+
+finish:
+
+ return r;
+}
+
+int copy_file(const char *src, const char *dst) {
+ int sfd = -1, dfd = -1, r = -1;
+
+ if ((sfd = open(src, O_RDONLY)) < 0) {
+ fprintf(stderr, "open(%s, O_RDONLY): %s\n", src, strerror(errno));
+ goto finish;
+ }
+
+ if ((dfd = open(dst, O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "open(%s, O_RDWR|O_TRUNC|O_CREAT): %s\n", dst, strerror(errno));
+ goto finish;
+ }
+
+ if (copy_fd(sfd, dfd, (uint32_t) -1) < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+
+ if (sfd >= 0)
+ close(sfd);
+
+ if (dfd >= 0)
+ close(dfd);
+
+ return r;
+}
+
+int copy_or_link_file(const char *src, const char *dst) {
+
+ if (link(src, dst) < 0) {
+
+ if (errno == EXDEV || errno == EPERM)
+ return copy_file(src, dst);
+
+ fprintf(stderr, "link(%s, %s): %s\n", src, dst, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}