aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2010-11-10 11:41:21 +0100
committerMiklos Szeredi <mszeredi@suse.cz>2010-11-10 11:41:21 +0100
commit4367f2df5038e369fef031e49448745e7065d179 (patch)
tree00d27b93f36cd05975b91cb9ecd3c827e227f35e
parent42bcaf301e9e06836e0a504b211b7fa95260493f (diff)
downloadlibfuse-4367f2df5038e369fef031e49448745e7065d179.tar.gz
fuse_buf_copy: check if buffers are the same
When copying fuse buffers, check if the source and destination are the same and omit the copy as appropriate. Also check if the source and destination memory regions overlap and use memmove in that case.
-rw-r--r--lib/buffer.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/lib/buffer.c b/lib/buffer.c
index 0006cbf..cb734a3 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -217,7 +217,16 @@ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
if (!src_is_fd && !dst_is_fd) {
- memcpy(dst->mem + dst_off, src->mem + src_off, len);
+ void *dstmem = dst->mem + dst_off;
+ void *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);
@@ -259,6 +268,9 @@ ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
{
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);