]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Improve of rsync.c code
authordhfelix <daniel.hdz.felix@hotmail.com>
Fri, 18 Jan 2019 18:46:42 +0000 (12:46 -0600)
committerdhfelix <daniel.hdz.felix@hotmail.com>
Fri, 18 Jan 2019 18:46:42 +0000 (12:46 -0600)
-add unit test for rsync.c
-TODO fix tal_tests

src/object/certificate.c
src/rsync/rsync.c
test/Makefile.am
test/rsync_test.c [new file with mode: 0644]

index da744fe7de069195fbe5675c371a7ab46c2d54f7..565dc6e4e376057aba8631a2ce5a8c0f5d77fc59 100644 (file)
@@ -454,16 +454,11 @@ abort:
        return -EINVAL;
 }
 
-/*
- * "GENERAL_NAME, global to local"
- * Result has to be freed.
- *
- * If this function returns ENOTRSYNC, it means that @name was not an RSYNC URI.
- * This often should not be treated as an error; please handle gracefully.
- * TODO open call hierarchy.
+/**
+ * Get GENERAL_NAME data.
  */
 static int
-gn_g2l(GENERAL_NAME *name, char **luri)
+get_gn(GENERAL_NAME *name, char **guri)
 {
        ASN1_STRING *asn1_string;
        int type;
@@ -505,8 +500,37 @@ gn_g2l(GENERAL_NAME *name, char **luri)
         * directory our g2l version of @asn1_string should contain.
         * But ask the testers to keep an eye on it anyway.
         */
-       return uri_g2l((char const *) ASN1_STRING_get0_data(asn1_string),
-           ASN1_STRING_length(asn1_string), luri);
+       *guri = (char *) ASN1_STRING_get0_data(asn1_string);
+       return 0;
+}
+
+/*
+ * "GENERAL_NAME, global to local"
+ * Result has to be freed.
+ *
+ * If this function returns ENOTRSYNC, it means that @name was not an RSYNC URI.
+ * This often should not be treated as an error; please handle gracefully.
+ * TODO open call hierarchy.
+ */
+static int
+gn_g2l(GENERAL_NAME *name, char **luri)
+{
+       char *guri;
+       int error;
+
+       error = get_gn(name, &guri);
+       if (error)
+               return error; /* message already printed. */
+
+       /*
+        * TODO (testers) According to RFC 5280, accessLocation can be an IRI
+        * somehow converted into URI form. I don't think that's an issue
+        * because the RSYNC clone operation should not have performed the
+        * conversion, so we should be looking at precisely the IA5String
+        * directory our g2l version of @asn1_string should contain.
+        * But ask the testers to keep an eye on it anyway.
+        */
+       return uri_g2l((char const *) guri, strlen(guri), luri);
 }
 
 static int
@@ -671,14 +695,13 @@ handle_caRepository(ACCESS_DESCRIPTION *ad)
        char *uri;
        int error;
 
-       error = gn_g2l(ad->location, &uri);
+       error = get_gn(ad->location, &uri);
        if (error)
                return error;
 
        pr_debug("caRepository: %s", uri);
        error = download_files(uri);
 
-       free(uri);
        return error;
 }
 
@@ -1158,7 +1181,7 @@ certificate_traverse_ta(X509 *cert, STACK_OF(X509_CRL) *crls)
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg       */
            { &BC,  true,  handle_bc,               },
-           { &SKI, true,  handle_ski,    &cert     },
+           { &SKI, true,  handle_ski,     cert     },
            { &AKI, false, handle_aki_ta,           },
            { &KU,  true,  handle_ku_ca,            },
            { &SIA, true,  handle_sia_ca, &sia_args },
@@ -1181,7 +1204,7 @@ certificate_traverse_ca(X509 *cert, STACK_OF(X509_CRL) *crls)
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg       */
            { &BC,  true,  handle_bc,            },
-           { &SKI, true,  handle_ski,    &cert     },
+           { &SKI, true,  handle_ski,     cert     },
            { &AKI, true,  handle_aki,              },
            { &KU,  true,  handle_ku_ca,            },
            { &CDP, true,  handle_cdp,              },
index 992a39cf155d3228b1746a9be5f6d13ccd639471..f1d71aadb27a3548f09d820048633754ee9e18aa 100644 (file)
@@ -22,24 +22,14 @@ SLIST_HEAD(uri_list, uri);
 
 static struct uri_list *rsync_uris;
 static bool execute_rsync = true;
+static char const *const RSYNC_PREFIX = "rsync://";
 
 //static const char *rsync_command[] = {"rsync", "--recursive", "--delete", "--times", NULL};
 
