[systemd-devel] [PATCH] [PATCH v2] util: add rename_noreplace

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Tue Mar 10 09:39:38 PDT 2015


On Tue, Mar 10, 2015 at 05:34:07PM +0100, Alban Crequy wrote:
> From: Alban Crequy <alban at 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


More information about the systemd-devel mailing list