1 |
The sendfile *offset parameter refers to the input file offest, so |
2 |
it cannot be used in the same way as the copy_file_range *off_out |
3 |
parameter. Therefore, add sf_wrapper function which implements the |
4 |
*off_out behavior for sendfile. |
5 |
|
6 |
Bug: https://bugs.gentoo.org/635126 |
7 |
--- |
8 |
[PATCH v3] adds an additional lseek call to ensure that the output |
9 |
file is positioned at the correct offset |
10 |
|
11 |
src/portage_util_file_copy_reflink_linux.c | 43 +++++++++++++++++++++++++----- |
12 |
1 file changed, 37 insertions(+), 6 deletions(-) |
13 |
|
14 |
diff --git a/src/portage_util_file_copy_reflink_linux.c b/src/portage_util_file_copy_reflink_linux.c |
15 |
index 4be9e0568..35a197590 100644 |
16 |
--- a/src/portage_util_file_copy_reflink_linux.c |
17 |
+++ b/src/portage_util_file_copy_reflink_linux.c |
18 |
@@ -56,7 +56,7 @@ initreflink_linux(void) |
19 |
|
20 |
/** |
21 |
* cfr_wrapper - A copy_file_range syscall wrapper function, having a |
22 |
- * function signature that is compatible with sendfile. |
23 |
+ * function signature that is compatible with sf_wrapper. |
24 |
* @fd_out: output file descriptor |
25 |
* @fd_in: input file descriptor |
26 |
* @off_out: offset of the output file |
27 |
@@ -79,6 +79,37 @@ cfr_wrapper(int fd_out, int fd_in, off_t *off_out, size_t len) |
28 |
} |
29 |
|
30 |
/** |
31 |
+ * sf_wrapper - A sendfile wrapper function, having a function signature |
32 |
+ * that is compatible with cfr_wrapper. |
33 |
+ * @fd_out: output file descriptor |
34 |
+ * @fd_in: input file descriptor |
35 |
+ * @off_out: offset of the output file |
36 |
+ * @len: number of bytes to copy between the file descriptors |
37 |
+ * |
38 |
+ * Return: Number of bytes written to out_fd on success, -1 on failure |
39 |
+ * (errno is set appropriately). |
40 |
+ */ |
41 |
+static ssize_t |
42 |
+sf_wrapper(int fd_out, int fd_in, off_t *off_out, size_t len) |
43 |
+{ |
44 |
+ ssize_t ret; |
45 |
+ if (lseek(fd_out, *off_out, SEEK_SET) < 0) |
46 |
+ return -1; |
47 |
+ ret = sendfile(fd_out, fd_in, NULL, len); |
48 |
+ if (ret > 0) { |
49 |
+ /* The sendfile docs do not guarantee that the offset of fd_in |
50 |
+ * will be adjusted by the number of bytes written, so use |
51 |
+ * lseek to guarantee it. |
52 |
+ */ |
53 |
+ if (lseek(fd_in, (*off_out) + ret, SEEK_SET) < 0) |
54 |
+ return -1; |
55 |
+ (*off_out) += ret; |
56 |
+ } |
57 |
+ return ret; |
58 |
+} |
59 |
+ |
60 |
+ |
61 |
+/** |
62 |
* do_lseek_data - Adjust file offsets to the next location containing |
63 |
* data, creating sparse empty blocks in the output file as needed. |
64 |
* @fd_in: input file descriptor |
65 |
@@ -250,7 +281,7 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) |
66 |
* syscall is not available (less than Linux 4.5). |
67 |
*/ |
68 |
error = 0; |
69 |
- copyfunc = sendfile; |
70 |
+ copyfunc = sf_wrapper; |
71 |
copyfunc_ret = copyfunc(fd_out, |
72 |
fd_in, |
73 |
&offset_out, |
74 |
@@ -293,10 +324,10 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) |
75 |
error = errno; |
76 |
} else { |
77 |
while (offset_out < stat_in.st_size) { |
78 |
- copyfunc_ret = sendfile(fd_out, |
79 |
- fd_in, |
80 |
- &offset_out, |
81 |
- stat_in.st_size - offset_out); |
82 |
+ copyfunc_ret = sf_wrapper(fd_out, |
83 |
+ fd_in, |
84 |
+ &offset_out, |
85 |
+ stat_in.st_size - offset_out); |
86 |
|
87 |
if (copyfunc_ret < 0) { |
88 |
error = errno; |
89 |
-- |
90 |
2.13.5 |