]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- use clone ioctl with plain copy as fallback
authorArvin Schnell <aschnell@suse.de>
Fri, 26 Aug 2011 10:05:31 +0000 (12:05 +0200)
committerArvin Schnell <aschnell@suse.de>
Fri, 26 Aug 2011 10:05:31 +0000 (12:05 +0200)
snapper/AppUtil.cc
snapper/AppUtil.h
snapper/File.cc

index caaaaf5bb25a52a40132c5104cee1fd88aa22616..cad4fc4ebb5b1fe3ea4553161a371daba34f23cc 100644 (file)
@@ -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;
     }
 
 
index fb2d849725ad2f7210165751efb6a0b193c94287..5e615a3958fb3c45a7fcf70fed9833b6d8c5cdca 100644 (file)
@@ -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);
index c009a7d8824ffcdfbab2879b1c78ef8ee362e341..b0ec47ee27b17fc2e76fe5c7f32306c03f107add 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <fnmatch.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <boost/algorithm/string.hpp>
 
 #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;
     }