-static int create_dir_recursive(char *);
-static int create_dir(char *);
-static int do_rsync(char const *);
-static int get_dest_path(char const *, char **);
-static bool is_file(char const *);
-static bool dir_exist(char *);
-
 int
 rsync_init(bool is_rsync_active)
 {
-       // TODO remove the next 2 lines
-       /*
-        * TODO (rsync) No, don't. Disabling rsync will forever be a useful
-        * debugging feature.
-        */
+       /* Disabling rsync will forever be a useful debugging feature. */
        if (!is_rsync_active) {
                execute_rsync = is_rsync_active;
                return 0;
@@ -71,35 +61,35 @@ rsync_destroy(void)
        free(rsync_uris);
 }
 
+/*
+ * Executes the rsync command. 'rsync_uri' as SRC and 'localuri' as DEST.
+ */
 static int
-do_rsync(char const *rsync_uri)
+do_rsync(char const *rsync_uri, char const *localuri)
 {
        int error;
        char *command;
-       char *dest;
-       /* TODO (rsync) comment is invisible in narrow editors */
-       char const *rsync_command = "rsync --recursive --delete --times --contimeout=20 "; /* space char at end*/
-
-       /* TODO (rsync) dest is leaking */
-       error = get_dest_path(rsync_uri, &dest);
-       if (error)
-               return error;
+       char const *rsync_command = "rsync --recursive --delete --times "
+                       "--contimeout=20 "; /* space char at end*/
 
-       /* TODO (rsync) It seems that rsync_command does not need a `+ 1` */
-       /* TODO (rsync) line exceeds 80 column limit */
-       command = malloc(strlen(rsync_command) + 1 + strlen(rsync_uri) + 1 + strlen(dest) + 1);
+       command = malloc(strlen(rsync_command)
+                       + strlen(rsync_uri)
+                       + 1 /* space char */
+                       + strlen(localuri) + 1); /* null char at end*/
        if (command == NULL)
-               return -ENOMEM;
+               return pr_enomem();
 
        strcpy(command, rsync_command);
        strcat(command, rsync_uri);
        strcat(command, " ");
-       strcat(command, dest);
-
-       free(dest);
+       strcat(command, localuri);
 
        pr_debug("(%s) command = %s", __func__, command);
 
+       /*
+        * TODO Improve the execution of the command, maybe using another function
+        * instead of system().
+        */
        error = system(command);
        if (error) {
                int error2 = errno;
@@ -118,88 +108,38 @@ do_rsync(char const *rsync_uri)
        return error;
 }
 
-/*
- * If @rsync_uri is a certificate, ghostbuster or manifest file, this returns
- * its local location's parent.
- * If @rsync_uri is anything else (including other file types), returns
- * @rsync_uri's local location.
- *
- * TODO (rsync) Why are you doing this? is rsync incapable of synchronizing
- * individual files?
- * TODO (rsync) Also: That's wrong anyway. certificates, ghostbusters and
- * manifests are not the only files RPKI has to handle. There's nothing in the
- * RFCs requiring that only known file types be present, or even that all files
- * must have extensions.
- * If you REALLY need to tell the difference between files and directories,
- * use stat(2) instead.
- */
-static int
-get_dest_path(char const *rsync_uri, char **result)
-{
-       char *local_uri, *temp_str;
-       unsigned int result_size;
-       int error;
-
-       /* TODO (rsync) local_uri is leaking */
-       error = uri_g2l(rsync_uri, strlen(rsync_uri), &local_uri);
-       if (error)
-               return error;
-
-       if (!is_file(local_uri)) {
-               *result = local_uri;
-               return 0;
-       }
-
-       temp_str = strrchr(local_uri, '/');
-       if (temp_str == NULL) {
-               return pr_err("URI '%s' has no slash.", local_uri);
-       }
-       result_size = temp_str - local_uri + 1; /* add slash (+1) */
-
-       temp_str = malloc(result_size + 1); /* null char (+1) */
-       if (temp_str == NULL) {
-               return pr_enomem();
-       }
-       temp_str[result_size] = '\0'; /*Set null char*/
-       strncpy(temp_str, local_uri, result_size);
-       free(local_uri);
-
-       *result = temp_str;
-       return 0;
-}
-
 /*
  * Returns whether new_uri's prefix is rsync_uri.
- * TODO (rsync) why does this not care about nodes? It will return true if
+ * TODO (rsync)SOLVED why does this not care about nodes? It will return true if
  * `rsync_uri = proto://a/b/c` and `new_uri = proto://a/b/cc`.
  */
 static bool
 rsync_uri_prefix_equals(struct uri *rsync_uri, char const *new_uri)
 {
        size_t uri_len;
-       uri_len = strlen(new_uri);
 
+       uri_len = strlen(new_uri);
        if (rsync_uri->len > uri_len)
                return false;
 
-       /*
-        * TODO (rsync) Don't use '!' for tests unless it's a boolean.
-        * (OpenBSD style)
-        */
-       return !strncasecmp(rsync_uri->string, new_uri, rsync_uri->len);
+       if (rsync_uri->string[rsync_uri->len - 1] != '/'
+                       && uri_len > rsync_uri->len && new_uri[rsync_uri->len] != '/') {
+               return false;
+       }
+
+       return strncasecmp(rsync_uri->string, new_uri, rsync_uri->len) == 0;
 }
 
+/*
+ * Checks if the 'rsync_uri' match equal or as a child of an existing URI in
+ * the list.
+ */
 static bool
 is_uri_in_list(char const *rsync_uri)
 {
        struct uri *cursor;
        bool found;
 
-       /* TODO (rsync) this if doesn't seem to be doing anything */
-       if (SLIST_EMPTY(rsync_uris)) {
-               return false;
-       }
-
        found = false;
        SLIST_FOREACH(cursor, rsync_uris, next) {
                if (rsync_uri_prefix_equals(cursor, rsync_uri)) {
@@ -212,329 +152,279 @@ is_uri_in_list(char const *rsync_uri)
 }
 
 static int
-add_uri_to_list(char const *rsync_uri_path)
+add_uri_to_list(char *rsync_uri_path)
 {
        struct uri *rsync_uri;
-       size_t urilen;
 
        rsync_uri = malloc(sizeof(struct uri));
        if (rsync_uri == NULL)
                return pr_enomem();
-       urilen = strlen(rsync_uri_path);
 
-       rsync_uri->string = malloc(urilen + 1);
-       if (!rsync_uri->string) {
-               free(rsync_uri);
-               return pr_enomem();
-       }
+       rsync_uri->string = rsync_uri_path;
+       rsync_uri->len = strlen(rsync_uri_path);
 
-       /*
-        * TODO (rsync) caller frees rsync_uri_path right after calling this.
-        * Transfer ownership instead so you don't need the extra allocate, copy
-        * and free.
-        */
-       strcpy(rsync_uri->string, rsync_uri_path);
-       rsync_uri->len = urilen;
        SLIST_INSERT_HEAD(rsync_uris, rsync_uri, next);
 
        return 0;
 }
 
 /*
- * Returns rsync_uri, truncated to the second significant slash.
- * I have no idea why.
- *
- * Examples:
- *
- *     rsync_uri: rsync://aa/bb/cc/dd/ee/ff/gg/hh/ii
- *     result:    rsync://aa/bb/
- *
- *     rsync_uri: rsync://aa/bb/
- *     result:    rsync://aa/bb/
- *
- *     rsync_uri: rsync://aa/
- *     result:    rsync://aa//
- *
- *     rsync_uri: rsync://aa
- *     result:    rsync://aa
+ * Compares two URIs to obtain the common path if exist.
+ * Return NULL if URIs does not match or only match in its domain name.
+ * E.g. uri1=proto://a/b/c/d uri2=proto://a/b/c/f, will return proto://a/b/c/
  */
 static int
-short_uri(char const *rsync_uri, char **result)
+find_prefix_path(char const *uri1, char const *uri2, char **result)
 {
-       char const *const PREFIX = "rsync://";
-       char const *tmp;
-       char *short_uri;
-       size_t result_len;
-       size_t prefix_len;
-
-       prefix_len = strlen(PREFIX);
+       int i, error;
+       char const *tmp, *last_equal;
 
-       if (strncmp(PREFIX, rsync_uri, prefix_len) != 0) {
-               /* TODO (rsync) why is this commented out? */
-//             pr_err("Global URI %s does not begin with '%s'.", rsync_uri,
-//                 PREFIX);
-               return -EINVAL;
-       }
+       *result = NULL;
+       last_equal = NULL;
+       error = 0;
 
        /*
-        * TODO (rsync) It took me a while to notice that this loop does not
-        * actually iterate. Why did you add it? It's misleading. If it's
-        * because you wanted to break instead of goto in the `tmp == NULL` if,
-        * then this should be a separate function instead.
+        * This code looks for 3 slashes to start compare path section.
         */
-       do {
-               tmp = rsync_uri + prefix_len;
+       tmp = uri1;
+       for (i = 0; i < 3; i++) {
                tmp = strchr(tmp, '/');
-
                if (tmp == NULL) {
-                       result_len = strlen(rsync_uri);
+                       goto end;
+               }
+               tmp++;
+       }
+
+       /* Compare protocol and domain. */
+       if (strncmp(uri1, uri2, tmp - uri1) != 0)
+               goto end;
+
+       while((tmp = strchr(tmp, '/')) != NULL) {
+               if (strncmp(uri1, uri2, tmp - uri1) != 0) {
                        break;
                }
+               last_equal = tmp;
+               tmp++;
+       }
 
-               tmp = tmp + 1;
-               tmp = strchr(tmp, '/');
+       if (last_equal != NULL) {
+               *result = malloc(last_equal - uri1 + 1 + 1); /*+ 1 slash + 1 null char*/
+               if (*result == NULL) {
+                       error = pr_enomem();
+                       goto end;
+               }
+               strncpy(*result, uri1, last_equal - uri1 + 1);
+               (*result)[last_equal - uri1 + 1] = '\0';
+       }
 
-               if (tmp != NULL)
-                       result_len = strlen(rsync_uri) - strlen(tmp);
-               else
-                       result_len = strlen(rsync_uri);
+end:
+       return error;
+}
 
-       } while (0);
+/*
+ * Compares rsync_uri against the uri_list and checks if can obtain a common
+ * short path.
+ * Returns NULL if URIs does not match any URI in the List.
+ * @see find_prefix_path
+ */
+static int
+compare_uris_and_short(char const *rsync_uri, char **result)
+{
+       struct uri *cursor;
+       int error;
 
-       short_uri = malloc(result_len + 1 + 1); /* slash + null chara */
-       if (!short_uri)
-               return -ENOMEM;
+       *result = NULL;
+       SLIST_FOREACH(cursor, rsync_uris, next) {
+               error = find_prefix_path(rsync_uri, cursor->string, result);
 
-       strncpy(short_uri, rsync_uri, result_len);
-       short_uri[result_len] = '/';
-       short_uri[result_len + 1] = '\0';
+               if (error)
+                       return error;
+
+               if (*result != NULL)
+                       break;
+       }
 
-       *result = short_uri;
        return 0;
 }
 
-int
-download_files(char const *rsync_uri)
+/*
+ * Removes filename or last path if not end with an slash char.
+ */
+static int
+get_path_only(char const *uri, size_t uri_len, size_t rsync_prefix_len,
+               char **result)
 {
-       int error;
-       char *rsync_uri_path, *localuri;
+       int error, i;
+       char tmp_uri[uri_len + 1];
+       char *slash_search = NULL;
+       bool is_domain_only = false;
 
-       if (!execute_rsync)
-               return 0;
+       error = 0;
 
-       if (is_uri_in_list(rsync_uri)){
-               pr_debug("(%s) ON LIST: %s", __func__, rsync_uri);
-               error = 0;
-               goto end;
-       } else {
-               pr_debug("(%s) DOWNLOAD: %s", __func__, rsync_uri);
+       for (i = 0; i < uri_len + 1; i++) {
+               tmp_uri[i] = uri[i];
        }
 
-       /*
-        * TODO (rsync) I don't understand why you need to do this.
-        * Please comment.
-        */
-       error = short_uri(rsync_uri, &rsync_uri_path);
-       if (error)
-               return error;
+       if (tmp_uri[uri_len - 1] != '/') {
+               slash_search = strrchr(tmp_uri, '/');
+       }
 
-       error = uri_g2l(rsync_uri_path, strlen(rsync_uri_path), &localuri);
-       if (error)
-               goto free_uri_path;
+       if (slash_search != NULL) {
+               if ((slash_search - tmp_uri) > rsync_prefix_len) {
+                       tmp_uri[slash_search - tmp_uri + 1] = '\0';
+                       uri_len = strlen(tmp_uri);
+               } else {
+                       is_domain_only = true;
+                       slash_search = NULL;
+               }
+       }
 
-       error = create_dir_recursive(localuri);
-       free(localuri);
-       if (error)
-               goto free_uri_path;
+       if (is_domain_only)
+               uri_len++; /* Add slash */
 
-       error = do_rsync(rsync_uri_path);
-       if (error)
-               goto free_uri_path;
+       *result = malloc(uri_len + 1); /* +1 null char */
+       if (*result == NULL) {
+               error = pr_enomem();
+               goto end;
+       }
 
-       /*
-        * TODO (rsync) This doesn't look right to me.
-        * The one you queried was rsync_uri. The one you're adding is
-        * rsync_uri_path. It looks like is_uri_in_list() will only match when
-        * short_uri() doesn't do anything.
-        */
-       error = add_uri_to_list(rsync_uri_path);
+       strcpy(*result, tmp_uri);
+
+       if (is_domain_only) {
+               (*result)[uri_len - 1] = '/';
+               (*result)[uri_len] = '\0';
+       }
 
-free_uri_path:
-       free(rsync_uri_path);
 end:
        return error;
-
 }
 
 static int
-create_dir_recursive(char *localuri)
+dir_exist(char *path, bool *result)
 {
-       char *temp_luri;
-       char path[PATH_MAX];
-       char *slash;
-       size_t localuri_len;
-       size_t repository_len;
-       unsigned int offset;
-
-       if (dir_exist(localuri))
-               return 0;
-
-       localuri_len = strlen(localuri);
-       repository_len = strlen(repository);
-       temp_luri = localuri + repository_len;
-
-       strcpy(path, repository);
-       offset = repository_len;
-
-       /*
-        * TODO (rsync) You might have gone a little overboard with this.
-        * Are you just trying to mkdir -p localuri?
-        * If so, wouldn't this be enough?
-        *
-        * for (i = 1; localuri[i] != '\0'; i++) {
-        *      if (localuri[i] == '/') {
-        *              localuri[i] = '\0';
-        *              create_dir(localuri); // handle error etc etc
-        *              localuri[i] = '/';
-        *      }
-        * }
-        *
-        * We're not in Java; our strings are mutable.
-        */
-
-       slash = strchr(temp_luri, '/');
-       while (slash != NULL) {
-               if (slash == temp_luri) {
-                       temp_luri++;
-                       localuri_len--;
-                       slash = strchr(temp_luri, '/');
-                       continue;
-               }
-               strcpy(path + offset, "/");
-               offset += 1;
-               strncpy(path + offset, temp_luri, slash - temp_luri);
-               offset += slash - temp_luri;
-               if (offset > localuri_len) {
-                       break;
-               }
-               path[offset] = '\0';
-               if (create_dir(path) == -1) {
-                       perror("Error while creating Dir");
-                       return -1;
+       int error;
+       struct stat _stat;
+       error = stat(path, &_stat);
+       if (error != 0) {
+               if (errno == ENOENT) {
+                       *result = false;
+                       goto end;
+               } else {
+                       return pr_errno(errno, "stat() failed");
                }
-               temp_luri += slash - temp_luri + 1;
-               slash = strchr(temp_luri, '/');
        }
 
-       if (offset < localuri_len) {
-               strcpy(path + offset, "/");
-               offset += 1;
-               strcpy(path + offset, temp_luri);
-               offset = localuri + localuri_len - temp_luri + offset + 1;
-               path[offset] = '\0';
-       }
+       if (!S_ISDIR(_stat.st_mode))
+               return pr_err("Path '%s' exist but is not a directory", path);
 
-       if (create_dir(path) == -1) {
-               perror("Error while creating Dir");
-               return -1;
-       }
+       *result = true;
+end:
        return 0;
-
 }
 
-static bool
-is_file(char const *path)
+static int
+create_dir(char *path)
 {
-       size_t path_len = strlen(path);
+       int error;
 
-       if (file_has_extension(path, path_len, ".cer"))
-               return true;
-       if (file_has_extension(path, path_len, ".gbr"))
-               return true;
-       if (file_has_extension(path, path_len, ".mft"))
-               return true;
+       error = mkdir(path, 0777);
 
-       return false;
+       if (error && errno != EEXIST)
+               return pr_errno(errno, "Error while making directory '%s'", path);
+
+       return 0;
 }
 
-static bool
-dir_exist(char *path)
+static int
+create_dir_recursive(char *localuri)
 {
-       int error;
-       struct stat _stat;
-       /*
-        * TODO (rsync) I don't know if you're aware of this, but you can
-        * usually run `man 2 [core c function]` or `man 3 [core c function]`
-        * and get a lot of info.
-        * `man 2 stat`, for example, contains a lot of stuff you clearly need
-        * to read.
-        */
-       error = stat(path, &_stat);
-       if (error == -1) {
-               /*
-                * TODO (rsync) Never do this. stat() can return -1 for a large
-                * number of reasons, and only one of them is "file not found."
-                * Return the error code and send the boolean as an out
-                * parameter.
-                */
-               return false; /* a dir or file not exist*/
+       int i, error;
+       bool exist = false;
+
+       error = dir_exist(localuri, &exist);
+       if (error)
+               return error;
+
+       if (exist)
+               return 0;
+
+       for (i = 1 + repository_len; localuri[i] != '\0'; i++) {
+               if (localuri[i] == '/') {
+                       localuri[i] = '\0';
+                       error = create_dir(localuri);
+                       localuri[i] = '/';
+                       if (error) {
+                               /* error msg already printed */
+                               return error;
+                       }
+               }
        }
 
-       /*
-        * TODO (rsync) Don't do this either. The function is called "dir_exist"
-        * but you're returning true even if the node happens to be a file,
-        * a socket, a named pipe, a door, etc etc. What's going to happen if
-        * each of these files interact with calling code?
-        */
-       return true;
+       return 0;
 }
 
-static int
-create_dir(char *path)
+int
+download_files(char const *rsync_uri)
 {
-       struct stat _stat;
        int error;
-       /*
-        * TODO (rsync) Does this really need to be a variable?
-        * You only use it once.
-        */
-       mode_t mode = 0777;
+       char *rsync_uri_path, *localuri, *tmp;
+       size_t prefix_len;
 
-       /*
-        * TODO (rsync) Again. The function is called "create_dir" but you're
-        * returning success on regular file found. And it's really weird that
-        * only .cer, .gbr and .mft files count as directories according to this
-        * if.
-        *
-        * Alternatively: As implemented, this if is redundant because the
-        * return 0 on successful stat below already succeeds on files. Not that
-        * I agree with the stat below either.
-        */
-       if (is_file(path))
-               return 0;
+       prefix_len = strlen(RSYNC_PREFIX);
 
-       error = stat(path, &_stat);
-       if (error != -1) {
-               /* a dir or file exist*/ /* TODO (rsync) STOP IT. */
+       if (!execute_rsync)
                return 0;
+
+       if (strlen(rsync_uri) < prefix_len ||
+                       strncmp(RSYNC_PREFIX, rsync_uri, prefix_len) != 0)
+               return pr_err("Global URI '%s' does not begin with '%s'.",
+                               rsync_uri, RSYNC_PREFIX);
+
+       if (is_uri_in_list(rsync_uri)){
+               pr_debug("(%s) ON LIST: %s", __func__, rsync_uri);
+               error = 0;
+               goto end;
+       } else {
+               pr_debug("(%s) DOWNLOAD: %s", __func__, rsync_uri);
        }
 
-       if (errno != ENOENT) {
-               /*
-                * TODO (rsync) Error message is unfriendly because the user
-                * has no context on what "stat" is.
-                * Something like "stat() failed" would be a little better.
-                * Use pr_errno() for the automatic errno string. (See `man 3
-                * perror`)
-                */
-               perror("stat");
-               /*
-                * TODO (rsync) No reason to lose the error code. Return errno
-                * (or better yet: the result of pr_errno(errno)) instead of -1.
-                */
-               return -1; /* another error occurs*/
+       error = get_path_only(rsync_uri, strlen(rsync_uri), prefix_len,
+                       &rsync_uri_path);
+       if (error)
+               return error;
+
+       error = compare_uris_and_short(rsync_uri_path, &tmp);
+       if (error) {
+               goto free_uri_path;
+       }
+
+       if (tmp != NULL) {
+               free(rsync_uri_path);
+               rsync_uri_path = tmp;
        }
 
-       error = mkdir(path, mode);
-       return error; /* TODO (rsync) No message on error */
+       error = uri_g2l(rsync_uri_path, strlen(rsync_uri_path), &localuri);
+       if (error)
+               goto free_uri_path;
+
+       error = create_dir_recursive(localuri);
+       if (error)
+               goto free_uri_path;
+
+       error = do_rsync(rsync_uri_path, localuri);
+       free(localuri);
+       if (error)
+               goto free_uri_path;
+
+       error = add_uri_to_list(rsync_uri_path);
+       if (error)
+               goto free_uri_path;
+
+       return 0;
+
+free_uri_path:
+       free(rsync_uri_path);
+end:
+       return error;
+
 }
index adbd3c723a364ef089d365f9f9665ec49b43a27f..22c0dbcbd91aa710ef77f52645435a74cd58006e 100644 (file)
@@ -1,12 +1,25 @@
 AM_CFLAGS = -pedantic -Wall -std=gnu11 -I../src ${CHECK_CFLAGS}
 MY_LDADD = ${CHECK_LIBS}
 
-check_PROGRAMS = line_file.test tal.test
+check_PROGRAMS = line_file.test tal.test rsync.test
 TESTS = ${check_PROGRAMS}
 
-line_file_test_SOURCES = line_file_test.c ../src/line_file.c ../src/line_file.h
+line_file_test_SOURCES = ../src/file.c ../src/file.h ../src/log.c ../src/log.h
+line_file_test_SOURCES += ../src/thread_var.c ../src/thread_var.h
+line_file_test_SOURCES += ../src/common.c ../src/common.h
+line_file_test_SOURCES += line_file_test.c ../src/line_file.c ../src/line_file.h
 line_file_test_LDADD = ${MY_LDADD}
 
-tal_test_SOURCES = tal_test.c ../src/line_file.c ../src/line_file.h
+tal_test_SOURCES = ../src/file.c ../src/file.h ../src/log.c ../src/log.h
+tal_test_SOURCES += ../src/thread_var.c ../src/thread_var.h
+tal_test_SOURCES += ../src/common.c ../src/common.h
+tal_test_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h
+tal_test_SOURCES += tal_test.c ../src/line_file.c ../src/line_file.h
 tal_test_CFLAGS = ${AM_CFLAGS} ${GLIB_CFLAGS}
 tal_test_LDADD = ${MY_LDADD} ${GLIB_LIBS}
+
+rsync_test_SOURCES = ../src/file.c ../src/file.h ../src/log.c ../src/log.h
+rsync_test_SOURCES += ../src/thread_var.c ../src/thread_var.h
+rsync_test_SOURCES += ../src/common.c ../src/common.h
+rsync_test_SOURCES += rsync_test.c
+rsync_test_LDADD = ${MY_LDADD}
\ No newline at end of file
diff --git a/test/rsync_test.c b/test/rsync_test.c
new file mode 100644 (file)
index 0000000..77d6373
--- /dev/null
@@ -0,0 +1,249 @@
+#include "rsync/rsync.c"
+
+#include <check.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "common.h"
+
+START_TEST(rsync_load_normal)
+{
+
+}
+END_TEST
+
+START_TEST(rsync_test_prefix_equals)
+{
+       struct uri rsync_uri;
+       char *uri = "proto://a/b/c";
+
+       rsync_uri.len = strlen(uri);
+       rsync_uri.string = uri;
+
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/c"), true);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/"), false);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/c/c"), true);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/cc"), false);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/cc/"), false);
+
+       uri = "proto://a/b/c/";
+       rsync_uri.len = strlen(uri);
+       rsync_uri.string = uri;
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/c"), false);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/"), false);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/c/c"), true);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/cc"), false);
+       ck_assert_int_eq(rsync_uri_prefix_equals(&rsync_uri, "proto://a/b/cc/"), false);
+
+}
+END_TEST
+
+START_TEST(rsync_test_list)
+{
+       struct uri *uri;
+       char *string_uri, *test_string;
+
+       rsync_init(true);
+
+       string_uri = "rsync://example.foo/repository/";
+       ck_assert_int_eq(add_uri_to_list(string_uri), 0);
+       string_uri = "rsync://example.foo/member_repository/";
+       ck_assert_int_eq(add_uri_to_list(string_uri), 0);
+       string_uri = "rsync://example.foz/repository/";
+       ck_assert_int_eq(add_uri_to_list(string_uri), 0);
+       string_uri = "rsync://example.boo/repo/";
+       ck_assert_int_eq(add_uri_to_list(string_uri), 0);
+       string_uri = "rsync://example.potato/rpki/";
+       ck_assert_int_eq(add_uri_to_list(string_uri), 0);
+
+       test_string = "rsync://example.foo/repository/";
+       ck_assert_int_eq(is_uri_in_list(test_string), true);
+       test_string = "rsync://example.foo/repository/abc/cdfg";
+       ck_assert_int_eq(is_uri_in_list(test_string), true);
+       test_string = "rsync://example.foo/member_repository/bca";
+       ck_assert_int_eq(is_uri_in_list(test_string), true);
+       test_string = "rsync://example.boo/repository/";
+       ck_assert_int_eq(is_uri_in_list(test_string), false);
+       test_string = "rsync://example.potato/repository/";
+       ck_assert_int_eq(is_uri_in_list(test_string), false);
+       test_string = "rsync://example.potato/rpki/abc/";
+       ck_assert_int_eq(is_uri_in_list(test_string), true);
+
+       /* rsync destroy */
+       while(!SLIST_EMPTY(rsync_uris)) {
+               uri = SLIST_FIRST(rsync_uris);
+               SLIST_REMOVE_HEAD(rsync_uris, next);
+               free(uri);
+       }
+
+       free(rsync_uris);
+}
+END_TEST
+
+static int
+malloc_string(char *string, char **result)
+{
+       *result = malloc(strlen(string) + 1);
+       if (*result == NULL) {
+               return pr_enomem();
+       }
+
+       strcpy(*result, string);
+       return 0;
+}
+
+static void
+test_get_path(char *test, char *expected)
+{
+       int error;
+       char *string, *result;
+       size_t rsync_prefix_len = strlen("rsync://");
+
+       error = malloc_string(test, &string);
+       if (error)
+               return;
+
+       error = get_path_only(string, strlen(string), rsync_prefix_len, &result);
+       if (error) {
+//             free(string);
+               return;
+       }
+
+       ck_assert_str_eq(expected, result);
+       ck_assert_str_eq(string, test);
+       free(string);
+       free(result);
+
+       return;
+}
+
+START_TEST(rsync_test_get_path)
+{
+       test_get_path("rsync://www.example.com/", "rsync://www.example.com/");
+       test_get_path("rsync://www.example.com", "rsync://www.example.com/");
+       test_get_path("rsync://www.example.com/test", "rsync://www.example.com/");
+       test_get_path("rsync://www.example.com/test/", "rsync://www.example.com/test/");
+       test_get_path("rsync://www.example.com/test/abc", "rsync://www.example.com/test/");
+       test_get_path("rsync://www.example.com/test/abc/", "rsync://www.example.com/test/abc/");
+       test_get_path("rsync://www.example.com/test/abc/abc.file", "rsync://www.example.com/test/abc/");
+       test_get_path("rsync://www.example.com/test/file.txt", "rsync://www.example.com/test/");
+}
+END_TEST
+
+static void
+test_get_prefix_from_URIs(char *expected, char *stored_uri, char *new_uri)
+{
+       int error;
+       char *result;
+       error = find_prefix_path(new_uri, stored_uri, &result);
+
+       if (error)
+               return;
+
+       if (expected == NULL) {
+               ck_assert_ptr_eq(expected, result);
+       } else {
+               ck_assert_str_eq(expected, result);
+       }
+
+       if (result != NULL)
+               free(result);
+}
+
+START_TEST(rsync_test_get_prefix)
+{
+       char *expected, *stored_uri, *new_uri;
+
+       new_uri = "rsync://www.example1.com/test/foo/";
+       stored_uri = "rsync://www.example1.com/test/bar/";
+       expected = "rsync://www.example1.com/test/";
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example2.com/test/foo/";
+       stored_uri = "rsync://www.example2.co/test/bar/";
+       expected = NULL;
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example3.com/test/foo/";
+       stored_uri = "rsync://www.example3.com/test/foo/test/";
+       expected = "rsync://www.example3.com/test/foo/";
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example4.com/test/";
+       stored_uri = "rsync://www.example4.com/test/foo/bar";
+       expected = "rsync://www.example4.com/test/";
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example5.com/foo/";
+       stored_uri = "rsync://www.example5.com/bar/";
+       expected = NULL;
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example6.com/bar/foo/";
+       stored_uri = "rsync://www.example6.com/bar/";
+       expected = "rsync://www.example6.com/bar/";
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example7.com/";
+       stored_uri = "rsync://www.example7.com/bar/";
+       expected = NULL;
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example8.com/bar";
+       stored_uri = "rsync://www.example8.com/";
+       expected = NULL;
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+       new_uri = "rsync://www.example9.com/bar/";
+       stored_uri = "rsync://www.example9.com/bar/";
+       expected = "rsync://www.example9.com/bar/";
+       test_get_prefix_from_URIs(expected, stored_uri, new_uri);
+
+}
+END_TEST
+
+Suite *rsync_load_suite(void)
+{
+       Suite *suite;
+       TCase *core, *prefix_equals, *uri_list, *test_get_path, *test_get_prefix;
+
+       core = tcase_create("Core");
+       tcase_add_test(core, rsync_load_normal);
+
+       prefix_equals = tcase_create("PrefixEquals");
+       tcase_add_test(prefix_equals, rsync_test_prefix_equals);
+
+       uri_list = tcase_create("uriList");
+       tcase_add_test(uri_list, rsync_test_list);
+
+       test_get_path = tcase_create("test_static_get_path");
+       tcase_add_test(test_get_path, rsync_test_get_path);
+
+       test_get_prefix = tcase_create("test_get_prefix");
+       tcase_add_test(test_get_prefix, rsync_test_get_prefix);
+
+       suite = suite_create("rsync_test()");
+       suite_add_tcase(suite, core);
+       suite_add_tcase(suite, prefix_equals);
+       suite_add_tcase(suite, uri_list);
+       suite_add_tcase(suite, test_get_path);
+       suite_add_tcase(suite, test_get_prefix);
+
+       return suite;
+}
+
+int main(void)
+{
+       Suite *suite;
+       SRunner *runner;
+       int tests_failed;
+
+       suite = rsync_load_suite();
+
+       runner = srunner_create(suite);
+       srunner_run_all(runner, CK_NORMAL);
+       tests_failed = srunner_ntests_failed(runner);
+       srunner_free(runner);
+
+       return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}