diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/copy.c | 46 | ||||
-rw-r--r-- | src/shared/copy.h | 1 | ||||
-rw-r--r-- | src/shared/machine-image.c | 150 | ||||
-rw-r--r-- | src/shared/machine-image.h | 3 | ||||
-rw-r--r-- | src/shared/missing.h | 10 | ||||
-rw-r--r-- | src/shared/util.c | 14 |
6 files changed, 207 insertions, 17 deletions
diff --git a/src/shared/copy.c b/src/shared/copy.c index 92f6e1e114..3df636704c 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) { @@ -356,9 +365,11 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) { 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; + } r = copy_file_fd(from, fdt, true); if (r < 0) { @@ -375,6 +386,29 @@ 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) { + _cleanup_free_ char *t; + int r; + + assert(from); + assert(to); + + r = tempfn_random(to, &t); + if (r < 0) + return r; + + r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode); + if (r < 0) + return r; + + if (renameat2(AT_FDCWD, t, AT_FDCWD, to, replace ? 0 : RENAME_NOREPLACE) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + int copy_times(int fdf, int fdt) { struct timespec ut[2]; struct stat st; diff --git a/src/shared/copy.h b/src/shared/copy.h index 6d725ef26d..58159a02cc 100644 --- a/src/shared/copy.h +++ b/src/shared/copy.h @@ -26,6 +26,7 @@ int copy_file_fd(const char *from, int to, bool try_reflink); int copy_file(const char *from, const char *to, int flags, mode_t mode); +int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace); int copy_tree(const char *from, const char *to, bool merge); int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge); int copy_directory_fd(int dirfd, const char *to, bool merge); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index fa06a0dc59..7c041fab76 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -20,11 +20,13 @@ ***/ #include <sys/statfs.h> +#include <fcntl.h> #include "strv.h" #include "utf8.h" #include "btrfs-util.h" #include "path-util.h" +#include "copy.h" #include "machine-image.h" static const char image_search_path[] = @@ -317,18 +319,158 @@ void image_hashmap_free(Hashmap *map) { } int image_remove(Image *i) { - int r; - assert(i); if (path_equal(i->path, "/") || path_startswith(i->path, "/usr")) return -EROFS; - if (i->type == IMAGE_SUBVOLUME) + switch (i->type) { + + case IMAGE_SUBVOLUME: return btrfs_subvol_remove(i->path); - else + + case IMAGE_DIRECTORY: + case IMAGE_GPT: return rm_rf_dangerous(i->path, false, true, false); + + default: + return -ENOTSUP; + } +} + +int image_rename(Image *i, const char *new_name) { + _cleanup_free_ char *new_path = NULL, *nn = NULL; + int r; + + assert(i); + + if (!image_name_is_valid(new_name)) + return -EINVAL; + + if (path_equal(i->path, "/") || + path_startswith(i->path, "/usr")) + return -EROFS; + + r = image_find(new_name, NULL); + if (r < 0) + return r; + if (r > 0) + return -EEXIST; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + case IMAGE_DIRECTORY: + new_path = file_in_same_dir(i->path, new_name); + break; + + case IMAGE_GPT: { + const char *fn; + + fn = strappenda(new_name, ".gpt"); + new_path = file_in_same_dir(i->path, fn); + break; + } + + default: + return -ENOTSUP; + } + + if (!new_path) + return -ENOMEM; + + nn = strdup(new_name); + if (!nn) + return -ENOMEM; + + if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, RENAME_NOREPLACE) < 0) + return -errno; + + free(i->path); + i->path = new_path; + new_path = NULL; + + free(i->name); + i->name = nn; + nn = NULL; + + return 0; +} + +int image_clone(Image *i, const char *new_name, bool read_only) { + const char *new_path; + int r; + + assert(i); + + if (!image_name_is_valid(new_name)) + return -EINVAL; + + r = image_find(new_name, NULL); + if (r < 0) + return r; + if (r > 0) + return -EEXIST; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + case IMAGE_DIRECTORY: + new_path = strappenda("/var/lib/container/", new_name); + + r = btrfs_subvol_snapshot(i->path, new_path, read_only, true); + break; + + case IMAGE_GPT: + new_path = strappenda("/var/lib/container/", new_name, ".gpt"); + + r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false); + break; + + default: + return -ENOTSUP; + } + + if (r < 0) + return r; + + return 0; +} + +int image_read_only(Image *i, bool b) { + int r; + assert(i); + + if (path_equal(i->path, "/") || + path_startswith(i->path, "/usr")) + return -EROFS; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + r = btrfs_subvol_set_read_only(i->path, b); + if (r < 0) + return r; + break; + + case IMAGE_GPT: { + struct stat st; + + if (stat(i->path, &st) < 0) + return -errno; + + if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0) + return -errno; + break; + } + + case IMAGE_DIRECTORY: + default: + return -ENOTSUP; + } + + return 0; } static const char* const image_type_table[_IMAGE_TYPE_MAX] = { diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index e17e32f4a5..9e0f6aedba 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -52,6 +52,9 @@ int image_find(const char *name, Image **ret); int image_discover(Hashmap *map); int image_remove(Image *i); +int image_rename(Image *i, const char *new_name); +int image_clone(Image *i, const char *new_name, bool read_only); +int image_read_only(Image *i, bool b); const char* image_type_to_string(ImageType t) _const_; ImageType image_type_from_string(const char *s) _pure_; diff --git a/src/shared/missing.h b/src/shared/missing.h index dd7bef4d9d..08cf83647d 100644 --- a/src/shared/missing.h +++ b/src/shared/missing.h @@ -657,3 +657,13 @@ static inline int raw_clone(unsigned long flags, void *child_stack) { static inline pid_t raw_getpid(void) { return (pid_t) syscall(__NR_getpid); } + +#if !HAVE_DECL_RENAMEAT2 +static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +} +#endif + +#ifndef RENAME_NOREPLACE +#define RENAME_NOREPLACE (1 << 0) +#endif diff --git a/src/shared/util.c b/src/shared/util.c index d04d73872e..92b4d498fe 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -1152,7 +1152,7 @@ char *delete_chars(char *s, const char *bad) { } char *file_in_same_dir(const char *path, const char *filename) { - char *e, *r; + char *e, *ret; size_t k; assert(path); @@ -1165,17 +1165,17 @@ char *file_in_same_dir(const char *path, const char *filename) { if (path_is_absolute(filename)) return strdup(filename); - if (!(e = strrchr(path, '/'))) + e = strrchr(path, '/'); + if (!e) return strdup(filename); k = strlen(filename); - if (!(r = new(char, e-path+1+k+1))) + ret = new(char, (e + 1 - path) + k + 1); + if (!ret) return NULL; - memcpy(r, path, e-path+1); - memcpy(r+(e-path)+1, filename, k+1); - - return r; + memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); + return ret; } int rmdir_parents(const char *path, const char *stop) { |