4646#include <errno.h>
4747#include <stdlib.h>
4848
49- #ifdef __linux__
50- #ifdef HAVE_LINUX_FS_H
51- #include <linux/fs.h>
52- #endif
53- #ifdef HAVE_SYS_IOCTL_H
54- #include <sys/ioctl.h>
55- #endif
49+ #ifdef HAVE_FICLONERANGE
50+ #include <linux/fs.h> // FICLONERANGE
51+ #include <sys/ioctl.h> // ioctl()
52+ #elif defined(HAVE_COPY_FILE_RANGE )
53+ #include <unistd.h> // COPY_FILE_RANGE_CLONE
54+ #elif defined(HAVE_SYS_CLONEFILE_H )
55+ #include <sys/clonefile.h> // CLONE_NOOWNERCOPY
56+ #elif defined(HAVE_REFLINK )
57+ #include <unistd.h> // reflink()
5658#endif
5759
5860#include "lib/global.h"
@@ -720,11 +722,12 @@ vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize)
720722int
721723vfs_clone_file (int dest_vfs_fd , int src_vfs_fd )
722724{
723- #ifdef FICLONE
725+ #ifdef HAVE_FILE_CLONING_BY_RANGE
724726 void * dest_fd = NULL ;
725727 void * src_fd = NULL ;
726728 struct vfs_class * dest_class ;
727729 struct vfs_class * src_class ;
730+ off_t in_offset , out_offset ;
728731
729732 dest_class = vfs_class_find_by_handle (dest_vfs_fd , & dest_fd );
730733 if ((dest_class -> flags & VFSF_LOCAL ) == 0 )
@@ -750,7 +753,38 @@ vfs_clone_file (int dest_vfs_fd, int src_vfs_fd)
750753 return (-1 );
751754 }
752755
753- return ioctl (* (int * ) dest_fd , FICLONE , * (int * ) src_fd );
756+ in_offset = mc_lseek (src_vfs_fd , 0 , SEEK_CUR );
757+ if (in_offset < 0 )
758+ return (-1 );
759+ out_offset = mc_lseek (dest_vfs_fd , 0 , SEEK_CUR );
760+ if (out_offset < 0 )
761+ return (-1 );
762+
763+ #if defined(FICLONERANGE )
764+ {
765+ struct file_clone_range fcr = {
766+ .src_fd = * (int * ) src_fd ,
767+ .src_offset = in_offset ,
768+ .src_length = 0 ,
769+ .dest_offset = out_offset ,
770+ };
771+
772+ return ioctl (* (int * ) dest_fd , FICLONERANGE , & fcr );
773+ }
774+ #elif defined(COPY_FILE_RANGE_CLONE )
775+ {
776+ ssize_t result ;
777+
778+ do
779+ {
780+ result = copy_file_range (* (int * ) src_fd , & in_offset , * (int * ) dest_fd , & out_offset ,
781+ SSIZE_MAX , COPY_FILE_RANGE_CLONE );
782+ }
783+ while (result > 0 );
784+ return result ;
785+ }
786+ #endif
787+
754788#else
755789 (void ) dest_vfs_fd ;
756790 (void ) src_vfs_fd ;
@@ -760,3 +794,40 @@ vfs_clone_file (int dest_vfs_fd, int src_vfs_fd)
760794}
761795
762796/* --------------------------------------------------------------------------------------------- */
797+
798+ int
799+ vfs_clone_file_by_path (const vfs_path_t * dest_vpath , const vfs_path_t * src_vpath ,
800+ gboolean preserve_uidgid )
801+ {
802+ #ifdef HAVE_FILE_CLONING_BY_PATH
803+ const char * src_path ;
804+ const char * dest_path ;
805+
806+ if (!vfs_file_is_local (dest_vpath ) || !vfs_file_is_local (src_vpath ))
807+ {
808+ errno = ENOTSUP ;
809+ return (-1 );
810+ }
811+
812+ src_path = vfs_path_get_last_path_str (src_vpath );
813+ dest_path = vfs_path_get_last_path_str (dest_vpath );
814+
815+ #if defined(HAVE_SYS_CLONEFILE_H )
816+ #ifndef CLONE_NOOWNERCOPY // macOS 10.13+
817+ #define CLONE_NOOWNERCOPY 0
818+ #endif
819+ return my_clonefile (src_path , dest_path , preserve_uidgid ? 0 : CLONE_NOOWNERCOPY );
820+ #elif defined(HAVE_REFLINK )
821+ return reflink (src_path , dest_path , preserve_uidgid );
822+ #endif
823+
824+ #else
825+ (void ) dest_vpath ;
826+ (void ) src_vpath ;
827+ (void ) preserve_uidgid ;
828+ errno = ENOTSUP ;
829+ return (-1 );
830+ #endif
831+ }
832+
833+ /* --------------------------------------------------------------------------------------------- */
0 commit comments