]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/copy_file_range.c
xfs_io: fix signed comparison problem in copy_file_range
[thirdparty/xfsprogs-dev.git] / io / copy_file_range.c
CommitLineData
628e112a
AS
1/*
2 * Copyright (c) 2016 Netapp, Inc. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#include <sys/syscall.h>
20#include <sys/uio.h>
21#include <xfs/xfs.h>
22#include "command.h"
23#include "input.h"
24#include "init.h"
25#include "io.h"
26
27static cmdinfo_t copy_range_cmd;
28
29static void
30copy_range_help(void)
31{
32 printf(_("\n\
33 Copies a range of bytes from a file into the open file, overwriting any data\n\
34 already there.\n\
35\n\
36 Example:\n\
37 'copy_range -s 100 -d 200 -l 300 some_file' - copies 300 bytes from some_file\n\
38 at offset 100 into the open\n\
39 file at offset 200\n\
40 'copy_range some_file' - copies all bytes from some_file into the open file\n\
41 at position 0\n\
42"));
43}
44
8041435d
DW
45/*
46 * Issue a raw copy_file_range syscall; for our test program we don't want the
47 * glibc buffered copy fallback.
48 */
628e112a 49static loff_t
25b4549c 50copy_file_range_cmd(int fd, long long *src, long long *dst, long long len)
628e112a
AS
51{
52 loff_t ret;
53
54 do {
8041435d
DW
55 ret = syscall(__NR_copy_file_range, fd, src, file->fd, dst,
56 len, 0);
43141802
AS
57 if (ret == -1) {
58 perror("copy_range");
628e112a 59 return errno;
43141802
AS
60 } else if (ret == 0)
61 break;
628e112a
AS
62 len -= ret;
63 } while (len > 0);
64
65 return 0;
66}
67
68static off64_t
69copy_src_filesize(int fd)
70{
f594a0d1 71 struct stat st;
628e112a 72
f594a0d1
FJ
73 if (fstat(fd, &st) < 0) {
74 perror("fstat");
628e112a
AS
75 return -1;
76 };
77 return st.st_size;
78}
79
80static int
81copy_dst_truncate(void)
82{
dde67673 83 int ret = ftruncate(file->fd, 0);
628e112a 84 if (ret < 0)
dde67673 85 perror("ftruncate");
628e112a
AS
86 return ret;
87}
88
89static int
90copy_range_f(int argc, char **argv)
91{
25b4549c
GR
92 long long src = 0;
93 long long dst = 0;
cb1b013b 94 long long len = 0;
628e112a
AS
95 int opt;
96 int ret;
97 int fd;
25b4549c
GR
98 size_t fsblocksize, fssectsize;
99
100 init_cvtnum(&fsblocksize, &fssectsize);
628e112a
AS
101
102 while ((opt = getopt(argc, argv, "s:d:l:")) != -1) {
103 switch (opt) {
104 case 's':
25b4549c
GR
105 src = cvtnum(fsblocksize, fssectsize, optarg);
106 if (src < 0) {
107 printf(_("invalid source offset -- %s\n"), optarg);
628e112a
AS
108 return 0;
109 }
110 break;
111 case 'd':
25b4549c
GR
112 dst = cvtnum(fsblocksize, fssectsize, optarg);
113 if (dst < 0) {
114 printf(_("invalid destination offset -- %s\n"), optarg);
628e112a
AS
115 return 0;
116 }
117 break;
118 case 'l':
25b4549c
GR
119 len = cvtnum(fsblocksize, fssectsize, optarg);
120 if (len < 0) {
121 printf(_("invalid length -- %s\n"), optarg);
628e112a
AS
122 return 0;
123 }
124 break;
125 }
126 }
127
128 if (optind != argc - 1)
129 return command_usage(&copy_range_cmd);
130
3fcab549 131 fd = openfile(argv[optind], NULL, IO_READONLY, 0, NULL);
628e112a
AS
132 if (fd < 0)
133 return 0;
134
135 if (src == 0 && dst == 0 && len == 0) {
136 len = copy_src_filesize(fd);
137 copy_dst_truncate();
138 }
139
8041435d 140 ret = copy_file_range_cmd(fd, &src, &dst, len);
628e112a
AS
141 close(fd);
142 return ret;
143}
144
145void
146copy_range_init(void)
147{
148 copy_range_cmd.name = "copy_range";
149 copy_range_cmd.cfunc = copy_range_f;
150 copy_range_cmd.argmin = 1;
151 copy_range_cmd.argmax = 7;
152 copy_range_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
153 copy_range_cmd.args = _("[-s src_off] [-d dst_off] [-l len] src_file");
154 copy_range_cmd.oneline = _("Copy a range of data between two files");
155 copy_range_cmd.help = copy_range_help;
156
157 add_command(&copy_range_cmd);
158}