From: Arvin Schnell Date: Fri, 26 Aug 2011 10:05:31 +0000 (+0200) Subject: - use clone ioctl with plain copy as fallback X-Git-Tag: v0.1.3~302 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e0636b37fd128b533499ee5b467d04615e6bc27c;p=thirdparty%2Fsnapper.git - use clone ioctl with plain copy as fallback --- diff --git a/snapper/AppUtil.cc b/snapper/AppUtil.cc index caaaaf5b..cad4fc4e 100644 --- a/snapper/AppUtil.cc +++ b/snapper/AppUtil.cc @@ -290,25 +290,66 @@ void initDefaultLogger() } - int - clonefile(const string& dest, const string& src, mode_t mode) + bool + clonefile(int src_fd, int dest_fd) { - int src_fd = open(src.c_str(), O_RDONLY | O_LARGEFILE); - - int dest_fd = open(dest.c_str(), O_WRONLY | O_LARGEFILE | O_CREAT | O_TRUNC, mode); - #undef BTRFS_IOCTL_MAGIC #define BTRFS_IOCTL_MAGIC 0x94 #undef BTRFS_IOC_CLONE #define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int) - int ret = ioctl(dest_fd, BTRFS_IOC_CLONE, src_fd); + int r1 = ioctl(dest_fd, BTRFS_IOC_CLONE, src_fd); + if (r1 != 0) + { + y2err("ioctl failed errno:" << errno << " (" << strerror(errno) << ")"); + } - close(dest_fd); + return r1 == 0; + } - close(src_fd); - return ret; + bool + copyfile(int src_fd, int dest_fd) + { + struct stat src_stat; + int r1 = fstat(src_fd, &src_stat); + if (r1 != 0) + { + y2err("fstat failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + posix_fadvise(src_fd, 0, src_stat.st_size, POSIX_FADV_SEQUENTIAL); + + static_assert(sizeof(off_t) >= 8, "off_t is too small"); + + const off_t block_size = 4096; + + char block[block_size]; + + off_t length = src_stat.st_size; + while (length > 0) + { + off_t t = min(block_size, length); + + int r2 = read(src_fd, block, t); + if (r2 != t) + { + y2err("read failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + int r3 = write(dest_fd, block, t); + if (r3 != t) + { + y2err("write failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + length -= t; + } + + return true; } diff --git a/snapper/AppUtil.h b/snapper/AppUtil.h index fb2d8497..5e615a39 100644 --- a/snapper/AppUtil.h +++ b/snapper/AppUtil.h @@ -48,7 +48,8 @@ bool checkDir(const string& Path_Cv); FILE* mkstemp(string& path); - int clonefile(const string& dest, const string& src, mode_t mode); + bool clonefile(int src_fd, int dest_fd); + bool copyfile(int src_fd, int dest_fd); int readlink(const string& path, string& buf); int symlink(const string& oldpath, const string& newpath); diff --git a/snapper/File.cc b/snapper/File.cc index c009a7d8..b0ec47ee 100644 --- a/snapper/File.cc +++ b/snapper/File.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "snapper/File.h" @@ -517,10 +518,46 @@ namespace snapper bool File::createFile(mode_t mode, uid_t owner, gid_t group) const { - // TODO: use clonefile - SystemCmd cmd(CPBIN " --preserve=mode,ownership " + - getAbsolutePath(LOC_PRE) + " " + getAbsolutePath(LOC_SYSTEM)); - return cmd.retcode() == 0; + int src_fd = open(getAbsolutePath(LOC_PRE).c_str(), O_RDONLY | O_LARGEFILE); + if (src_fd < 0) + { + y2err("open failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + int dest_fd = open(getAbsolutePath(LOC_SYSTEM).c_str(), O_WRONLY | O_LARGEFILE | + O_CREAT | O_TRUNC, mode); + if (dest_fd < 0) + { + y2err("open failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + int r1 = fchmod(dest_fd, mode); + if (r1 != 0) + { + y2err("fchmod failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + int r2 = fchown(dest_fd, owner, group); + if (r2 != 0) + { + y2err("fchown failed errno:" << errno << " (" << strerror(errno) << ")"); + return false; + } + + bool ret = clonefile(src_fd, dest_fd) || copyfile(src_fd, dest_fd); + if (!ret) + { + y2err("clone and copy failed " << getAbsolutePath(LOC_SYSTEM)); + } + + close(dest_fd); + + close(src_fd); + + return ret; }