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 <ae@cy.md>
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 /// Submit a `BTRFS_IOC_FILE_CLONE_RANGE` ioctl.
40 void cloneRange(
41 	ref const File srcFile, ulong srcOffset,
42 	ref const File dstFile, ulong dstOffset,
43 	ulong length)
44 {
45 	btrfs_ioctl_clone_range_args args;
46 
47 	args.src_fd = srcFile.fileno;
48 	args.src_offset = srcOffset;
49 	args.src_length = length;
50 	args.dest_offset = dstOffset;
51 
52 	int ret = ioctl(dstFile.fileno, BTRFS_IOC_FILE_CLONE_RANGE, &args);
53 	errnoEnforce(ret >= 0, "ioctl(BTRFS_IOC_FILE_CLONE_RANGE)");
54 }
55 
56 unittest
57 {
58 	if (!checkBtrfs())
59 		return;
60 	import std.range, std.random, std.algorithm, std.file;
61 	enum blockSize = 16*1024; // TODO: detect
62 	auto data = blockSize.iota.map!(n => uniform!ubyte).array();
63 	std.file.write("test1.bin", data);
64 	scope(exit) remove("test1.bin");
65 	auto f1 = File("test1.bin", "rb");
66 	scope(exit) remove("test2.bin");
67 	auto f2 = File("test2.bin", "wb");
68 	cloneRange(f1, 0, f2, 0, blockSize);
69 	f2.close();
70 	f1.close();
71 	assert(std.file.read("test2.bin") == data);
72 }