summaryrefslogtreecommitdiff
path: root/src/basic/copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic/copy.c')
-rw-r--r--src/basic/copy.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/src/basic/copy.c b/src/basic/copy.c
index cc5faa80a1..b20c178727 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -29,7 +29,7 @@
#define COPY_BUFFER_SIZE (16*1024)
-int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
+int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
bool try_sendfile = true, try_splice = true;
int r;
@@ -37,22 +37,26 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
assert(fdt >= 0);
/* Try btrfs reflinks first. */
- if (try_reflink && max_bytes == (off_t) -1) {
+ if (try_reflink &&
+ max_bytes == (uint64_t) -1 &&
+ lseek(fdf, 0, SEEK_CUR) == 0 &&
+ lseek(fdt, 0, SEEK_CUR) == 0) {
+
r = btrfs_reflink(fdf, fdt);
if (r >= 0)
- return r;
+ return 0; /* we copied the whole thing, hence hit EOF, return 0 */
}
for (;;) {
size_t m = COPY_BUFFER_SIZE;
ssize_t n;
- if (max_bytes != (off_t) -1) {
+ if (max_bytes != (uint64_t) -1) {
if (max_bytes <= 0)
- return -EFBIG;
+ return 1; /* return > 0 if we hit the max_bytes limit */
- if ((off_t) m > max_bytes)
+ if ((uint64_t) m > max_bytes)
m = (size_t) max_bytes;
}
@@ -75,7 +79,7 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
/* The try splice, unless we already tried */
if (try_splice) {
- n = splice(fdf, NULL, fdt, NULL, m, 0);
+ n = splice(fdf, NULL, fdt, NULL, m, 0);
if (n < 0) {
if (errno != EINVAL && errno != ENOSYS)
return -errno;
@@ -91,7 +95,7 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
/* As a fallback just copy bits by hand */
{
- char buf[m];
+ uint8_t buf[m];
n = read(fdf, buf, m);
if (n < 0)
@@ -105,13 +109,13 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
}
next:
- if (max_bytes != (off_t) -1) {
- assert(max_bytes >= n);
+ if (max_bytes != (uint64_t) -1) {
+ assert(max_bytes >= (uint64_t) n);
max_bytes -= n;
}
}
- return 0;
+ return 0; /* return 0 if we hit EOF earlier than the size limit */
}
static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
@@ -152,7 +156,7 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
if (fdt < 0)
return -errno;
- r = copy_bytes(fdf, fdt, (off_t) -1, true);
+ r = copy_bytes(fdf, fdt, (uint64_t) -1, true);
if (r < 0) {
unlinkat(dt, to, 0);
return r;
@@ -371,7 +375,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
if (fdf < 0)
return -errno;
- r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
+ r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink);
(void) copy_times(fdf, fdt);
(void) copy_xattr(fdf, fdt);