]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Fix rsync target location
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 6 Oct 2023 21:47:21 +0000 (15:47 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Sat, 7 Oct 2023 01:40:21 +0000 (19:40 -0600)
Was downloading rsync://a.b/c into rsync://a.b/c/c, because of an rsync
complication (from rsync(1)):

> A trailing slash on the source changes this behavior to avoid creating
> an additional directory level at the destination. You can think of a
> trailing / on a source as meaning "copy the contents of this
> directory" as opposed to "copy the directory by name", but in both
> cases the attributes of the containing directory are transferred to
> the containing directory on the destination. In other words, each of
> the following commands copies the files in the same way, including
> their setting of the attributes of /dest/foo:
>
> rsync -av /src/foo /dest
> rsync -av /src/foo/ /dest/foo

src/cache/local_cache.c
src/common.c
src/common.h
src/http/http.c
src/rrdp/rrdp_parser.c
src/rsync/rsync.c

index c8d45c8a3a20efe0a2e69c66062c76894cb087df..e40e4d5c93accb5ae5ce29ef2b99ab4f8533e623 100644 (file)
@@ -324,10 +324,10 @@ cache_prepare(void)
        if (rsync == NULL)
                load_metadata_json();
 
-       error = pb_init_cache(&pb, "tmp/a");
+       error = pb_init_cache(&pb, "tmp");
        if (error)
                return error;
-       error = create_dir_recursive(pb.string);
+       error = create_dir_recursive(pb.string, true);
        pb_cleanup(&pb);
        return error;
 }
index 5498b7b67eca38447767831d3000f275fbdca0c4..f09cf321921292f1541a6982d5f8fb0d7d463256 100644 (file)
@@ -224,41 +224,31 @@ valid_file_or_dir(char const *location, bool check_file, bool check_dir,
        return result;
 }
 
+/*
+ * > 0: exists
+ * = 0: !exists
+ * < 0: error
+ */
 static int
