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 v2] updates sf_wrapper to guarantee that the offset of |
9 |
fd_in is in sync with *off_out on success |
10 |
|
11 |
src/portage_util_file_copy_reflink_linux.c | 41 +++++++++++++++++++++++++----- |
12 |
1 file changed, 35 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..3e97730df 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,35 @@ 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 |
+ ret = sendfile(fd_out, fd_in, NULL, len); |
46 |
+ if (ret > 0) { |
47 |
+ /* The sendfile docs do not guarantee that the offset of fd_in |
48 |
+ * will be adjusted by the number of bytes written, so use |
49 |
+ * lseek to guarantee it. |
50 |
+ */ |
51 |
+ if (lseek(fd_in, (*off_out) + ret, SEEK_SET) < 0) |
52 |
+ return -1; |
53 |
+ (*off_out) += ret; |
54 |
+ } |
55 |
+ return ret; |
56 |
+} |
57 |
+ |
58 |
+ |
59 |
+/** |
60 |
* do_lseek_data - Adjust file offsets to the next location containing |
61 |
* data, creating sparse empty blocks in the output file as needed. |
62 |
* @fd_in: input file descriptor |
63 |
@@ -250,7 +279,7 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) |
64 |
* syscall is not available (less than Linux 4.5). |
65 |
*/ |
66 |
error = 0; |
67 |
- copyfunc = sendfile; |
68 |
+ copyfunc = sf_wrapper; |
69 |
copyfunc_ret = copyfunc(fd_out, |
70 |
fd_in, |
71 |
&offset_out, |
72 |
@@ -293,10 +322,10 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) |
73 |
error = errno; |
74 |
} else { |
75 |
while (offset_out < stat_in.st_size) { |
76 |
- copyfunc_ret = sendfile(fd_out, |
77 |
- fd_in, |
78 |
- &offset_out, |
79 |
- stat_in.st_size - offset_out); |
80 |
+ copyfunc_ret = sf_wrapper(fd_out, |
81 |
+ fd_in, |
82 |
+ &offset_out, |
83 |
+ stat_in.st_size - offset_out); |
84 |
|
85 |
if (copyfunc_ret < 0) { |
86 |
error = errno; |
87 |
-- |
88 |
2.13.5 |