From: nulltoken Date: Sun, 3 Jul 2011 12:03:43 +0000 (+0200) Subject: signature: straighten the creation of a signature X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=a01acc47bb4cc8a5c8120c95c1b054d91506ef5a;p=libgit2.git signature: straighten the creation of a signature - Fails on empty name and/or email - Trims leading and trailing spaces of name and email --- diff --git a/src/signature.c b/src/signature.c index b8356dacf..bc88a76e1 100644 --- a/src/signature.c +++ b/src/signature.c @@ -33,25 +33,83 @@ void git_signature_free(git_signature *sig) if (sig == NULL) return; - free(sig->name); - free(sig->email); + if (sig->name) + free(sig->name); + + if (sig->email) + free(sig->email); + free(sig); } +static const char *skip_leading_spaces(const char *buffer, const char *buffer_end) +{ + while (*buffer == ' ' && buffer < buffer_end) + buffer++; + + return buffer; +} + +static const char *skip_trailing_spaces(const char *buffer_start, const char *buffer_end) +{ + while (*buffer_end == ' ' && buffer_end > buffer_start) + buffer_end--; + + return buffer_end; +} + +static int process_trimming(const char *input, char **storage, const char *input_end, int fail_when_empty) +{ + const char *left, *right; + int trimmed_input_length; + + left = skip_leading_spaces(input, input_end); + right = skip_trailing_spaces(input, input_end - 1); + + if (right <= left) + if (fail_when_empty) + return git__throw(GIT_EINVALIDARGS, "Failed to trim. Input is either empty or only contains spaces"); + else + right = left - 1; + + trimmed_input_length = right - left + 1; + + *storage = git__malloc(trimmed_input_length + 1); + if (*storage == NULL) + return GIT_ENOMEM; + + memcpy(*storage, left, trimmed_input_length); + (*storage)[trimmed_input_length] = 0; + + return GIT_SUCCESS; +} + git_signature *git_signature_new(const char *name, const char *email, git_time_t time, int offset) { + int error; git_signature *p = NULL; + assert(name && email); + if ((p = git__malloc(sizeof(git_signature))) == NULL) goto cleanup; - p->name = git__strdup(name); - p->email = git__strdup(email); - p->when.time = time; - p->when.offset = offset; + memset(p, 0x0, sizeof(git_signature)); + + error = process_trimming(name, &p->name, name + strlen(name), 1); + if (error < GIT_SUCCESS) { + git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'name' argument is invalid"); + goto cleanup; + } - if (p->name == NULL || p->email == NULL) + error = process_trimming(email, &p->email, email + strlen(email), 1); + if (error < GIT_SUCCESS) { + git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'email' argument is invalid"); goto cleanup; + } + + p->when.time = time; + p->when.offset = offset; return p; @@ -149,46 +207,28 @@ static int parse_timezone_offset(const char *buffer, int *offset_out) } int process_next_token(const char **buffer_out, char **storage, - const char *token_end, const char *line_end) + const char *token_end, const char *right_boundary) { - int name_length = 0; - const char *buffer = *buffer_out; - - /* Skip leading spaces before the name */ - while (*buffer == ' ' && buffer < line_end) - buffer++; - - name_length = token_end - buffer; - - /* Trim trailing spaces after the name */ - while (buffer[name_length - 1] == ' ' && name_length > 0) - name_length--; - - *storage = git__malloc(name_length + 1); - if (*storage == NULL) - return GIT_ENOMEM; + int error = process_trimming(*buffer_out, storage, token_end, 0); + if (error < GIT_SUCCESS) + return error; - memcpy(*storage, buffer, name_length); - (*storage)[name_length] = 0; - buffer = token_end + 1; + *buffer_out = token_end + 1; - if (buffer > line_end) + if (*buffer_out > right_boundary) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short"); - *buffer_out = buffer; return GIT_SUCCESS; } -const char* scan_for_previous_token(const char *buffer, const char *left_boundary) +const char *scan_for_previous_token(const char *buffer, const char *left_boundary) { - const char *start = buffer; + const char *start; - if (start <= left_boundary) + if (buffer <= left_boundary) return NULL; - /* Trim potential trailing spaces */ - while (*start == ' ' && start > left_boundary) - start--; + start = skip_trailing_spaces(left_boundary, buffer); /* Search for previous occurence of space */ while (start[-1] != ' ' && start > left_boundary) diff --git a/tests/t04-commit.c b/tests/t04-commit.c index 52770720e..0f480e552 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -331,7 +331,6 @@ BEGIN_TEST(parse1, "parse the signature line in a commit") 123456, -60); - /* Parse an obviously invalid signature */ TEST_SIGNATURE_PASS( "committer <>\n", @@ -446,6 +445,39 @@ BEGIN_TEST(parse1, "parse the signature line in a commit") END_TEST +static int try_build_signature(const char *name, const char *email, git_time_t time, int offset) +{ + git_signature *sign; + int error = GIT_SUCCESS; + + sign = git_signature_new(name, email, time, offset); + + if (sign == NULL) + error = GIT_ERROR; + + git_signature_free((git_signature *)sign); + + return error; +} + +BEGIN_TEST(signature0, "creating a signature trims leading and trailing spaces") + git_signature *sign; + sign = git_signature_new(" nulltoken ", " emeric.fermas@gmail.com ", 1234567890, 60); + must_be_true(sign != NULL); + must_pass(strcmp(sign->name, "nulltoken")); + must_pass(strcmp(sign->email, "emeric.fermas@gmail.com")); + git_signature_free((git_signature *)sign); +END_TEST + +BEGIN_TEST(signature1, "can not create a signature with empty name or email") + must_pass(try_build_signature("nulltoken", "emeric.fermas@gmail.com", 1234567890, 60)); + + must_fail(try_build_signature("", "emeric.fermas@gmail.com", 1234567890, 60)); + must_fail(try_build_signature(" ", "emeric.fermas@gmail.com", 1234567890, 60)); + must_fail(try_build_signature("nulltoken", "", 1234567890, 60)); + must_fail(try_build_signature("nulltoken", " ", 1234567890, 60)); +END_TEST + /* External declaration for testing the buffer parsing method */ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags); @@ -722,4 +754,7 @@ BEGIN_SUITE(commit) ADD_TEST(write0); ADD_TEST(root0); + + ADD_TEST(signature0); + ADD_TEST(signature1); END_SUITE