1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2011 Oracle. All rights reserved.
5 #define _XOPEN_SOURCE 500
12 #include <sys/types.h>
26 #define MIN(a,b) ((a)<(b)?(a):(b))
30 error(const char *fmt, ...)
35 vsprintf(buf, fmt, args);
38 fprintf(stderr, "ERROR: [%s:%d] %s:%s\n", __func__, __LINE__,
39 buf, strerror(errno));
43 full_write(int fd, const void *buf, size_t count)
46 const char *ptr = (const char *) buf;
49 ssize_t n = write(fd, ptr, count);
53 error("failed as %s", strerror(errno));
58 error("%zu bytes transferred. Aborting.",
72 * Copy a data extent from source file to dest file.
73 * @data_off: data offset
74 * @hole_off: hole offset
75 * The length of this extent is (hole_off - data_off).
78 do_extent_copy(int src_fd, int dest_fd, off_t data_off, off_t hole_off)
80 uint64_t len = (uint64_t)(hole_off - data_off);
84 /* Seek to data_off for data reading */
85 ret = lseek(src_fd, data_off, SEEK_SET);
87 error("seek source file to %llu failed as %s",
88 (uint64_t)data_off, strerror(errno));
92 /* Seek to data_off for data writing, make holes as well */
93 ret = lseek(dest_fd, data_off, SEEK_SET);
95 error("seek dest file to %llu failed as %s",
96 (uint64_t)data_off, strerror(errno));
101 ssize_t nr_read = read(src_fd, buf, BUF_SIZE);
105 error("read source file extent failed as %s",
112 error("reached EOF");
116 if (full_write(dest_fd, buf, nr_read) != nr_read) {
117 error("write data to dest file failed as %s",
130 * If lseek(2) failed and the errno is set to ENXIO, for
131 * SEEK_DATA there are no more data regions past the supplied
132 * offset. For SEEK_HOLE, there are no more holes past the
133 * supplied offset. Set scan->hit_final_extent to true for
137 copy_extents(int src_fd, int dest_fd, off_t src_total_size)
140 off_t seek_start = 0;
142 off_t data_pos, hole_pos;
145 data_pos = lseek(src_fd, seek_start, SEEK_DATA);
150 error("SEEK_DATA failed due to %s",
157 hole_pos = lseek(src_fd, data_pos, SEEK_HOLE);
162 error("SEEK_HOLE failed due to %s\n",
170 ret = do_extent_copy(src_fd, dest_fd, data_pos, hole_pos);
172 error("copy extent failed");
176 dest_pos += (hole_pos - data_pos);
177 seek_start = hole_pos;
178 } while (seek_start < src_total_size);
180 if (dest_pos < src_total_size) {
181 ret = ftruncate(dest_fd, src_total_size);
183 error("truncate dest file to %lld bytes failed as %s",
184 (long long)src_total_size, strerror(errno));
192 main(int argc, char **argv)
198 size_t src_total_size;
201 fprintf(stdout, "Usage: %s source dest\n", argv[0]);
205 src_fd = open(argv[1], O_RDONLY, 0644);
207 error("create %s failed", argv[1]);
211 dest_fd = open(argv[2], O_RDWR|O_CREAT|O_EXCL, 0644);
213 error("create %s failed", argv[2]);
218 ret = fstat(src_fd, &st);
220 error("get file %s staticis failed", argv[1]);
225 src_total_size = st.st_size;
226 ret = copy_extents(src_fd, dest_fd, src_total_size);
228 error("extents copy failed");