diff options
author | Giuseppe Scrivano <gscrivano@gnu.org> | 2009-07-25 16:35:27 +0200 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2009-07-29 12:15:50 +0200 |
commit | 45330176690b079ed47ac7c58f29a1b028f97b07 (patch) | |
tree | 2f0f4637db6debaec9ed57e9b98584413893be4b /src | |
parent | 095861179cad632893106670226a4658199a4f95 (diff) | |
download | coreutils-45330176690b079ed47ac7c58f29a1b028f97b07.tar.xz |
cp: support btrfs' copy-on-write file clone operation
* src/copy.c [HAVE_SYS_IOCTL_H]: Include <sys/ioctl.h>.
(BTRFS_IOCTL_MAGIC, BTRFS_IOC_CLONE): Define.
(clone_file): New function.
(copy_reg): Use the btrfs clone operation if possible.
Diffstat (limited to 'src')
-rw-r--r-- | src/copy.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/src/copy.c b/src/copy.c index 4c8c432fc..bbed336b1 100644 --- a/src/copy.c +++ b/src/copy.c @@ -61,6 +61,10 @@ # include "verror.h" #endif +#if HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + #ifndef HAVE_FCHOWN # define HAVE_FCHOWN false # define fchown(fd, uid, gid) (-1) @@ -114,6 +118,23 @@ static bool owner_failure_ok (struct cp_options const *x); static char const *top_level_src_name; static char const *top_level_dst_name; +/* Perform the O(1) btrfs clone operation, if possible. + Upon success, return 0. Otherwise, return -1 and set errno. */ +static inline int +clone_file (int dest_fd, int src_fd) +{ +#ifdef __linux__ +# undef BTRFS_IOCTL_MAGIC +# define BTRFS_IOCTL_MAGIC 0x94 +# undef BTRFS_IOC_CLONE +# define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int) + return ioctl (dest_fd, BTRFS_IOC_CLONE, src_fd); +#else + errno = ENOTSUP; + return -1; +#endif +} + /* FIXME: describe */ /* FIXME: rewrite this to use a hash table so we avoid the quadratic performance hit that's probably noticeable only on trees deeper @@ -589,6 +610,13 @@ copy_reg (char const *src_name, char const *dst_name, goto close_src_and_dst_desc; } + /* If --sparse=auto is in effect, attempt a btrfs clone operation. + If the operation is not supported or it fails then copy the file + in the usual way. */ + bool copied = (x->sparse_mode == SPARSE_AUTO + && clone_file (dest_desc, source_desc) == 0); + + if (!copied) { typedef uintptr_t word; off_t n_read_total = 0; |