chiark / gitweb /
machined: support non-btrfs file systems with "machinectl clone"
[elogind.git] / src / basic / copy.c
index c5cbbb79f44070f444e6aaeafda60b508583ba69..c2c0579c89842848ed49916e93f9669dd2669b7a 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+//#include <dirent.h>
+//#include <errno.h>
+//#include <fcntl.h>
+//#include <stddef.h>
+//#include <stdio.h>
+//#include <stdlib.h>
+//#include <string.h>
 #include <sys/sendfile.h>
+//#include <sys/stat.h>
 #include <sys/xattr.h>
+//#include <time.h>
+//#include <unistd.h>
 
 //#include "alloc-util.h"
 //#include "btrfs-util.h"
 //#include "fileio.h"
 //#include "fs-util.h"
 #include "io-util.h"
+//#include "macro.h"
 //#include "string-util.h"
 #include "strv.h"
+#include "time-util.h"
 //#include "umask-util.h"
-#include "util.h"
 //#include "xattr-util.h"
 
 #define COPY_BUFFER_SIZE (16*1024)
@@ -45,8 +54,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
 
         assert(fdf >= 0);
         assert(fdt >= 0);
-// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
         /* Try btrfs reflinks first. */
         if (try_reflink &&
             max_bytes == (uint64_t) -1 &&
@@ -65,7 +73,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
                 if (max_bytes != (uint64_t) -1) {
 
                         if (max_bytes <= 0)
-                                return -EFBIG;
+                                return 1; /* return > 0 if we hit the max_bytes limit */
 
                         if ((uint64_t) m > max_bytes)
                                 m = (size_t) max_bytes;
@@ -129,8 +137,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
         return 0; /* return 0 if we hit EOF earlier than the size limit */
 }
 
-// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
         _cleanup_free_ char *target = NULL;
         int r;
@@ -260,6 +267,8 @@ static int fd_copy_directory(
                 fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
         else
                 fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
+        if (fdf < 0)
+                return -errno;
 
         d = fdopendir(fdf);
         if (!d)
@@ -280,22 +289,6 @@ static int fd_copy_directory(
 
         r = 0;
 
-        if (created) {
-                struct timespec ut[2] = {
-                        st->st_atim,
-                        st->st_mtim
-                };
-
-                if (fchown(fdt, st->st_uid, st->st_gid) < 0)
-                        r = -errno;
-
-                if (fchmod(fdt, st->st_mode & 07777) < 0)
-                        r = -errno;
-
-                (void) futimens(fdt, ut);
-                (void) copy_xattr(dirfd(d), fdt);
-        }
-
         FOREACH_DIRENT_ALL(de, d, return -errno) {
                 struct stat buf;
                 int q;
@@ -319,7 +312,7 @@ static int fd_copy_directory(
                         q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                 else if (S_ISFIFO(buf.st_mode))
                         q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
-                else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
+                else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
                         q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                 else
                         q = -EOPNOTSUPP;
@@ -331,6 +324,22 @@ static int fd_copy_directory(
                         r = q;
         }
 
+        if (created) {
+                struct timespec ut[2] = {
+                        st->st_atim,
+                        st->st_mtim
+                };
+
+                if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+                        r = -errno;
+
+                if (fchmod(fdt, st->st_mode & 07777) < 0)
+                        r = -errno;
+
+                (void) copy_xattr(dirfd(d), fdt);
+                (void) futimens(fdt, ut);
+        }
+
         return r;
 }
 
@@ -351,7 +360,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
                 return fd_copy_symlink(fdf, from, &st, fdt, to);
         else if (S_ISFIFO(st.st_mode))
                 return fd_copy_fifo(fdf, from, &st, fdt, to);
-        else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
+        else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
                 return fd_copy_node(fdf, from, &st, fdt, to);
         else
                 return -EOPNOTSUPP;
@@ -362,7 +371,6 @@ int copy_tree(const char *from, const char *to, bool merge) {
 }
 
 int copy_directory_fd(int dirfd, const char *to, bool merge) {
-
         struct stat st;
 
         assert(dirfd >= 0);
@@ -377,6 +385,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
         return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
 }
 
+int copy_directory(const char *from, const char *to, bool merge) {
+        struct stat st;
+
+        assert(from);
+        assert(to);
+
+        if (lstat(from, &st) < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode))
+                return -ENOTDIR;
+
+        return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+}
+
 int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         _cleanup_close_ int fdf = -1;
         int r;