mirror of https://github.com/trapexit/mergerfs.git
20 changed files with 1116 additions and 1593 deletions
-
20Makefile
-
18libfuse/Makefile
-
64libfuse/include/fuse_common.h
-
24libfuse/include/fuse_lowlevel.h
-
316libfuse/lib/buffer.c
-
2libfuse/lib/crc32b.c
-
62libfuse/lib/fuse.cpp
-
140libfuse/lib/fuse_lowlevel.cpp
-
19libfuse/util/fusermount.c
-
1src/branches.cpp
-
7src/branches.hpp
-
4src/config.cpp
-
2src/config.hpp
-
2src/config_pagesize.hpp
-
2src/fs_copyfile.cpp
-
2src/fs_glob.cpp
-
2src/fs_wait_for_mount.cpp
-
1src/fuse_create.cpp
-
1src/fuse_open.cpp
-
2src/fuse_readdir.cpp
@ -1,316 +0,0 @@ |
|||
/* |
|||
FUSE: Filesystem in Userspace |
|||
Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu> |
|||
|
|||
This program can be distributed under the terms of the GNU LGPLv2. |
|||
See the file COPYING.LIB |
|||
*/ |
|||
|
|||
#define _GNU_SOURCE |
|||
|
|||
#include "fuse_i.h" |
|||
#include "fuse_lowlevel.h" |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <errno.h> |
|||
#include <assert.h> |
|||
|
|||
size_t fuse_buf_size(const struct fuse_bufvec *bufv) |
|||
{ |
|||
size_t i; |
|||
size_t size = 0; |
|||
|
|||
for (i = 0; i < bufv->count; i++) { |
|||
if (bufv->buf[i].size == SIZE_MAX) |
|||
size = SIZE_MAX; |
|||
else |
|||
size += bufv->buf[i].size; |
|||
} |
|||
|
|||
return size; |
|||
} |
|||
|
|||
static size_t min_size(size_t s1, size_t s2) |
|||
{ |
|||
return s1 < s2 ? s1 : s2; |
|||
} |
|||
|
|||
static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off, |
|||
const struct fuse_buf *src, size_t src_off, |
|||
size_t len) |
|||
{ |
|||
ssize_t res = 0; |
|||
size_t copied = 0; |
|||
|
|||
while (len) { |
|||
if (dst->flags & FUSE_BUF_FD_SEEK) { |
|||
res = pwrite(dst->fd, src->mem + src_off, len, |
|||
dst->pos + dst_off); |
|||
} else { |
|||
res = write(dst->fd, src->mem + src_off, len); |
|||
} |
|||
if (res == -1) { |
|||
if (!copied) |
|||
return -errno; |
|||
break; |
|||
} |
|||
if (res == 0) |
|||
break; |
|||
|
|||
copied += res; |
|||
if (!(dst->flags & FUSE_BUF_FD_RETRY)) |
|||
break; |
|||
|
|||
src_off += res; |
|||
dst_off += res; |
|||
len -= res; |
|||
} |
|||
|
|||
return copied; |
|||
} |
|||
|
|||
static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off, |
|||
const struct fuse_buf *src, size_t src_off, |
|||
size_t len) |
|||
{ |
|||
ssize_t res = 0; |
|||
size_t copied = 0; |
|||
|
|||
while (len) { |
|||
if (src->flags & FUSE_BUF_FD_SEEK) { |
|||
res = pread(src->fd, dst->mem + dst_off, len, |
|||
src->pos + src_off); |
|||
} else { |
|||
res = read(src->fd, dst->mem + dst_off, len); |
|||
} |
|||
if (res == -1) { |
|||
if (!copied) |
|||
return -errno; |
|||
break; |
|||
} |
|||
if (res == 0) |
|||
break; |
|||
|
|||
copied += res; |
|||
if (!(src->flags & FUSE_BUF_FD_RETRY)) |
|||
break; |
|||
|
|||
dst_off += res; |
|||
src_off += res; |
|||
len -= res; |
|||
} |
|||
|
|||
return copied; |
|||
} |
|||
|
|||
static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off, |
|||
const struct fuse_buf *src, size_t src_off, |
|||
size_t len) |
|||
{ |
|||
char buf[4096]; |
|||
struct fuse_buf tmp = { |
|||
.size = sizeof(buf), |
|||
.flags = 0, |
|||
}; |
|||
ssize_t res; |
|||
size_t copied = 0; |
|||
|
|||
tmp.mem = buf; |
|||
|
|||
while (len) { |
|||
size_t this_len = min_size(tmp.size, len); |
|||
size_t read_len; |
|||
|
|||
res = fuse_buf_read(&tmp, 0, src, src_off, this_len); |
|||
if (res < 0) { |
|||
if (!copied) |
|||
return res; |
|||
break; |
|||
} |
|||
if (res == 0) |
|||
break; |
|||
|
|||
read_len = res; |
|||
res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len); |
|||
if (res < 0) { |
|||
if (!copied) |
|||
return res; |
|||
break; |
|||
} |
|||
if (res == 0) |
|||
break; |
|||
|
|||
copied += res; |
|||
|
|||
if (res < this_len) |
|||
break; |
|||
|
|||
dst_off += res; |
|||
src_off += res; |
|||
len -= res; |
|||
} |
|||
|
|||
return copied; |
|||
} |
|||
|
|||
#ifdef HAVE_SPLICE |
|||
static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off, |
|||
const struct fuse_buf *src, size_t src_off, |
|||
size_t len, enum fuse_buf_copy_flags flags) |
|||
{ |
|||
int splice_flags = 0; |
|||
off_t *srcpos = NULL; |
|||
off_t *dstpos = NULL; |
|||
off_t srcpos_val; |
|||
off_t dstpos_val; |
|||
ssize_t res; |
|||
size_t copied = 0; |
|||
|
|||
if (flags & FUSE_BUF_SPLICE_MOVE) |
|||
splice_flags |= SPLICE_F_MOVE; |
|||
if (flags & FUSE_BUF_SPLICE_NONBLOCK) |
|||
splice_flags |= SPLICE_F_NONBLOCK; |
|||
|
|||
if (src->flags & FUSE_BUF_FD_SEEK) { |
|||
srcpos_val = src->pos + src_off; |
|||
srcpos = &srcpos_val; |
|||
} |
|||
if (dst->flags & FUSE_BUF_FD_SEEK) { |
|||
dstpos_val = dst->pos + dst_off; |
|||
dstpos = &dstpos_val; |
|||
} |
|||
|
|||
while (len) { |
|||
res = splice(src->fd, srcpos, dst->fd, dstpos, len, splice_flags); |
|||
if (res == -1) { |
|||
if (copied) |
|||
break; |
|||
|
|||
if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE)) |
|||
return -errno; |
|||
|
|||
/* Maybe splice is not supported for this combination */ |
|||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, |
|||
len); |
|||
} |
|||
if (res == 0) |
|||
break; |
|||
|
|||
copied += res; |
|||
if (!(src->flags & FUSE_BUF_FD_RETRY) && |
|||
!(dst->flags & FUSE_BUF_FD_RETRY)) { |
|||
break; |
|||
} |
|||
|
|||
len -= res; |
|||
} |
|||
|
|||
return copied; |
|||
} |
|||
#else |
|||
static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off, |
|||
const struct fuse_buf *src, size_t src_off, |
|||
size_t len, enum fuse_buf_copy_flags flags) |
|||
{ |
|||
(void) flags; |
|||
|
|||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); |
|||
} |
|||
#endif |
|||
|
|||
|
|||
static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off, |
|||
const struct fuse_buf *src, size_t src_off, |
|||
size_t len, enum fuse_buf_copy_flags flags) |
|||
{ |
|||
int src_is_fd = src->flags & FUSE_BUF_IS_FD; |
|||
int dst_is_fd = dst->flags & FUSE_BUF_IS_FD; |
|||
|
|||
if (!src_is_fd && !dst_is_fd) { |
|||
char *dstmem = dst->mem + dst_off; |
|||
char *srcmem = src->mem + src_off; |
|||
|
|||
if (dstmem != srcmem) { |
|||
if (dstmem + len <= srcmem || srcmem + len <= dstmem) |
|||
memcpy(dstmem, srcmem, len); |
|||
else |
|||
memmove(dstmem, srcmem, len); |
|||
} |
|||
|
|||
return len; |
|||
} else if (!src_is_fd) { |
|||
return fuse_buf_write(dst, dst_off, src, src_off, len); |
|||
} else if (!dst_is_fd) { |
|||
return fuse_buf_read(dst, dst_off, src, src_off, len); |
|||
} else if (flags & FUSE_BUF_NO_SPLICE) { |
|||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); |
|||
} else { |
|||
return fuse_buf_splice(dst, dst_off, src, src_off, len, flags); |
|||
} |
|||
} |
|||
|
|||
static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv) |
|||
{ |
|||
if (bufv->idx < bufv->count) |
|||
return &bufv->buf[bufv->idx]; |
|||
else |
|||
return NULL; |
|||
} |
|||
|
|||
static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len) |
|||
{ |
|||
const struct fuse_buf *buf = fuse_bufvec_current(bufv); |
|||
|
|||
bufv->off += len; |
|||
assert(bufv->off <= buf->size); |
|||
if (bufv->off == buf->size) { |
|||
assert(bufv->idx < bufv->count); |
|||
bufv->idx++; |
|||
if (bufv->idx == bufv->count) |
|||
return 0; |
|||
bufv->off = 0; |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv, |
|||
enum fuse_buf_copy_flags flags) |
|||
{ |
|||
size_t copied = 0; |
|||
|
|||
if (dstv == srcv) |
|||
return fuse_buf_size(dstv); |
|||
|
|||
for (;;) { |
|||
const struct fuse_buf *src = fuse_bufvec_current(srcv); |
|||
const struct fuse_buf *dst = fuse_bufvec_current(dstv); |
|||
size_t src_len; |
|||
size_t dst_len; |
|||
size_t len; |
|||
ssize_t res; |
|||
|
|||
if (src == NULL || dst == NULL) |
|||
break; |
|||
|
|||
src_len = src->size - srcv->off; |
|||
dst_len = dst->size - dstv->off; |
|||
len = min_size(src_len, dst_len); |
|||
|
|||
res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags); |
|||
if (res < 0) { |
|||
if (!copied) |
|||
return res; |
|||
break; |
|||
} |
|||
copied += res; |
|||
|
|||
if (!fuse_bufvec_advance(srcv, res) || |
|||
!fuse_bufvec_advance(dstv, res)) |
|||
break; |
|||
|
|||
if (res < len) |
|||
break; |
|||
} |
|||
|
|||
return copied; |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue