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) {