]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/copy_file_range.c
xfs_io: refactor inode command
[thirdparty/xfsprogs-dev.git] / io / copy_file_range.c
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
27 static cmdinfo_t copy_range_cmd;
28
29 static void
30 copy_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
45 static loff_t
46 copy_file_range(int fd, loff_t *src, loff_t *dst, size_t len)
47 {
48 loff_t ret;
49
50 do {
51 ret = syscall(__NR_copy_file_range, fd, src, file->fd, dst, len, 0);
52 if (ret == -1)
53 return errno;
54 len -= ret;
55 } while (len > 0);
56
57 return 0;
58 }
59
60 static off64_t
61 copy_src_filesize(int fd)
62 {
63 struct stat64 st;
64
65 if (fstat64(fd, &st) < 0) {
66 perror("fstat64");
67 return -1;
68 };
69 return st.st_size;
70 }
71
72 static int
73 copy_dst_truncate(void)
74 {
75 int ret = ftruncate64(file->fd, 0);
76 if (ret < 0)
77 perror("ftruncate64");
78 return ret;
79 }
80
81 static int
82 copy_range_f(int argc, char **argv)
83 {
84 loff_t src = 0;
85 loff_t dst = 0;
86 size_t len = 0;
87 char *sp;
88 int opt;
89 int ret;
90 int fd;
91
92 while ((opt = getopt(argc, argv, "s:d:l:")) != -1) {
93 switch (opt) {
94 case 's':
95 src = strtoull(optarg, &sp, 10);
96 if (!sp || sp == optarg) {
97 printf(_("invalid source offset -- %s\n"), sp);
98 return 0;
99 }
100 break;
101 case 'd':
102 dst = strtoull(optarg, &sp, 10);
103 if (!sp || sp == optarg) {
104 printf(_("invalid destination offset -- %s\n"), sp);
105 return 0;
106 }
107 break;
108 case 'l':
109 len = strtoull(optarg, &sp, 10);
110 if (!sp || sp == optarg) {
111 printf(_("invalid length -- %s\n"), sp);
112 return 0;
113 }
114 break;
115 }
116 }
117
118 if (optind != argc - 1)
119 return command_usage(&copy_range_cmd);
120
121 fd = openfile(argv[optind], NULL, IO_READONLY, 0);
122 if (fd < 0)
123 return 0;
124
125 if (src == 0 && dst == 0 && len == 0) {
126 len = copy_src_filesize(fd);
127 copy_dst_truncate();
128 }
129
130 ret = copy_file_range(fd, &src, &dst, len);
131 close(fd);
132 return ret;
133 }
134
135 void
136 copy_range_init(void)
137 {
138 copy_range_cmd.name = "copy_range";
139 copy_range_cmd.cfunc = copy_range_f;
140 copy_range_cmd.argmin = 1;
141 copy_range_cmd.argmax = 7;
142 copy_range_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
143 copy_range_cmd.args = _("[-s src_off] [-d dst_off] [-l len] src_file");
144 copy_range_cmd.oneline = _("Copy a range of data between two files");
145 copy_range_cmd.help = copy_range_help;
146
147 add_command(&copy_range_cmd);
148 }