diff options
-rw-r--r-- | src/commit.c | 27 | ||||
-rw-r--r-- | src/config_file.c | 155 | ||||
-rw-r--r-- | src/config_mem.c | 10 | ||||
-rw-r--r-- | src/config_snapshot.c | 45 | ||||
-rw-r--r-- | src/diff_generate.c | 2 | ||||
-rw-r--r-- | src/futils.c | 1 | ||||
-rw-r--r-- | src/integer.h | 28 | ||||
-rw-r--r-- | src/parse.c | 10 | ||||
-rw-r--r-- | src/parse.h | 1 | ||||
-rw-r--r-- | src/patch_parse.c | 54 | ||||
-rw-r--r-- | src/refdb_fs.c | 93 | ||||
-rw-r--r-- | src/reflog.c | 24 | ||||
-rw-r--r-- | src/stash.c | 80 | ||||
-rw-r--r-- | tests/commit/write.c | 40 | ||||
-rw-r--r-- | tests/config/snapshot.c | 37 | ||||
-rw-r--r-- | tests/patch/parse.c | 47 | ||||
-rw-r--r-- | tests/patch/patch_common.h | 33 | ||||
-rw-r--r-- | tests/refs/reflog/messages.c | 21 | ||||
-rw-r--r-- | tests/refs/reflog/reflog.c | 38 | ||||
-rw-r--r-- | tests/stash/save.c | 20 |
20 files changed, 499 insertions, 267 deletions
diff --git a/src/commit.c b/src/commit.c index 20e0b8a47..aca65ff2d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -878,6 +878,14 @@ static void format_header_field(git_buf *out, const char *field, const char *con git_buf_putc(out, '\n'); } +static const git_oid *commit_parent_from_commit(size_t n, void *payload) +{ + const git_commit *commit = (const git_commit *) payload; + + return git_array_get(commit->parent_ids, n); + +} + int git_commit_create_with_signature( git_oid *out, git_repository *repo, @@ -890,12 +898,26 @@ int git_commit_create_with_signature( const char *field; const char *header_end; git_buf commit = GIT_BUF_INIT; + git_commit *parsed; + git_array_oid_t parents = GIT_ARRAY_INIT; - /* We start by identifying the end of the commit header */ + /* The first step is to verify that all the tree and parents exist */ + parsed = git__calloc(1, sizeof(git_commit)); + GIT_ERROR_CHECK_ALLOC(parsed); + if ((error = commit_parse(parsed, commit_content, strlen(commit_content), 0)) < 0) + goto cleanup; + + if ((error = validate_tree_and_parents(&parents, repo, &parsed->tree_id, commit_parent_from_commit, parsed, NULL, true)) < 0) + goto cleanup; + + git_array_clear(parents); + + /* Then we start appending by identifying the end of the commit header */ header_end = strstr(commit_content, "\n\n"); if (!header_end) { git_error_set(GIT_ERROR_INVALID, "malformed commit contents"); - return -1; + error = -1; + goto cleanup; } /* The header ends after the first LF */ @@ -919,6 +941,7 @@ int git_commit_create_with_signature( goto cleanup; cleanup: + git_commit__free(parsed); git_buf_dispose(&commit); return error; } diff --git a/src/config_file.c b/src/config_file.c index bf770c95b..c9e36493e 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -9,23 +9,17 @@ #include "git2/config.h" #include "git2/sys/config.h" -#include "git2/types.h" #include "array.h" -#include "buf_text.h" #include "buffer.h" #include "config_backend.h" #include "config_entries.h" #include "config_parse.h" #include "filebuf.h" #include "regexp.h" -#include "strmap.h" #include "sysdir.h" #include "wildmatch.h" -#include <ctype.h> -#include <sys/types.h> - /* Max depth for [include] directives */ #define MAX_INCLUDE_DEPTH 10 @@ -60,9 +54,9 @@ typedef struct { unsigned int depth; } config_file_parse_data; -static int config_read(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth); -static int config_read_buffer(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); -static int config_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value); +static int config_file_read(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth); +static int config_file_read_buffer(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); +static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value); static char *escape_value(const char *ptr); /** @@ -70,21 +64,21 @@ static char *escape_value(const char *ptr); * refcount. This is its own function to make sure we use the mutex to * avoid the map pointer from changing under us. */ -static git_config_entries *diskfile_entries_take(config_file_backend *b) +static int config_file_entries_take(git_config_entries **out, config_file_backend *b) { - git_config_entries *entries; + int error; - if (git_mutex_lock(&b->values_mutex) < 0) { - git_error_set(GIT_ERROR_OS, "failed to lock config backend"); - return NULL; + if ((error = git_mutex_lock(&b->values_mutex)) < 0) { + git_error_set(GIT_ERROR_OS, "failed to lock config backend"); + return error; } - entries = b->entries; - git_config_entries_incref(entries); + git_config_entries_incref(b->entries); + *out = b->entries; git_mutex_unlock(&b->values_mutex); - return entries; + return 0; } static void config_file_clear(config_file *file) @@ -103,7 +97,7 @@ static void config_file_clear(config_file *file) git__free(file->path); } -static int config_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) +static int config_file_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); int res; @@ -117,7 +111,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level, const if (!git_path_exists(b->file.path)) return 0; - if (res < 0 || (res = config_read(b->entries, repo, &b->file, level, 0)) < 0) { + if (res < 0 || (res = config_file_read(b->entries, repo, &b->file, level, 0)) < 0) { git_config_entries_free(b->entries); b->entries = NULL; } @@ -125,7 +119,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level, const return res; } -static int config_is_modified(int *modified, config_file *file) +static int config_file_is_modified(int *modified, config_file *file) { config_file *include; git_buf buf = GIT_BUF_INIT; @@ -151,7 +145,7 @@ static int config_is_modified(int *modified, config_file *file) check_includes: git_array_foreach(file->includes, i, include) { - if ((error = config_is_modified(modified, include)) < 0 || *modified) + if ((error = config_file_is_modified(modified, include)) < 0 || *modified) goto out; } @@ -161,7 +155,7 @@ out: return error; } -static int config_set_entries(git_config_backend *cfg, git_config_entries *entries) +static int config_file_set_entries(git_config_backend *cfg, git_config_entries *entries) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *old = NULL; @@ -193,16 +187,16 @@ out: return error; } -static int config_refresh_from_buffer(git_config_backend *cfg, const char *buf, size_t buflen) +static int config_file_refresh_from_buffer(git_config_backend *cfg, const char *buf, size_t buflen) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *entries = NULL; int error; if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_read_buffer(entries, b->repo, &b->file, - b->level, 0, buf, buflen)) < 0 || - (error = config_set_entries(cfg, entries)) < 0) + (error = config_file_read_buffer(entries, b->repo, &b->file, + b->level, 0, buf, buflen)) < 0 || + (error = config_file_set_entries(cfg, entries)) < 0) goto out; entries = NULL; @@ -211,7 +205,7 @@ out: return error; } -static int config_refresh(git_config_backend *cfg) +static int config_file_refresh(git_config_backend *cfg) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *entries = NULL; @@ -220,15 +214,15 @@ static int config_refresh(git_config_backend *cfg) if (cfg->readonly) return 0; - if ((error = config_is_modified(&modified, &b->file)) < 0 && error != GIT_ENOTFOUND) + if ((error = config_file_is_modified(&modified, &b->file)) < 0 && error != GIT_ENOTFOUND) goto out; if (!modified) return 0; if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_read(entries, b->repo, &b->file, b->level, 0)) < 0 || - (error = config_set_entries(cfg, entries)) < 0) + (error = config_file_read(entries, b->repo, &b->file, b->level, 0)) < 0 || + (error = config_file_set_entries(cfg, entries)) < 0) goto out; entries = NULL; @@ -238,7 +232,7 @@ out: return (error == GIT_ENOTFOUND) ? 0 : error; } -static void backend_free(git_config_backend *_backend) +static void config_file_free(git_config_backend *_backend) { config_file_backend *backend = GIT_CONTAINER_OF(_backend, config_file_backend, parent); @@ -251,26 +245,33 @@ static void backend_free(git_config_backend *_backend) git__free(backend); } -static int config_iterator_new( +static int config_file_iterator( git_config_iterator **iter, struct git_config_backend *backend) { config_file_backend *b = GIT_CONTAINER_OF(backend, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_entries *dupped = NULL, *entries = NULL; int error; - if ((error = config_refresh(backend)) < 0 || - (error = git_config_entries_dup(&entries, b->entries)) < 0 || - (error = git_config_entries_iterator_new(iter, entries)) < 0) + if ((error = config_file_refresh(backend)) < 0 || + (error = config_file_entries_take(&entries, b)) < 0 || + (error = git_config_entries_dup(&dupped, entries)) < 0 || + (error = git_config_entries_iterator_new(iter, dupped)) < 0) goto out; out: /* Let iterator delete duplicated entries when it's done */ git_config_entries_free(entries); + git_config_entries_free(dupped); return error; } -static int config_set(git_config_backend *cfg, const char *name, const char *value) +static int config_file_snapshot(git_config_backend **out, git_config_backend *backend) +{ + return git_config_backend_snapshot(out, backend); +} + +static int config_file_set(git_config_backend *cfg, const char *name, const char *value) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *entries; @@ -281,8 +282,8 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val if ((error = git_config__normalize_name(name, &key)) < 0) return error; - if ((entries = diskfile_entries_take(b)) == NULL) - return -1; + if ((error = config_file_entries_take(&entries, b)) < 0) + return error; /* Check whether we'd be modifying an included or multivar key */ if ((error = git_config_entries_get_unique(&existing, entries, key)) < 0) { @@ -302,7 +303,7 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val GIT_ERROR_CHECK_ALLOC(esc_value); } - if ((error = config_write(b, name, key, NULL, esc_value)) < 0) + if ((error = config_file_write(b, name, key, NULL, esc_value)) < 0) goto out; out: @@ -313,7 +314,7 @@ out: } /* release the map containing the entry as an equivalent to freeing it */ -static void free_diskfile_entry(git_config_entry *entry) +static void config_file_entry_free(git_config_entry *entry) { git_config_entries *entries = (git_config_entries *) entry->payload; git_config_entries_free(entries); @@ -322,32 +323,32 @@ static void free_diskfile_entry(git_config_entry *entry) /* * Internal function that actually gets the value in string form */ -static int config_get(git_config_backend *cfg, const char *key, git_config_entry **out) +static int config_file_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *entries = NULL; git_config_entry *entry; int error = 0; - if (!h->parent.readonly && ((error = config_refresh(cfg)) < 0)) + if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0)) return error; - if ((entries = diskfile_entries_take(h)) == NULL) - return -1; + if ((error = config_file_entries_take(&entries, h)) < 0) + return error; if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { git_config_entries_free(entries); return error; } - entry->free = free_diskfile_entry; + entry->free = config_file_entry_free; entry->payload = entries; *out = entry; return 0; } -static int config_set_multivar( +static int config_file_set_multivar( git_config_backend *cfg, const char *name, const char *regexp, const char *value) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); @@ -363,8 +364,8 @@ static int config_set_multivar( if ((result = git_regexp_compile(&preg, regexp, 0)) < 0) goto out; - /* If we do have it, set call config_write() and reload */ - if ((result = config_write(b, name, key, &preg, value)) < 0) + /* If we do have it, set call config_file_write() and reload */ + if ((result = config_file_write(b, name, key, &preg, value)) < 0) goto out; out: @@ -374,7 +375,7 @@ out: return result; } -static int config_delete(git_config_backend *cfg, const char *name) +static int config_file_delete(git_config_backend *cfg, const char *name) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *entries = NULL; @@ -385,7 +386,7 @@ static int config_delete(git_config_backend *cfg, const char *name) if ((error = git_config__normalize_name(name, &key)) < 0) goto out; - if ((entries = diskfile_entries_take(b)) == NULL) + if ((error = config_file_entries_take(&entries, b)) < 0) goto out; /* Check whether we'd be modifying an included or multivar key */ @@ -395,7 +396,7 @@ static int config_delete(git_config_backend *cfg, const char *name) goto out; } - if ((error = config_write(b, name, entry->name, NULL, NULL)) < 0) + if ((error = config_file_write(b, name, entry->name, NULL, NULL)) < 0) goto out; out: @@ -404,7 +405,7 @@ out: return error; } -static int config_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) +static int config_file_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_entries *entries = NULL; @@ -416,10 +417,8 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con if ((result = git_config__normalize_name(name, &key)) < 0) goto out; - if ((entries = diskfile_entries_take(b)) == NULL) { - result = -1; + if ((result = config_file_entries_take(&entries, b)) < 0) goto out; - } if ((result = git_config_entries_get(&entry, entries, key)) < 0) { if (result == GIT_ENOTFOUND) @@ -430,7 +429,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con if ((result = git_regexp_compile(&preg, regexp, 0)) < 0) goto out; - if ((result = config_write(b, name, key, &preg, NULL)) < 0) + if ((result = config_file_write(b, name, key, &preg, NULL)) < 0) goto out; out: @@ -440,7 +439,7 @@ out: return result; } -static int config_lock(git_config_backend *_cfg) +static int config_file_lock(git_config_backend *_cfg) { config_file_backend *cfg = GIT_CONTAINER_OF(_cfg, config_file_backend, parent); int error; @@ -459,7 +458,7 @@ static int config_lock(git_config_backend *_cfg) } -static int config_unlock(git_config_backend *_cfg, int success) +static int config_file_unlock(git_config_backend *_cfg, int success) { config_file_backend *cfg = GIT_CONTAINER_OF(_cfg, config_file_backend, parent); int error = 0; @@ -490,17 +489,17 @@ int git_config_backend_from_file(git_config_backend **out, const char *path) GIT_ERROR_CHECK_ALLOC(backend->file.path); git_array_init(backend->file.includes); - backend->parent.open = config_open; - backend->parent.get = config_get; - backend->parent.set = config_set; - backend->parent.set_multivar = config_set_multivar; - backend->parent.del = config_delete; - backend->parent.del_multivar = config_delete_multivar; - backend->parent.iterator = config_iterator_new; - backend->parent.snapshot = git_config_backend_snapshot; - backend->parent.lock = config_lock; - backend->parent.unlock = config_unlock; - backend->parent.free = backend_free; + backend->parent.open = config_file_open; + backend->parent.get = config_file_get; + backend->parent.set = config_file_set; + backend->parent.set_multivar = config_file_set_multivar; + backend->parent.del = config_file_delete; + backend->parent.del_multivar = config_file_delete_multivar; + backend->parent.iterator = config_file_iterator; + backend->parent.snapshot = config_file_snapshot; + backend->parent.lock = config_file_lock; + backend->parent.unlock = config_file_unlock; + backend->parent.free = config_file_free; *out = (git_config_backend *)backend; @@ -574,8 +573,8 @@ static int parse_include(config_file_parse_data *parse_data, const char *file) git_array_init(include->includes); include->path = git_buf_detach(&path); - result = config_read(parse_data->entries, parse_data->repo, - include, parse_data->level, parse_data->depth+1); + result = config_file_read(parse_data->entries, parse_data->repo, include, + parse_data->level, parse_data->depth+1); if (result == GIT_ENOTFOUND) { git_error_clear(); @@ -793,7 +792,7 @@ static int read_on_variable( return result; } -static int config_read_buffer( +static int config_file_read_buffer( git_config_entries *entries, const git_repository *repo, config_file *file, @@ -833,7 +832,7 @@ out: return error; } -static int config_read( +static int config_file_read( git_config_entries *entries, const git_repository *repo, config_file *file, @@ -856,8 +855,8 @@ static int config_read( if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0) goto out; - if ((error = config_read_buffer(entries, repo, file, level, depth, - contents.ptr, contents.size)) < 0) + if ((error = config_file_read_buffer(entries, repo, file, level, depth, + contents.ptr, contents.size)) < 0) goto out; out: @@ -1088,7 +1087,7 @@ static int write_on_eof( /* * This is pretty much the parsing, except we write out anything we don't have */ -static int config_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char* value) +static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char* value) { char *orig_section = NULL, *section = NULL, *orig_name, *name, *ldot; @@ -1149,7 +1148,7 @@ static int config_write(config_file_backend *cfg, const char *orig_key, const ch if ((error = git_filebuf_commit(&file)) < 0) goto done; - if ((error = config_refresh_from_buffer(&cfg->parent, buf.ptr, buf.size)) < 0) + if ((error = config_file_refresh_from_buffer(&cfg->parent, buf.ptr, buf.size)) < 0) goto done; } diff --git a/src/config_mem.c b/src/config_mem.c index e4006db32..5b573a995 100644 --- a/src/config_mem.c +++ b/src/config_mem.c @@ -170,14 +170,6 @@ static int config_memory_unlock(git_config_backend *backend, int success) return config_error_readonly(); } -static int config_memory_snapshot(git_config_backend **out, git_config_backend *backend) -{ - GIT_UNUSED(out); - GIT_UNUSED(backend); - git_error_set(GIT_ERROR_CONFIG, "this backend does not support snapshots"); - return -1; -} - static void config_memory_free(git_config_backend *_backend) { config_memory_backend *backend = (config_memory_backend *)_backend; @@ -219,7 +211,7 @@ int git_config_backend_from_string(git_config_backend **out, const char *cfg, si backend->parent.iterator = config_memory_iterator; backend->parent.lock = config_memory_lock; backend->parent.unlock = config_memory_unlock; - backend->parent.snapshot = config_memory_snapshot; + backend->parent.snapshot = git_config_backend_snapshot; backend->parent.free = config_memory_free; *out = (git_config_backend *)backend; diff --git a/src/config_snapshot.c b/src/config_snapshot.c index 764abe208..62b9068fb 100644 --- a/src/config_snapshot.c +++ b/src/config_snapshot.c @@ -22,7 +22,7 @@ static int config_error_readonly(void) return -1; } -static int config_iterator_new_readonly( +static int config_snapshot_iterator( git_config_iterator **iter, struct git_config_backend *backend) { @@ -41,13 +41,13 @@ out: } /* release the map containing the entry as an equivalent to freeing it */ -static void free_diskfile_entry(git_config_entry *entry) +static void config_snapshot_entry_free(git_config_entry *entry) { git_config_entries *entries = (git_config_entries *) entry->payload; git_config_entries_free(entries); } -static int config_get_readonly(git_config_backend *cfg, const char *key, git_config_entry **out) +static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); git_config_entries *entries = NULL; @@ -68,14 +68,14 @@ static int config_get_readonly(git_config_backend *cfg, const char *key, git_con return error; } - entry->free = free_diskfile_entry; + entry->free = config_snapshot_entry_free; entry->payload = entries; *out = entry; return 0; } -static int config_set_readonly(git_config_backend *cfg, const char *name, const char *value) +static int config_snapshot_set(git_config_backend *cfg, const char *name, const char *value) { GIT_UNUSED(cfg); GIT_UNUSED(name); @@ -84,7 +84,7 @@ static int config_set_readonly(git_config_backend *cfg, const char *name, const return config_error_readonly(); } -static int config_set_multivar_readonly( +static int config_snapshot_set_multivar( git_config_backend *cfg, const char *name, const char *regexp, const char *value) { GIT_UNUSED(cfg); @@ -95,7 +95,7 @@ static int config_set_multivar_readonly( return config_error_readonly(); } -static int config_delete_multivar_readonly(git_config_backend *cfg, const char *name, const char *regexp) +static int config_snapshot_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) { GIT_UNUSED(cfg); GIT_UNUSED(name); @@ -104,7 +104,7 @@ static int config_delete_multivar_readonly(git_config_backend *cfg, const char * return config_error_readonly(); } -static int config_delete_readonly(git_config_backend *cfg, const char *name) +static int config_snapshot_delete(git_config_backend *cfg, const char *name) { GIT_UNUSED(cfg); GIT_UNUSED(name); @@ -112,14 +112,14 @@ static int config_delete_readonly(git_config_backend *cfg, const char *name) return config_error_readonly(); } -static int config_lock_readonly(git_config_backend *_cfg) +static int config_snapshot_lock(git_config_backend *_cfg) { GIT_UNUSED(_cfg); return config_error_readonly(); } -static int config_unlock_readonly(git_config_backend *_cfg, int success) +static int config_snapshot_unlock(git_config_backend *_cfg, int success) { GIT_UNUSED(_cfg); GIT_UNUSED(success); @@ -127,7 +127,7 @@ static int config_unlock_readonly(git_config_backend *_cfg, int success) return config_error_readonly(); } -static void backend_readonly_free(git_config_backend *_backend) +static void config_snapshot_free(git_config_backend *_backend) { config_snapshot_backend *backend = GIT_CONTAINER_OF(_backend, config_snapshot_backend, parent); @@ -139,7 +139,7 @@ static void backend_readonly_free(git_config_backend *_backend) git__free(backend); } -static int config_readonly_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) +static int config_snapshot_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); git_config_entries *entries = NULL; @@ -188,16 +188,17 @@ int git_config_backend_snapshot(git_config_backend **out, git_config_backend *so backend->parent.readonly = 1; backend->parent.version = GIT_CONFIG_BACKEND_VERSION; - backend->parent.open = config_readonly_open; - backend->parent.get = config_get_readonly; - backend->parent.set = config_set_readonly; - backend->parent.set_multivar = config_set_multivar_readonly; - backend->parent.del = config_delete_readonly; - backend->parent.del_multivar = config_delete_multivar_readonly; - backend->parent.iterator = config_iterator_new_readonly; - backend->parent.lock = config_lock_readonly; - backend->parent.unlock = config_unlock_readonly; - backend->parent.free = backend_readonly_free; + backend->parent.open = config_snapshot_open; + backend->parent.get = config_snapshot_get; + backend->parent.set = config_snapshot_set; + backend->parent.set_multivar = config_snapshot_set_multivar; + backend->parent.snapshot = git_config_backend_snapshot; + backend->parent.del = config_snapshot_delete; + backend->parent.del_multivar = config_snapshot_delete_multivar; + backend->parent.iterator = config_snapshot_iterator; + backend->parent.lock = config_snapshot_lock; + backend->parent.unlock = config_snapshot_unlock; + backend->parent.free = config_snapshot_free; *out = &backend->parent; diff --git a/src/diff_generate.c b/src/diff_generate.c index b68efb6ea..7ec24d50d 100644 --- a/src/diff_generate.c +++ b/src/diff_generate.c @@ -1371,7 +1371,7 @@ int git_diff_tree_to_index( if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 || (error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 || (error = git_iterator_for_index(&b, repo, index, &b_opts)) < 0 || - (error = git_diff__from_iterators(&diff, repo, a, b, opts) < 0)) + (error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0) goto out; /* if index is in case-insensitive order, re-sort deltas to match */ diff --git a/src/futils.c b/src/futils.c index e15c8017f..7454844e7 100644 --- a/src/futils.c +++ b/src/futils.c @@ -476,6 +476,7 @@ int git_futils_mkdir( break; } else if (errno != ENOENT) { git_error_set(GIT_ERROR_OS, "failed to stat '%s'", parent_path.ptr); + error = -1; goto done; } diff --git a/src/integer.h b/src/integer.h index 4738e9e35..e024a86d3 100644 --- a/src/integer.h +++ b/src/integer.h @@ -72,15 +72,25 @@ GIT_INLINE(int) git__is_int(long long p) # error compiler has add with overflow intrinsics but SIZE_MAX is unknown # endif +# define git__add_int_overflow(out, one, two) \ + __builtin_sadd_overflow(one, two, out) +# define git__sub_int_overflow(out, one, two) \ + __builtin_ssub_overflow(one, two, out) + /* Use Microsoft's safe integer handling functions where available */ #elif defined(_MSC_VER) +# define ENABLE_INTSAFE_SIGNED_FUNCTIONS # include <intsafe.h> # define git__add_sizet_overflow(out, one, two) \ (SizeTAdd(one, two, out) != S_OK) # define git__multiply_sizet_overflow(out, one, two) \ (SizeTMult(one, two, out) != S_OK) +#define git__add_int_overflow(out, one, two) \ + (IntAdd(one, two, out) != S_OK) +#define git__sub_int_overflow(out, one, two) \ + (IntSub(one, two, out) != S_OK) #else @@ -108,6 +118,24 @@ GIT_INLINE(bool) git__multiply_sizet_overflow(size_t *out, size_t one, size_t tw return false; } +GIT_INLINE(bool) git__add_int_overflow(int *out, int one, int two) +{ + if ((two > 0 && one > (INT_MAX - two)) || + (two < 0 && one < (INT_MIN - two))) + return true; + *out = one + two; + return false; +} + +GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two) +{ + if ((two > 0 && one < (INT_MIN + two)) || + (two < 0 && one > (INT_MAX + two))) + return true; + *out = one - two; + return false; +} + #endif #endif diff --git a/src/parse.c b/src/parse.c index b04fda36b..0a10758bf 100644 --- a/src/parse.c +++ b/src/parse.c @@ -101,6 +101,16 @@ int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base) return 0; } +int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx) +{ + if (ctx->line_len < GIT_OID_HEXSZ) + return -1; + if ((git_oid_fromstrn(out, ctx->line, GIT_OID_HEXSZ)) < 0) + return -1; + git_parse_advance_chars(ctx, GIT_OID_HEXSZ); + return 0; +} + int git_parse_peek(char *out, git_parse_ctx *ctx, int flags) { size_t remain = ctx->line_len; diff --git a/src/parse.h b/src/parse.h index 188ac281c..0ecb7c103 100644 --- a/src/parse.h +++ b/src/parse.h @@ -50,6 +50,7 @@ int git_parse_advance_expected( int git_parse_advance_ws(git_parse_ctx *ctx); int git_parse_advance_nl(git_parse_ctx *ctx); int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base); +int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx); enum GIT_PARSE_PEEK_FLAGS { GIT_PARSE_PEEK_SKIP_WHITESPACE = (1 << 0) diff --git a/src/patch_parse.c b/src/patch_parse.c index 126918249..1bf0190c3 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -70,31 +70,36 @@ static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx, size_t int error; if ((error = git_buf_put(path, ctx->parse_ctx.line, path_len)) < 0) - goto done; + return error; git_parse_advance_chars(&ctx->parse_ctx, path_len); git_buf_rtrim(path); - if (path->size > 0 && path->ptr[0] == '"') - error = git_buf_unquote(path); - - if (error < 0) - goto done; + if (path->size > 0 && path->ptr[0] == '"' && + (error = git_buf_unquote(path)) < 0) + return error; git_path_squash_slashes(path); -done: - return error; + if (!path->size) + return git_parse_err("patch contains empty path at line %"PRIuZ, + ctx->parse_ctx.line_num); + + return 0; } static int parse_header_path(char **out, git_patch_parse_ctx *ctx) { git_buf path = GIT_BUF_INIT; - int error = parse_header_path_buf(&path, ctx, header_path_len(ctx)); + int error; + if ((error = parse_header_path_buf(&path, ctx, header_path_len(ctx))) < 0) + goto out; *out = git_buf_detach(&path); +out: + git_buf_dispose(&path); return error; } @@ -104,6 +109,12 @@ static int parse_header_git_oldpath( git_buf old_path = GIT_BUF_INIT; int error; + if (patch->old_path) { + error = git_parse_err("patch contains duplicate old path at line %"PRIuZ, + ctx->parse_ctx.line_num); + goto out; + } + if ((error = parse_header_path_buf(&old_path, ctx, ctx->parse_ctx.line_len - 1)) < 0) goto out; @@ -120,9 +131,14 @@ static int parse_header_git_newpath( git_buf new_path = GIT_BUF_INIT; int error; - if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0) + if (patch->new_path) { + error = git_parse_err("patch contains duplicate new path at line %"PRIuZ, + ctx->parse_ctx.line_num); goto out; + } + if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0) + goto out; patch->new_path = git_buf_detach(&new_path); out: @@ -564,11 +580,17 @@ static int parse_hunk_body( !git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -"); git_parse_advance_line(&ctx->parse_ctx)) { + int old_lineno, new_lineno, origin, prefix = 1; char c; - int origin; - int prefix = 1; - int old_lineno = hunk->hunk.old_start + (hunk->hunk.old_lines - oldlines); - int new_lineno = hunk->hunk.new_start + (hunk->hunk.new_lines - newlines); + + if (git__add_int_overflow(&old_lineno, hunk->hunk.old_start, hunk->hunk.old_lines) || + git__sub_int_overflow(&old_lineno, old_lineno, oldlines) || + git__add_int_overflow(&new_lineno, hunk->hunk.new_start, hunk->hunk.new_lines) || + git__sub_int_overflow(&new_lineno, new_lineno, newlines)) { + error = git_parse_err("unrepresentable line count at line %"PRIuZ, + ctx->parse_ctx.line_num); + goto done; + } if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') { error = git_parse_err("invalid patch instruction at line %"PRIuZ, @@ -628,6 +650,7 @@ static int parse_hunk_body( line->content_len = ctx->parse_ctx.line_len - prefix; line->content = git__strndup(ctx->parse_ctx.line + prefix, line->content_len); + GIT_ERROR_CHECK_ALLOC(line->content); line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len; line->origin = origin; line->num_lines = 1; @@ -667,8 +690,9 @@ static int parse_hunk_body( memset(line, 0x0, sizeof(git_diff_line)); - line->content = git__strdup(ctx->parse_ctx.line); line->content_len = ctx->parse_ctx.line_len; + line->content = git__strndup(ctx->parse_ctx.line, line->content_len); + GIT_ERROR_CHECK_ALLOC(line->content); line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len; line->origin = eof_for_origin(last_origin); line->num_lines = 1; diff --git a/src/refdb_fs.c b/src/refdb_fs.c index c48afb94f..77b72dc2a 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -13,6 +13,7 @@ #include "futils.h" #include "filebuf.h" #include "pack.h" +#include "parse.h" #include "reflog.h" #include "refdb.h" #include "iterator.h" @@ -1651,70 +1652,57 @@ static int reflog_alloc(git_reflog **reflog, const char *name) static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) { - const char *ptr; - git_reflog_entry *entry; - -#define seek_forward(_increase) do { \ - if (_increase >= buf_size) { \ - git_error_set(GIT_ERROR_INVALID, "ran out of data while parsing reflog"); \ - goto fail; \ - } \ - buf += _increase; \ - buf_size -= _increase; \ - } while (0) - - while (buf_size > GIT_REFLOG_SIZE_MIN) { - entry = git__calloc(1, sizeof(git_reflog_entry)); - GIT_ERROR_CHECK_ALLOC(entry); + git_parse_ctx parser = GIT_PARSE_CTX_INIT; - entry->committer = git__calloc(1, sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(entry->committer); + if ((git_parse_ctx_init(&parser, buf, buf_size)) < 0) + return -1; - if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0) - goto fail; - seek_forward(GIT_OID_HEXSZ + 1); + for (; parser.remain_len; git_parse_advance_line(&parser)) { + git_reflog_entry *entry; + const char *sig; + char c; - if (git_oid_fromstrn(&entry->oid_cur, buf, GIT_OID_HEXSZ) < 0) - goto fail; - seek_forward(GIT_OID_HEXSZ + 1); + entry = git__calloc(1, sizeof(*entry)); + GIT_ERROR_CHECK_ALLOC(entry); + entry->committer = git__calloc(1, sizeof(*entry->committer)); + GIT_ERROR_CHECK_ALLOC(entry->committer); - ptr = buf; + if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 || + git_parse_advance_expected(&parser, " ", 1) < 0 || + git_parse_advance_oid(&entry->oid_cur, &parser) < 0) + goto next; - /* Seek forward to the end of the signature. */ - while (*buf && *buf != '\t' && *buf != '\n') - seek_forward(1); + sig = parser.line; + while (git_parse_peek(&c, &parser, 0) == 0 && c != '\t' && c != '\n') + git_parse_advance_chars(&parser, 1); - if (git_signature__parse(entry->committer, &ptr, buf + 1, NULL, *buf) < 0) - goto fail; + if (git_signature__parse(entry->committer, &sig, parser.line, NULL, 0) < 0) + goto next; - if (*buf == '\t') { - /* We got a message. Read everything till we reach LF. */ - seek_forward(1); - ptr = buf; + if (c == '\t') { + size_t len; + git_parse_advance_chars(&parser, 1); - while (*buf && *buf != '\n') - seek_forward(1); + len = parser.line_len; + if (parser.line[len - 1] == '\n') + len--; - entry->msg = git__strndup(ptr, buf - ptr); + entry->msg = git__strndup(parser.line, len); GIT_ERROR_CHECK_ALLOC(entry->msg); - } else - entry->msg = NULL; + } - while (*buf && *buf == '\n' && buf_size > 1) - seek_forward(1); + if ((git_vector_insert(&log->entries, entry)) < 0) { + git_reflog_entry__free(entry); + return -1; + } - if (git_vector_insert(&log->entries, entry) < 0) - goto fail; + continue; + +next: + git_reflog_entry__free(entry); } return 0; - -#undef seek_forward - -fail: - git_reflog_entry__free(entry); - - return -1; } static int create_new_reflog_file(const char *filepath) @@ -1856,8 +1844,15 @@ static int serialize_reflog_entry( git_buf_rtrim(buf); if (msg) { + size_t i; + git_buf_putc(buf, '\t'); git_buf_puts(buf, msg); + + for (i = 0; i < buf->size - 2; i++) + if (buf->ptr[i] == '\n') + buf->ptr[i] = ' '; + git_buf_rtrim(buf); } git_buf_putc(buf, '\n'); diff --git a/src/reflog.c b/src/reflog.c index 1834a2736..24dada047 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -74,9 +74,8 @@ int git_reflog_write(git_reflog *reflog) int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg) { - git_reflog_entry *entry; const git_reflog_entry *previous; - const char *newline; + git_reflog_entry *entry; assert(reflog && new_oid && committer); @@ -87,19 +86,18 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_sign goto cleanup; if (msg != NULL) { - if ((entry->msg = git__strdup(msg)) == NULL) - goto cleanup; + size_t i, msglen = strlen(msg); - newline = strchr(msg, '\n'); - - if (newline) { - if (newline[1] != '\0') { - git_error_set(GIT_ERROR_INVALID, "reflog message cannot contain newline"); - goto cleanup; - } + if ((entry->msg = git__strndup(msg, msglen)) == NULL) + goto cleanup; - entry->msg[newline - msg] = '\0'; - } + /* + * Replace all newlines with spaces, except for + * the final trailing newline. + */ + for (i = 0; i < msglen; i++) + if (entry->msg[i] == '\n') + entry->msg[i] = ' '; } previous = git_reflog_entry_byindex(reflog, 0); diff --git a/src/stash.c b/src/stash.c index aa3cecf6e..4a13d0530 100644 --- a/src/stash.c +++ b/src/stash.c @@ -437,36 +437,33 @@ cleanup: return error; } -static int prepare_worktree_commit_message( - git_buf* msg, - const char *user_message) +static int prepare_worktree_commit_message(git_buf *out, const char *user_message) { git_buf buf = GIT_BUF_INIT; - int error; - - if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0) - return error; - - git_buf_clear(msg); + int error = 0; - if (!user_message) - git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf)); - else { + if (!user_message) { + git_buf_printf(&buf, "WIP on %s", git_buf_cstr(out)); + } else { const char *colon; - if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL) + if ((colon = strchr(git_buf_cstr(out), ':')) == NULL) goto cleanup; - git_buf_puts(msg, "On "); - git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr); - git_buf_printf(msg, ": %s\n", user_message); + git_buf_puts(&buf, "On "); + git_buf_put(&buf, git_buf_cstr(out), colon - out->ptr); + git_buf_printf(&buf, ": %s\n", user_message); + } + + if (git_buf_oom(&buf)) { + error = -1; + goto cleanup; } - error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0; + git_buf_swap(out, &buf); cleanup: git_buf_dispose(&buf); - return error; } @@ -497,10 +494,7 @@ static int is_dirty_cb(const char *path, unsigned int status, void *payload) return GIT_PASSTHROUGH; } -static int ensure_there_are_changes_to_stash( - git_repository *repo, - bool include_untracked_files, - bool include_ignored_files) +static int ensure_there_are_changes_to_stash(git_repository *repo, uint32_t flags) { int error; git_status_options opts = GIT_STATUS_OPTIONS_INIT; @@ -508,11 +502,11 @@ static int ensure_there_are_changes_to_stash( opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES; - if (include_untracked_files) + if (flags & GIT_STASH_INCLUDE_UNTRACKED) opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; - if (include_ignored_files) + if (flags & GIT_STASH_INCLUDE_IGNORED) opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS; @@ -527,20 +521,14 @@ static int ensure_there_are_changes_to_stash( return error; } -static int reset_index_and_workdir( - git_repository *repo, - git_commit *commit, - bool remove_untracked, - bool remove_ignored) +static int reset_index_and_workdir(git_repository *repo, git_commit *commit, uint32_t flags) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; opts.checkout_strategy = GIT_CHECKOUT_FORCE; - - if (remove_untracked) + if (flags & GIT_STASH_INCLUDE_UNTRACKED) opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED; - - if (remove_ignored) + if (flags & GIT_STASH_INCLUDE_IGNORED) opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED; return git_checkout_tree(repo, (git_object *)commit, &opts); @@ -566,31 +554,26 @@ int git_stash_save( if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0) goto cleanup; - if ((error = ensure_there_are_changes_to_stash( - repo, - (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0, - (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0) + if ((error = ensure_there_are_changes_to_stash(repo, flags)) < 0) goto cleanup; if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; - if ((error = commit_index( - &i_commit, repo, index, stasher, git_buf_cstr(&msg), b_commit)) < 0) + if ((error = commit_index(&i_commit, repo, index, stasher, + git_buf_cstr(&msg), b_commit)) < 0) goto cleanup; if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) && - (error = commit_untracked( - &u_commit, repo, stasher, git_buf_cstr(&msg), - i_commit, flags)) < 0) + (error = commit_untracked(&u_commit, repo, stasher, + git_buf_cstr(&msg), i_commit, flags)) < 0) goto cleanup; if ((error = prepare_worktree_commit_message(&msg, message)) < 0) goto cleanup; - if ((error = commit_worktree( - out, repo, stasher, git_buf_cstr(&msg), - i_commit, b_commit, u_commit)) < 0) + if ((error = commit_worktree(out, repo, stasher, git_buf_cstr(&msg), + i_commit, b_commit, u_commit)) < 0) goto cleanup; git_buf_rtrim(&msg); @@ -598,11 +581,8 @@ int git_stash_save( if ((error = update_reflog(out, repo, git_buf_cstr(&msg))) < 0) goto cleanup; - if ((error = reset_index_and_workdir( - repo, - ((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit, - (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0, - (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0) + if ((error = reset_index_and_workdir(repo, (flags & GIT_STASH_KEEP_INDEX) ? i_commit : b_commit, + flags)) < 0) goto cleanup; cleanup: diff --git a/tests/commit/write.c b/tests/commit/write.c index d829c973d..2c2278546 100644 --- a/tests/commit/write.c +++ b/tests/commit/write.c @@ -299,19 +299,43 @@ void test_commit_write__can_validate_objects(void) cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); } -void test_commit_write__attach_singleline_signature(void) +void test_commit_write__attach_signature_checks_objects(void) { const char *sig = "magic word: pretty please"; + const char *badtree = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ +parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ +author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +\n\ +a simple commit which does not work\n"; - const char *data = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ + const char *badparent = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\ parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ \n\ +a simple commit which does not work\n"; + + git_oid id; + + cl_git_fail_with(-1, git_commit_create_with_signature(&id, g_repo, badtree, sig, "magicsig")); + cl_git_fail_with(-1, git_commit_create_with_signature(&id, g_repo, badparent, sig, "magicsig")); + +} + +void test_commit_write__attach_singleline_signature(void) +{ + const char *sig = "magic word: pretty please"; + + const char *data = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\ +parent 8496071c1b46c854b31185ea97743be6a8774479\n\ +author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +\n\ a simple commit which works\n"; - const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ -parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ + const char *complete = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\ +parent 8496071c1b46c854b31185ea97743be6a8774479\n\ author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ magicsig magic word: pretty please\n\ @@ -352,15 +376,15 @@ cpxtDQQMGYFpXK/71stq\n\ =ozeK\n\ -----END PGP SIGNATURE-----"; - const char *data = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ -parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ + const char *data = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\ +parent 8496071c1b46c854b31185ea97743be6a8774479\n\ author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ \n\ a simple commit which works\n"; -const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ -parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ +const char *complete = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\ +parent 8496071c1b46c854b31185ea97743be6a8774479\n\ author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ gpgsig -----BEGIN PGP SIGNATURE-----\n\ diff --git a/tests/config/snapshot.c b/tests/config/snapshot.c index 61562d206..5cc08a721 100644 --- a/tests/config/snapshot.c +++ b/tests/config/snapshot.c @@ -1,5 +1,7 @@ #include "clar_libgit2.h" +#include "config_backend.h" + static git_config *cfg; static git_config *snapshot; @@ -100,3 +102,38 @@ void test_config_snapshot__includes(void) cl_git_pass(p_unlink("including")); cl_git_pass(p_unlink("included")); } + +void test_config_snapshot__snapshot(void) +{ + git_config *snapshot_snapshot; + int i; + + cl_git_mkfile("configfile", "[section]\nkey = 1\n"); + + cl_git_pass(git_config_open_ondisk(&cfg, "configfile")); + cl_git_pass(git_config_snapshot(&snapshot, cfg)); + + cl_git_pass(git_config_snapshot(&snapshot_snapshot, snapshot)); + + cl_git_pass(git_config_get_int32(&i, snapshot_snapshot, "section.key")); + cl_assert_equal_i(i, 1); + + git_config_free(snapshot_snapshot); + + cl_git_pass(p_unlink("configfile")); +} + +void test_config_snapshot__snapshot_from_in_memony(void) +{ + const char *configuration = "[section]\nkey = 1\n"; + git_config_backend *backend; + int i; + + cl_git_pass(git_config_new(&cfg)); + cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration))); + cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0)); + + cl_git_pass(git_config_snapshot(&snapshot, cfg)); + cl_git_pass(git_config_get_int32(&i, snapshot, "section.key")); + cl_assert_equal_i(i, 1); +} diff --git a/tests/patch/parse.c b/tests/patch/parse.c index b89322ff3..c18b63ab7 100644 --- a/tests/patch/parse.c +++ b/tests/patch/parse.c @@ -148,3 +148,50 @@ void test_patch_parse__lifetime_of_patch_does_not_depend_on_buffer(void) git_patch_free(patch); } + +void test_patch_parse__binary_file_with_missing_paths(void) +{ + git_patch *patch; + cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_MISSING_PATHS, + strlen(PATCH_BINARY_FILE_WITH_MISSING_PATHS), NULL)); +} + +void test_patch_parse__binary_file_with_whitespace_paths(void) +{ + git_patch *patch; + cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS, + strlen(PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS), NULL)); +} + +void test_patch_parse__binary_file_with_empty_quoted_paths(void) +{ + git_patch *patch; + cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS, + strlen(PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS), NULL)); +} + +void test_patch_parse__memory_leak_on_multiple_paths(void) +{ + git_patch *patch; + cl_git_fail(git_patch_from_buffer(&patch, PATCH_MULTIPLE_OLD_PATHS, strlen(PATCH_MULTIPLE_OLD_PATHS), NULL)); +} + +void test_patch_parse__truncated_no_newline_at_end_of_file(void) +{ + size_t len = strlen(PATCH_APPEND_NO_NL) - strlen("at end of file\n"); + const git_diff_line *line; + git_patch *patch; + + cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL, len, NULL)); + cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 4)); + cl_assert_equal_s(line->content, "\\ No newline "); + + git_patch_free(patch); +} + +void test_patch_parse__line_number_overflow(void) +{ + git_patch *patch; + cl_git_fail(git_patch_from_buffer(&patch, PATCH_INTMAX_NEW_LINES, strlen(PATCH_INTMAX_NEW_LINES), NULL)); + git_patch_free(patch); +} diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h index d730d142c..4f2141dbe 100644 --- a/tests/patch/patch_common.h +++ b/tests/patch/patch_common.h @@ -905,3 +905,36 @@ "-b\n" \ "+bb\n" \ " c\n" + +#define PATCH_BINARY_FILE_WITH_MISSING_PATHS \ + "diff --git \n" \ + "--- \n" \ + "+++ \n" \ + "Binary files " + +#define PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS \ + "diff --git a/file b/file\n" \ + "--- \n" \ + "+++ \n" \ + "Binary files " + +#define PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS \ + "diff --git a/file b/file\n" \ + "--- \"\"\n" \ + "+++ \"\"\n" \ + "Binary files " + +#define PATCH_MULTIPLE_OLD_PATHS \ + "diff --git \n" \ + "--- \n" \ + "+++ \n" \ + "index 0000..7DDb\n" \ + "--- \n" + +#define PATCH_INTMAX_NEW_LINES \ + "diff --git a/file b/file\n" \ + "--- a/file\n" \ + "+++ b/file\n" \ + "@@ -0 +2147483647 @@\n" \ + "\n" \ + " " diff --git a/tests/refs/reflog/messages.c b/tests/refs/reflog/messages.c index f8acd23d2..43f59a84b 100644 --- a/tests/refs/reflog/messages.c +++ b/tests/refs/reflog/messages.c @@ -281,6 +281,27 @@ void test_refs_reflog_messages__creating_a_direct_reference(void) git_reference_free(reference); } +void test_refs_reflog_messages__newline_gets_replaced(void) +{ + const git_reflog_entry *entry; + git_signature *signature; + git_reflog *reflog; + git_oid oid; + + cl_git_pass(git_signature_now(&signature, "me", "foo@example.com")); + cl_git_pass(git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); + + cl_git_pass(git_reflog_read(&reflog, g_repo, "HEAD")); + cl_assert_equal_sz(7, git_reflog_entrycount(reflog)); + cl_git_pass(git_reflog_append(reflog, &oid, signature, "inner\nnewline")); + cl_assert_equal_sz(8, git_reflog_entrycount(reflog)); + + cl_assert(entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_s(git_reflog_entry_message(entry), "inner newline"); + + git_signature_free(signature); + git_reflog_free(reflog); +} void test_refs_reflog_messages__renaming_ref(void) { diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c index 7e4b1ef4a..5cefc3227 100644 --- a/tests/refs/reflog/reflog.c +++ b/tests/refs/reflog/reflog.c @@ -87,15 +87,13 @@ void test_refs_reflog_reflog__append_then_read(void) cl_git_pass(git_signature_now(&committer, "foo", "foo@bar")); cl_git_pass(git_reflog_read(&reflog, g_repo, new_ref)); - - cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline")); cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL)); cl_git_pass(git_reflog_append(reflog, &oid, committer, commit_msg "\n")); cl_git_pass(git_reflog_write(reflog)); - git_reflog_free(reflog); assert_appends(committer, &oid); + git_reflog_free(reflog); git_signature_free(committer); } @@ -224,45 +222,45 @@ void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_re git_buf_dispose(&subtrees_log_path); } -void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error(void) +void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_succeeds(void) { git_reflog *reflog; - const git_error *error; const char *refname = "refs/heads/newline"; const char *refmessage = "Reflog*message with a newline and enough content after it to pass the GIT_REFLOG_SIZE_MIN check inside reflog_parse."; + const git_reflog_entry *entry; git_reference *ref; git_oid id; git_buf logpath = GIT_BUF_INIT, logcontents = GIT_BUF_INIT; char *star; - git_oid_fromstr(&id, current_master_tip); - - /* create a new branch */ + /* Create a new branch. */ + cl_git_pass(git_oid_fromstr(&id, current_master_tip)); cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage)); - /* corrupt the branch reflog by introducing a newline inside the reflog message (we replace '*' with '\n') */ - git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname); + /* + * Corrupt the branch reflog by introducing a newline inside the reflog message. + * We do this by replacing '*' with '\n' + */ + cl_git_pass(git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname)); cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath))); cl_assert((star = strchr(git_buf_cstr(&logcontents), '*')) != NULL); *star = '\n'; cl_git_rewritefile(git_buf_cstr(&logpath), git_buf_cstr(&logcontents)); - /* confirm that the file was rewritten successfully and now contains a '\n' in the expected location */ + /* + * Confirm that the file was rewritten successfully + * and now contains a '\n' in the expected location + */ cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath))); cl_assert(strstr(git_buf_cstr(&logcontents), "Reflog\nmessage") != NULL); - /* clear the error state so we can capture the error generated by git_reflog_read */ - git_error_clear(); - - cl_git_fail(git_reflog_read(&reflog, g_repo, refname)); - - error = git_error_last(); - - cl_assert(error != NULL); - cl_assert_equal_s("unable to parse OID - contains invalid characters", error->message); + cl_git_pass(git_reflog_read(&reflog, g_repo, refname)); + cl_assert(entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_s(git_reflog_entry_message(entry), "Reflog"); git_reference_free(ref); + git_reflog_free(reflog); git_buf_dispose(&logpath); git_buf_dispose(&logcontents); } diff --git a/tests/stash/save.c b/tests/stash/save.c index 362c704ea..d568567d5 100644 --- a/tests/stash/save.c +++ b/tests/stash/save.c @@ -283,6 +283,26 @@ void test_stash_save__stashing_updates_the_reflog(void) assert_object_oid("refs/stash@{1}", NULL, GIT_OBJECT_COMMIT); } +void test_stash_save__multiline_message(void) +{ + const char *msg = "This\n\nis a multiline message\n"; + const git_reflog_entry *entry; + git_reflog *reflog; + + assert_object_oid("refs/stash@{0}", NULL, GIT_OBJECT_COMMIT); + + cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, msg, GIT_STASH_DEFAULT)); + + cl_git_pass(git_reflog_read(&reflog, repo, "refs/stash")); + cl_assert(entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_s(git_reflog_entry_message(entry), "On master: This is a multiline message"); + + assert_object_oid("refs/stash@{0}", git_oid_tostr_s(&stash_tip_oid), GIT_OBJECT_COMMIT); + assert_commit_message_contains("refs/stash@{0}", msg); + + git_reflog_free(reflog); +} + void test_stash_save__cannot_stash_when_there_are_no_local_change(void) { git_index *index; |