From: dhfelix Date: Fri, 18 Jan 2019 18:46:42 +0000 (-0600) Subject: Improve of rsync.c code X-Git-Tag: v0.0.2~110^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=827d7f2e0e4920f077df554a908d1ef6cdeb6766;p=thirdparty%2FFORT-validator.git Improve of rsync.c code -add unit test for rsync.c -TODO fix tal_tests --- diff --git a/src/object/certificate.c b/src/object/certificate.c index da744fe7..565dc6e4 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -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, }, diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c index 992a39cf..f1d71aad 100644 --- a/src/rsync/rsync.c +++ b/src/rsync/rsync.c @@ -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; + } diff --git a/test/Makefile.am b/test/Makefile.am index adbd3c72..22c0dbcb 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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 index 00000000..77d6373f --- /dev/null +++ b/test/rsync_test.c @@ -0,0 +1,249 @@ +#include "rsync/rsync.c" + +#include +#include +#include + +#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; +}