summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commit.c27
-rw-r--r--src/config_file.c155
-rw-r--r--src/config_mem.c10
-rw-r--r--src/config_snapshot.c45
-rw-r--r--src/diff_generate.c2
-rw-r--r--src/futils.c1
-rw-r--r--src/integer.h28
-rw-r--r--src/parse.c10
-rw-r--r--src/parse.h1
-rw-r--r--src/patch_parse.c54
-rw-r--r--src/refdb_fs.c93
-rw-r--r--src/reflog.c24
-rw-r--r--src/stash.c80
-rw-r--r--tests/commit/write.c40
-rw-r--r--tests/config/snapshot.c37
-rw-r--r--tests/patch/parse.c47
-rw-r--r--tests/patch/patch_common.h33
-rw-r--r--tests/refs/reflog/messages.c21
-rw-r--r--tests/refs/reflog/reflog.c38
-rw-r--r--tests/stash/save.c20
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;