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;
}
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
* 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
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 *);
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;
/* 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;
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)
{
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]);
}
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)