NFSv4.2 copy_file_range test
09 Dec 2016update 2020-01-19: latest code:
https://github.com/tcler/linux-network-filesystems/tree/master/utils/syscall_wrapper/copy_file_range.c
https://github.com/tcler/linux-network-filesystems/tree/master/utils/syscall_wrapper/copy_file_range.pl
https://github.com/tcler/linux-network-filesystems/tree/master/utils/syscall_wrapper/copy_file_range.py
#!/usr/bin/python
import sys
import os
import errno
from ctypes import *
libc = CDLL("libc.so.6", use_errno=True)
SYS_COPY_RANGE = 326 #syscall number __NR_copy_file_range from usr/include/asm/unistd_64.h
def copyfile(f_in, f_out):
INTP = POINTER(c_uint64)
size = os.stat(f_in.name).st_size
copied = 0
lsize = size
while lsize != 0:
pos = c_uint64(copied)
addr = addressof(pos)
offset = cast(addr, INTP)
print("> Offset: %s lsize: %s; fdin %d fdout %d" % (copied, lsize, f_in.fileno(), f_out.fileno()))
ret = libc.syscall(c_int(SYS_COPY_RANGE),
c_int(f_in.fileno()), POINTER(c_uint64)(), #offset,
c_int(f_out.fileno()), POINTER(c_uint64)(), #offset,
c_uint64(lsize), 0)
if ret < 0:
sys.stderr.write("[err] SYS_COPY_RANGE fail: errno %d %s" % (get_errno(), os.strerror(get_errno())))
return ret
if ret == 0:
sys.stderr.write("[warn] SYS_COPY_RANGE return 0: errno %d %s" % (get_errno(), os.strerror(get_errno())))
copied = copied + ret;
lsize = lsize - ret;
print("SYS_COPY_RANGE returns: %s" % ret)
print("Total: %s" % copied)
return ret
if len(sys.argv) != 3:
print("Usage: " + sys.argv[0] + " src dst")
sys.exit(1)
if not os.path.exists(sys.argv[1]):
print("ERROR: " + sys.argv[1] + " does not exist :(")
sys.exit(1)
f_in = open(sys.argv[1], "r")
f_out = open(sys.argv[2], "w")
copyfile(f_in, f_out)
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
loff_t copy_file_range(int fd_in, loff_t *off_in, int fd_out,
loff_t *off_out, size_t len, unsigned int flags)
{
#ifndef __NR_copy_file_range
#define __NR_copy_file_range 326
#endif
return syscall(__NR_copy_file_range, fd_in, off_in, fd_out,
off_out, len, flags);
}
int main(int argc, char **argv)
{
int fd_in, fd_out;
struct stat stat;
loff_t len, ret;
char buf[2];
if (argc != 3) {
fprintf(stderr, "Usage: %s <source> <destination>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd_in = open(argv[1], O_RDONLY);
if (fd_in == -1) {
perror("open (argv[1])");
exit(EXIT_FAILURE);
}
if (fstat(fd_in, &stat) == -1) {
perror("fstat");
exit(EXIT_FAILURE);
}
len = stat.st_size;
fd_out = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC, 0644);
if (fd_out == -1) {
perror("open (argv[2])");
exit(EXIT_FAILURE);
}
do {
ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0);
if (ret == -1) {
perror("copy_file_range");
exit(EXIT_FAILURE);
}
len -= ret;
} while (len > 0);
close(fd_in);
close(fd_out);
exit(EXIT_SUCCESS);
}