diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 158 |
1 files changed, 152 insertions, 6 deletions
@@ -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); +} + |