X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fcopy.c;h=230e7e4d3fc3a793431fc5165a5c3631dbbf0d3b;hb=ce5792dac67c5ae5656f1f9665b777d44af4cb35;hp=92f6e1e114329738b852ba7abde0cfb28681a529;hpb=e6bd041c973c1f4074c3268b23c380ede0d64f19;p=elogind.git diff --git a/src/shared/copy.c b/src/shared/copy.c index 92f6e1e11..230e7e4d3 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -120,6 +120,7 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) { _cleanup_close_ int fdf = -1, fdt = -1; + struct timespec ts[2]; int r, q; assert(from); @@ -146,7 +147,10 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int if (fchmod(fdt, st->st_mode & 07777) < 0) r = -errno; - (void) copy_times(fdf, fdt); + ts[0] = st->st_atim; + ts[1] = st->st_mtim; + (void) futimens(fdt, ts); + (void) copy_xattr(fdf, fdt); q = close(fdt); @@ -243,14 +247,19 @@ 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) copy_times(fdf, fdt); - (void) copy_xattr(fdf, fdt); + (void) futimens(fdt, ut); + (void) copy_xattr(dirfd(d), fdt); } FOREACH_DIRENT(de, d, return -errno) { @@ -276,7 +285,7 @@ static int fd_copy_directory( else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)) q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name); else - q = -ENOTSUP; + q = -EOPNOTSUPP; if (q == -EEXIST && merge) q = 0; @@ -308,7 +317,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) return fd_copy_node(fdf, from, &st, fdt, to); else - return -ENOTSUP; + return -EOPNOTSUPP; } int copy_tree(const char *from, const char *to, bool merge) { @@ -350,15 +359,20 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) { return r; } -int copy_file(const char *from, const char *to, int flags, mode_t mode) { - int fdt, r; +int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) { + int fdt = -1, r; assert(from); assert(to); - fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode); - if (fdt < 0) - return -errno; + RUN_WITH_UMASK(0000) { + fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode); + if (fdt < 0) + return -errno; + } + + if (chattr_flags != 0) + (void) chattr_fd(fdt, chattr_flags, (unsigned) -1); r = copy_file_fd(from, fdt, true); if (r < 0) { @@ -375,10 +389,39 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) { return 0; } +int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) { + _cleanup_free_ char *t = NULL; + int r; + + assert(from); + assert(to); + + r = tempfn_random(to, NULL, &t); + if (r < 0) + return r; + + r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags); + if (r < 0) + return r; + + if (replace) { + r = renameat(AT_FDCWD, t, AT_FDCWD, to); + if (r < 0) + r = -errno; + } else + r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to); + if (r < 0) { + (void) unlink_noerrno(t); + return r; + } + + return 0; +} + int copy_times(int fdf, int fdt) { struct timespec ut[2]; struct stat st; - usec_t crtime; + usec_t crtime = 0; assert(fdf >= 0); assert(fdt >= 0);