1 /**
2  * BTRFS_IOC_FILE_CLONE_RANGE.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.sys.btrfs.clone_range;
15 
16 version(linux):
17 
18 import core.stdc.errno;
19 import core.sys.posix.sys.ioctl;
20 
21 import std.exception;
22 import std.stdio : File;
23 
24 import ae.sys.btrfs.common;
25 
26 private:
27 
28 enum BTRFS_IOC_FILE_CLONE_RANGE = _IOW!btrfs_ioctl_clone_range_args(BTRFS_IOCTL_MAGIC, 13);
29 
30 struct btrfs_ioctl_clone_range_args
31 {
32 	long src_fd;
33 	ulong src_offset, src_length;
34 	ulong dest_offset;
35 }
36 
37 public:
38 
39 void cloneRange(
40 	in ref File srcFile, ulong srcOffset,
41 	in ref File dstFile, ulong dstOffset,
42 	ulong length)
43 {
44 	btrfs_ioctl_clone_range_args args;
45 
46 	args.src_fd = srcFile.fileno;
47 	args.src_offset = srcOffset;
48 	args.src_length = length;
49 	args.dest_offset = dstOffset;
50 
51 	int ret = ioctl(dstFile.fileno, BTRFS_IOC_FILE_CLONE_RANGE, &args);
52 	errnoEnforce(ret >= 0, "ioctl(BTRFS_IOC_FILE_CLONE_RANGE)");
53 }
54 
55 unittest
56 {
57 	if (!checkBtrfs())
58 		return;
59 	import std.range, std.random, std.algorithm, std.file;
60 	enum blockSize = 16*1024; // TODO: detect
61 	auto data = blockSize.iota.map!(n => uniform!ubyte).array();
62 	std.file.write("test1.bin", data);
63 	scope(exit) remove("test1.bin");
64 	auto f1 = File("test1.bin", "rb");
65 	scope(exit) remove("test2.bin");
66 	auto f2 = File("test2.bin", "wb");
67 	cloneRange(f1, 0, f2, 0, blockSize);
68 	f2.close();
69 	f1.close();
70 	assert(std.file.read("test2.bin") == data);
71 }