Browse Source

Ticket #1983: support BTRFS's file clone operation.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
gray_-_wolf 6 years ago
parent
commit
0493a5e90e
3 changed files with 51 additions and 0 deletions
  1. 41 0
      lib/vfs/vfs.c
  2. 2 0
      lib/vfs/vfs.h
  3. 8 0
      src/filemanager/file.c

+ 41 - 0
lib/vfs/vfs.c

@@ -45,6 +45,13 @@
 #include <errno.h>
 #include <stdlib.h>
 
+#ifdef __linux__
+#include <linux/fs.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#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
 }
 
 /* --------------------------------------------------------------------------------------------- */

+ 2 - 0
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
  */

+ 8 - 0
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)
     {