-dir_exists(char *path, bool *result)
+dir_exists(char const *path)
 {
-       struct stat _stat;
-       char *last_slash;
+       struct stat meta;
        int error;
 
-       last_slash = strrchr(path, '/');
-       if (last_slash == NULL) {
-               /*
-                * Simply because create_dir_recursive() has nothing meaningful
-                * to do when this happens. It's a pretty strange error.
-                */
-               *result = true;
-               return 0;
-       }
-
-       *last_slash = '\0';
-
-       if (stat(path, &_stat) == 0) {
-               if (!S_ISDIR(_stat.st_mode)) {
-                       return pr_op_err_st("Path '%s' exists and is not a directory.",
-                           path);
-               }
-               *result = true;
-       } else if (errno == ENOENT) {
-               *result = false;
-       } else {
+       if (stat(path, &meta) != 0) {
                error = errno;
+               if (error == ENOENT)
+                       return false;
                pr_op_err_st("stat() failed: %s", strerror(error));
                return error;
        }
 
-       *last_slash = '/';
-       return 0;
+       if (!S_ISDIR(meta.st_mode)) {
+               return pr_op_err_st("Path '%s' exists and is not a directory.",
+                   path);
+       }
+
+       return 1;
 }
 
 static int
@@ -283,32 +273,38 @@ create_dir(char const *path)
  * This function fixes that.
  */
 int
-create_dir_recursive(char const *path)
+create_dir_recursive(char const *path, bool include_basename)
 {
-       char *localuri;
-       int i, error;
-       bool exist;
+       char *localuri, *last_slash;
+       int i, result = 0;
 
        localuri = pstrdup(path); /* Remove const */
 
-       exist = false;
-       error = dir_exists(localuri, &exist);
-       if (error || exist)
+       if (!include_basename) {
+               last_slash = strrchr(localuri, '/');
+               if (last_slash == NULL)
+                       goto end;
+               *last_slash = '\0';
+       }
+
+       result = dir_exists(localuri); /* short circuit */
+       if (result != 0)
                goto end;
 
        for (i = 1; localuri[i] != '\0'; i++) {
                if (localuri[i] == '/') {
                        localuri[i] = '\0';
-                       error = create_dir(localuri);
+                       result = create_dir(localuri);
                        localuri[i] = '/';
-                       if (error)
+                       if (result != 0)
                                goto end; /* error msg already printed */
                }
        }
+       result = create_dir(localuri);
 
 end:
        free(localuri);
-       return error;
+       return result;
 }
 
 static int
index b2012b095c0318e20a2f3fc551bfcdf8ffbab67f..d33edbea25dfec8900554eca479677afabcc98d0 100644 (file)
@@ -65,7 +65,7 @@ int process_file_or_dir(char const *, char const *, bool, process_file_cb,
 typedef int (*pr_errno_cb)(const char *, ...);
 bool valid_file_or_dir(char const *, bool, bool, pr_errno_cb);
 
-int create_dir_recursive(char const *);
+int create_dir_recursive(char const *, bool);
 int delete_dir_recursive_bottom_up(char const *);
 
 int get_current_time(time_t *);
index 131c48b834263d83627d08ac580f4cceeb874fdc..f193d3683fb9713a5a9953ba50fd8ca269efec38 100644 (file)
@@ -432,7 +432,7 @@ http_download(struct rpki_uri *uri, bool *changed)
        if (error || !(*changed))
                goto end;
 
-       error = create_dir_recursive(final_file_name);
+       error = create_dir_recursive(final_file_name, false);
        if (error) {
                remove(tmp_file_name);
                goto end;
index e813359ec51a4deddd26d9f20e2b5300c1e87cbd..721b7d931f3d7abe673ed4f53cd168a8c9716dfe 100644 (file)
@@ -489,7 +489,7 @@ write_from_uri(char const *location, unsigned char *content, size_t content_len)
 
        /* pr_val_debug("Expanding %s.", uri_get_local(uri)); */
 
-       error = create_dir_recursive(uri_get_local(uri));
+       error = create_dir_recursive(uri_get_local(uri), false);
        if (error) {
                uri_refput(uri);
                return error;
index 11d91dab371616e95a43cf0c034240d1ca72fd5b..e7564a6a5ffa48a6b7a062a471100a804be54b89 100644 (file)
@@ -43,6 +43,53 @@ release_args(char **args, unsigned int size)
        free(args);
 }
 
+/*
+ * See rsync(1):
+ *
+ * > You can think of a trailing / on a source as meaning "copy the contents of
+ * > this directory" as opposed to "copy the directory by name"
+ *
+ * This gets in our way:
+ *
+ * - If URI is "rsync://a.b/d", we need to rsync into "cache/rsync/a.b"
+ *   (rsync will create d).
+ * - If URI is "rsync://a.b/d/", we need to rsync into "cache/rsync/a.b/d"
+ *   (rsync will not create d).
+ */
+static bool
+has_trailing_slash(struct rpki_uri *uri)
+{
+       char const *guri;
+       size_t glen;
+
+       guri = uri_get_global(uri);
+       glen = uri_get_global_len(uri);
+
+       if (glen == 0)
+               pr_crit("URI length is zero: %s", guri);
+
+       return guri[glen - 1] == '/';
+}
+
+static char *
+get_target(struct rpki_uri *uri)
+{
+       char *target;
+       char *last_slash;
+
+       target = pstrdup(uri_get_local(uri));
+
+       if (has_trailing_slash(uri))
+               return target;
+
+       last_slash = strrchr(target, '/');
+       if (last_slash == NULL)
+               pr_crit("path contains zero slashes: %s", target);
+
+       *last_slash = '\0';
+       return target;
+}
+
 static void
 prepare_rsync(struct rpki_uri *uri, char ***args, size_t *args_len)
 {
@@ -68,7 +115,7 @@ prepare_rsync(struct rpki_uri *uri, char ***args, size_t *args_len)
                if (strcmp(config_args->array[i], "$REMOTE") == 0)
                        copy_args[i + 1] = pstrdup(uri_get_global(uri));
                else if (strcmp(config_args->array[i], "$LOCAL") == 0)
-                       copy_args[i + 1] = pstrdup(uri_get_local(uri));
+                       copy_args[i + 1] = pstrdup(get_target(uri));
                else
                        copy_args[i + 1] = pstrdup(config_args->array[i]);
        }
@@ -234,12 +281,14 @@ rsync_download(struct rpki_uri *uri)
                        pr_val_debug("    %s", args[i]);
        }
 
+       error = create_dir_recursive(uri_get_local(uri),
+           has_trailing_slash(uri));
+       if (error)
+               goto release_args;
+
        retries = 0;
        do {
                child_status = 0;
-               error = create_dir_recursive(uri_get_local(uri));
-               if (error)
-                       goto release_args;
 
                error = create_pipes(fork_fds);
                if (error)