On Tue, Mar 10, 2015 at 05:34:07PM +0100, Alban Crequy wrote: > From: Alban Crequy <al...@endocode.com> > > renameat2() exists since Linux 3.15 but btrfs support for the flag > RENAME_NOREPLACE was added later. > > This patch implements a fallback when renameat2() returns EINVAL. > EINVAL is the error returned when the filesystem does not support one of > the flags. > --- > src/import/import-raw.c | 2 +- > src/import/import-tar.c | 2 +- > src/import/pull-raw.c | 2 +- > src/import/pull-tar.c | 2 +- > src/shared/copy.c | 7 ++++++- > src/shared/machine-image.c | 2 +- > src/shared/machine-pool.c | 2 +- > src/shared/util.c | 32 ++++++++++++++++++++++++++++++++ > src/shared/util.h | 2 ++ > 9 files changed, 46 insertions(+), 7 deletions(-) > > diff --git a/src/import/import-raw.c b/src/import/import-raw.c > index 15e5eb2..e354023 100644 > --- a/src/import/import-raw.c > +++ b/src/import/import-raw.c > @@ -245,7 +245,7 @@ static int raw_import_finish(RawImport *i) { > (void) rm_rf_dangerous(i->final_path, false, true, false); > } > > - if (renameat2(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path, > RENAME_NOREPLACE) < 0) > + if (rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, > i->final_path) < 0) > return log_error_errno(errno, "Failed to move image into > place: %m");
Change rename_noreplace to return -errno on error, 0 on success, and then this part should look like this: r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path); if (r < 0) return log_error_errno(r, "Failed to move image into place: %m"); (Similarly for other places of course). Zbyszek > free(i->temp_path); > diff --git a/src/import/import-tar.c b/src/import/import-tar.c > index d5b6dad..dcbe721 100644 > --- a/src/import/import-tar.c > +++ b/src/import/import-tar.c > @@ -201,7 +201,7 @@ static int tar_import_finish(TarImport *i) { > (void) rm_rf_dangerous(i->final_path, false, true, false); > } > > - if (renameat2(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path, > RENAME_NOREPLACE) < 0) > + if (rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, > i->final_path) < 0) > return log_error_errno(errno, "Failed to move image into > place: %m"); > > free(i->temp_path); > diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c > index d1d77d5..d4b17e7 100644 > --- a/src/import/pull-raw.c > +++ b/src/import/pull-raw.c > @@ -384,7 +384,7 @@ static void raw_pull_job_on_finished(PullJob *j) { > if (r < 0) > goto finish; > > - r = renameat2(AT_FDCWD, i->temp_path, AT_FDCWD, > i->final_path, RENAME_NOREPLACE); > + r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, > i->final_path); > if (r < 0) { > r = log_error_errno(errno, "Failed to move RAW file > into place: %m"); > goto finish; > diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c > index 504642f..69df7af 100644 > --- a/src/import/pull-tar.c > +++ b/src/import/pull-tar.c > @@ -281,7 +281,7 @@ static void tar_pull_job_on_finished(PullJob *j) { > if (r < 0) > goto finish; > > - if (renameat2(AT_FDCWD, i->temp_path, AT_FDCWD, > i->final_path, RENAME_NOREPLACE) < 0) { > + if (rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, > i->final_path) < 0) { > r = log_error_errno(errno, "Failed to rename to > final image name: %m"); > goto finish; > } > diff --git a/src/shared/copy.c b/src/shared/copy.c > index 0239a58..e578d03 100644 > --- a/src/shared/copy.c > +++ b/src/shared/copy.c > @@ -404,7 +404,12 @@ int copy_file_atomic(const char *from, const char *to, > mode_t mode, bool replace > if (r < 0) > return r; > > - if (renameat2(AT_FDCWD, t, AT_FDCWD, to, replace ? 0 : > RENAME_NOREPLACE) < 0) { > + if (replace) { > + r = renameat(AT_FDCWD, t, AT_FDCWD, to); > + } else { > + r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to); > + } > + if (r < 0) { > unlink_noerrno(t); > return -errno; > } > diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c > index c6d2850..ad5bff4 100644 > --- a/src/shared/machine-image.c > +++ b/src/shared/machine-image.c > @@ -440,7 +440,7 @@ int image_rename(Image *i, const char *new_name) { > if (!nn) > return -ENOMEM; > > - if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, > RENAME_NOREPLACE) < 0) > + if (rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path) < 0) > return -errno; > > /* Restore the immutable bit, if it was set before */ > diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c > index e7671a3..7e902a3 100644 > --- a/src/shared/machine-pool.c > +++ b/src/shared/machine-pool.c > @@ -140,7 +140,7 @@ static int setup_machine_raw(uint64_t size, sd_bus_error > *error) { > goto fail; > } > > - if (renameat2(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw", > RENAME_NOREPLACE) < 0) { > + if (rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, > "/var/lib/machines.raw") < 0) { > r = sd_bus_error_set_errnof(error, errno, "Failed to move > /var/lib/machines.raw into place: %m"); > goto fail; > } > diff --git a/src/shared/util.c b/src/shared/util.c > index 74f2994..2ab7270 100644 > --- a/src/shared/util.c > +++ b/src/shared/util.c > @@ -8118,3 +8118,35 @@ void cmsg_close_all(struct msghdr *mh) { > if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == > SCM_RIGHTS) > close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - > CMSG_LEN(0)) / sizeof(int)); > } > + > +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const > char *newpath) { > + struct stat buf; > + int ret; > + > + ret = renameat2(olddirfd, oldpath, newdirfd, newpath, > RENAME_NOREPLACE); > + > + /* Even though renameat2() exists since Linux 3.15, btrfs added > + * support for it later. If it is not implemented, fallback to > another > + * method. */ > + if (ret == 0 || errno != EINVAL) > + return ret; > + > + /* The link()/unlink() fallback does not work on directories. But > + * renameat() without RENAME_NOREPLACE gives the same semantics on > + * directories, except when newpath is an *empty* directory. This is > + * good enough. */ > + ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); > + if (ret == 0 && S_ISDIR(buf.st_mode)) > + return renameat(olddirfd, oldpath, newdirfd, newpath); > + > + /* If it is not a directory, use the link()/unlink() fallback. */ > + ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); > + if (ret < 0) > + return ret; > + > + ret = unlinkat(olddirfd, oldpath, 0); > + if (ret < 0) > + unlinkat(newdirfd, newpath, 0); > + > + return ret; > +} > diff --git a/src/shared/util.h b/src/shared/util.h > index 2de654f..45a8d37 100644 > --- a/src/shared/util.h > +++ b/src/shared/util.h > @@ -1080,3 +1080,5 @@ void sigkill_wait(pid_t *pid); > int syslog_parse_priority(const char **p, int *priority, bool with_facility); > > void cmsg_close_all(struct msghdr *mh); > + > +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const > char *newpath); > -- > 2.1.4 > > _______________________________________________ > systemd-devel mailing list > systemd-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/systemd-devel _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel