summaryrefslogtreecommitdiffstats
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c158
1 files changed, 152 insertions, 6 deletions
diff --git a/src/util.c b/src/util.c
index ed93e6b..56be93c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,3 +1,5 @@
+#define USE_SENDFILE
+
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
@@ -9,6 +11,10 @@
#include <sys/mman.h>
#include <fcntl.h>
+#ifdef USE_SENDFILE
+#include <sys/sendfile.h>
+#endif
+
#include "util.h"
void statistics(DB *db) {
@@ -118,6 +124,10 @@ int copy_fd(int sfd, int dfd, uint32_t l) {
void *buf = NULL;
int r = -1;
struct stat st;
+#ifdef USE_SENDFILE
+ ssize_t k;
+ off_t sfo;
+#endif
if ((src_o = lseek(sfd, 0, SEEK_CUR)) == (off_t) -1) {
fprintf(stderr, "lseek(): %s\n", strerror(errno));
@@ -148,6 +158,25 @@ int copy_fd(int sfd, int dfd, uint32_t l) {
goto finish;
}
+
+#ifdef USE_SENDFILE
+
+ sfo = src_o;
+ if ((k = sendfile(dfd, sfd, &sfo, l)) > 0) {
+
+ l -= k;
+ dst_o += k;
+ src_o = sfo;
+
+ if (lseek(sfd, src_o, SEEK_SET) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+ } else if (k < 0)
+ fprintf(stderr, "sendfile() failed for file copy, trying mmap(): %s\n", strerror(errno));
+
+#endif
+
if (l > BUFSIZE) {
uint32_t m = l < MMAPSIZE ? l : MMAPSIZE;
@@ -182,6 +211,9 @@ int copy_fd(int sfd, int dfd, uint32_t l) {
fprintf(stderr, "lseek(): %s\n", strerror(errno));
goto finish;
}
+
+ if (l > 0)
+ fprintf(stderr, "mmap() failed for file copy, trying read()/write(): %s\n", strerror(errno));
}
if (l > 0) {
@@ -213,16 +245,16 @@ finish:
return r;
}
-int copy_file(const char *src, const char *dst) {
+int copy_file(const char *src, const char *dst, int c) {
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));
+ 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));
+ if ((dfd = open(dst, O_RDWR|O_TRUNC|O_CREAT|( c ? 0 : O_EXCL), 0666)) < 0) {
+ fprintf(stderr, "open(\"%s\", O_RDWR|O_TRUNC|O_CREAT%s): %s\n", dst, c ? "" : "|O_EXCL", strerror(errno));
goto finish;
}
@@ -242,12 +274,15 @@ finish:
return r;
}
-int copy_or_link_file(const char *src, const char *dst) {
+int copy_or_link_file(const char *src, const char *dst, int c) {
+ if (c)
+ unlink(dst);
+
if (link(src, dst) < 0) {
if (errno == EXDEV || errno == EPERM)
- return copy_file(src, dst);
+ return copy_file(src, dst, c);
fprintf(stderr, "link(%s, %s): %s\n", src, dst, strerror(errno));
return -1;
@@ -255,3 +290,114 @@ int copy_or_link_file(const char *src, const char *dst) {
return 0;
}
+
+int move_file(const char *src, const char *dst, int c) {
+ int r;
+
+ if ((r = copy_or_link_file(src, dst, c)) < 0)
+ return -1;
+
+ if (unlink(src) < 0) {
+ fprintf(stderr, "unlink(%s): %s\n", src, strerror(errno));
+ unlink(dst);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int prune_empty_directories(const char *path, const char *root) {
+ char rroot[PATH_MAX],
+ rpath[PATH_MAX];
+
+ strncpy(rroot, root, PATH_MAX);
+ rroot[PATH_MAX-1] = 0;
+ normalize_path(rroot);
+
+ strncpy(rpath, path, PATH_MAX);
+ rpath[PATH_MAX-1] = 0;
+ normalize_path(rpath);
+
+ for (;;) {
+ char *e;
+
+ if (!rpath[0])
+ break;
+
+ if (!strcmp(rpath, "/"))
+ break;
+
+ if (!strcmp(rpath, rroot))
+ break;
+
+ if (rmdir(rpath) < 0) {
+
+ if (errno == ENOTEMPTY)
+ break;
+
+ if (errno != ENOENT) {
+ fprintf(stderr, "rmdir(\"%s\"): %s\n", rpath, strerror(errno));
+ return -1;
+ }
+ }
+
+ if (!(e = strrchr(rpath, '/')))
+ break;
+
+ *e = 0;
+
+ }
+
+ return 0;
+}
+
+int mkdir_p(const char *path, mode_t m) {
+ char tmp[PATH_MAX];
+ char *e, *b;
+ int quit = 0;
+
+ strncpy(tmp, path, PATH_MAX);
+ tmp[PATH_MAX-1] = 0;
+
+ normalize_path(tmp);
+
+ for (b = tmp, quit = 0; !quit;) {
+
+ if (!(e = strchr(b, '/'))) {
+ e = strchr(b, 0);
+ quit = 1;
+ }
+
+ *e = 0;
+ if (mkdir(tmp, m) < 0) {
+ if (errno != EEXIST) {
+ fprintf(stderr, "mkdir(\"%s\"): %s\n", tmp, strerror(errno));
+ return -1;
+ }
+ }
+ *e = '/';
+
+ b = e+1;
+ }
+
+ return 0;
+}
+
+/* Create all leading directories in path */
+int makeprefixpath(const char *path, mode_t m) {
+ char tmp[PATH_MAX], *e;
+
+ strncpy(tmp, path, PATH_MAX);
+ tmp[PATH_MAX-1] = 0;
+
+ normalize_path(tmp);
+
+ if (!(e = strrchr(tmp, '/')))
+ return 0;
+
+ *e = 0;
+
+ return mkdir_p(tmp, m);
+}
+