From 0493a5e90ed8e2a18325b31892bea59e2d244489 Mon Sep 17 00:00:00 2001 From: gray_-_wolf Date: Sat, 11 Aug 2018 20:48:51 +0300 Subject: [PATCH 1/3] Ticket #1983: support BTRFS's file clone operation. Signed-off-by: Andrew Borodin --- lib/vfs/vfs.c | 41 +++++++++++++++++++++++++++++++++++++++++ lib/vfs/vfs.h | 2 ++ src/filemanager/file.c | 8 ++++++++ 3 files changed, 51 insertions(+) diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index 189ca7b7c..f14a620cd 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -45,6 +45,13 @@ #include #include +#ifdef __linux__ +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif /* HAVE_SYS_IOCTL_H */ +#endif /* __linux__ */ + #include "lib/global.h" #include "lib/strutil.h" #include "lib/util.h" @@ -654,6 +661,40 @@ vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize) return posix_fallocate (*(int *) dest_fd, dest_fsize, src_fsize - dest_fsize); #endif /* HAVE_POSIX_FALLOCATE */ +} + + /* --------------------------------------------------------------------------------------------- */ + +int +vfs_clone_file (int dest_vfs_fd, int src_vfs_fd) +{ +#ifdef FICLONE + void *dest_fd = NULL; + void *src_fd = NULL; + struct vfs_class *dest_class; + struct vfs_class *src_class; + + dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd); + if (dest_fd == NULL || (dest_class->flags & VFSF_LOCAL) == 0) + { + errno = EOPNOTSUPP; + return (-1); + } + + src_class = vfs_class_find_by_handle (src_vfs_fd, &src_fd); + if (src_fd == NULL || (src_class->flags & VFSF_LOCAL) == 0) + { + errno = EOPNOTSUPP; + return (-1); + } + + return ioctl (*(int *) dest_fd, FICLONE, *(int *) src_fd); +#else + (void) dest_vfs_fd; + (void) src_vfs_fd; + errno = EOPNOTSUPP; + return (-1); +#endif } /* --------------------------------------------------------------------------------------------- */ diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index 2510195a6..58ba4b59d 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -287,6 +287,8 @@ char *_vfs_get_cwd (void); int vfs_preallocate (int dest_desc, off_t src_fsize, off_t dest_fsize); +int vfs_clone_file (int dest_vfs_fd, int src_vfs_fd); + /** * Interface functions described in interface.c */ diff --git a/src/filemanager/file.c b/src/filemanager/file.c index 9f4683a10..6683fbeed 100644 --- a/src/filemanager/file.c +++ b/src/filemanager/file.c @@ -2345,6 +2345,14 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, appending = ctx->do_append; ctx->do_append = FALSE; + /* Try clone the file first. */ + if (vfs_clone_file (dest_desc, src_desc) == 0) + { + dst_status = DEST_FULL; + return_status = FILE_CONT; + goto ret; + } + /* Find out the optimal buffer size. */ while (mc_fstat (dest_desc, &dst_stat) != 0) { From 23a2056a18a0b01d909a163b4ee503e5d2153429 Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Sat, 11 Aug 2018 20:55:10 +0300 Subject: [PATCH 2/3] (vfs_clone_file): clarify errno in case of bad file descriptors. Signed-off-by: Andrew Borodin --- lib/vfs/vfs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index f14a620cd..23203f578 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -675,18 +675,28 @@ vfs_clone_file (int dest_vfs_fd, int src_vfs_fd) struct vfs_class *src_class; dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd); - if (dest_fd == NULL || (dest_class->flags & VFSF_LOCAL) == 0) + if ((dest_class->flags & VFSF_LOCAL) == 0) { errno = EOPNOTSUPP; return (-1); } + if (dest_fd == NULL) + { + errno = EBADF; + return (-1); + } src_class = vfs_class_find_by_handle (src_vfs_fd, &src_fd); - if (src_fd == NULL || (src_class->flags & VFSF_LOCAL) == 0) + if ((src_class->flags & VFSF_LOCAL) == 0) { errno = EOPNOTSUPP; return (-1); } + if (src_fd == NULL) + { + errno = EBADF; + return (-1); + } return ioctl (*(int *) dest_fd, FICLONE, *(int *) src_fd); #else From 2e5cd866f93029776a7bdda3ac3e74bd7591c3a9 Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Sat, 11 Aug 2018 21:00:42 +0300 Subject: [PATCH 3/3] Check linux/fs.h file. Signed-off-by: Andrew Borodin --- configure.ac | 6 ++++++ lib/vfs/vfs.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index bf2e98b2a..a0c88fb0e 100644 --- a/configure.ac +++ b/configure.ac @@ -304,6 +304,12 @@ AC_EGREP_CPP([yes], AC_MSG_RESULT(no) ]) +dnl Check linux/fs.h for FICLONE to support BTRFS's file clone operation +case $host_os in +linux*) + AC_CHECK_HEADERS([linux/fs.h]) +esac + dnl Check if the OS is supported by the console saver. cons_saver="" case $host_os in diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index 23203f578..ea58c2f32 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -46,7 +46,9 @@ #include #ifdef __linux__ +#ifdef HAVE_LINUX_FS_H #include +#endif /* HAVE_LINUX_FS_H */ #ifdef HAVE_SYS_IOCTL_H #include #endif /* HAVE_SYS_IOCTL_H */