summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md4
-rw-r--r--include/git2/remote.h48
-rw-r--r--include/git2/repository.h2
-rw-r--r--include/git2/transport.h8
-rw-r--r--include/git2/tree.h3
-rw-r--r--src/config_file.c2
-rw-r--r--src/fetch.c2
-rw-r--r--src/filebuf.c22
-rw-r--r--src/filebuf.h15
-rw-r--r--src/index.c2
-rw-r--r--src/odb_loose.c2
-rw-r--r--src/protocol.c50
-rw-r--r--src/protocol.h23
-rw-r--r--src/reflog.c2
-rw-r--r--src/refs.c4
-rw-r--r--src/refspec.c9
-rw-r--r--src/refspec.h5
-rw-r--r--src/remote.c76
-rw-r--r--src/transport.c36
-rw-r--r--src/transports/git.c45
-rw-r--r--src/transports/http.c53
-rw-r--r--tests-clay/buf/basic.c29
-rw-r--r--tests-clay/clay.h5
-rw-r--r--tests-clay/clay_libgit2.h2
-rw-r--r--tests-clay/clay_main.c21
-rw-r--r--tests-clay/config/stress.c2
-rw-r--r--tests-clay/core/filebuf.c54
-rw-r--r--tests-clay/index/rename.c2
-rw-r--r--tests/t00-core.c6
-rw-r--r--tests/t06-index.c2
-rw-r--r--tests/t15-config.c2
33 files changed, 389 insertions, 152 deletions
diff --git a/.gitignore b/.gitignore
index 87ba3f34f..6594f1478 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ msvc/Release/
CMake*
*.cmake
.DS_Store
+*~
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7655e0ba5..5505a96ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,7 +64,7 @@ IF (MSVC)
SET(CMAKE_C_FLAGS_RELEASE "/MT /O2")
SET(WIN_RC "src/win32/git2.rc")
ELSE ()
- SET(CMAKE_C_FLAGS "-O2 -g -Wall -Wextra -Wstrict-aliasing=2 -Wstrict-prototypes -Wmissing-prototypes ${CMAKE_C_FLAGS}")
+ SET(CMAKE_C_FLAGS "-O2 -g -Wall -Wextra -Wno-missing-field-initializers -Wstrict-aliasing=2 -Wstrict-prototypes -Wmissing-prototypes ${CMAKE_C_FLAGS}")
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
IF (NOT MINGW) # MinGW always does PIC and complains if we tell it to
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
diff --git a/README.md b/README.md
index 6ba9e6407..ed2bcb304 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ What It Can Do
libgit2 is already very usable.
* SHA conversions, formatting and shortening
-* abstracked ODB backend system
+* abstracted ODB backend system
* commit, tag, tree and blob parsing, editing, and write-back
* tree traversal
* revision walking
@@ -85,7 +85,7 @@ Here are the bindings to libgit2 that are currently available:
* node-gitteh (Node.js bindings) <https://github.com/libgit2/node-gitteh>
* nodegit (Node.js bindings) <https://github.com/tbranyen/nodegit>
* go-git (Go bindings) <https://github.com/str1ngs/go-git>
-* libqgit2 (C++ QT bindings) <https://projects.kde.org/projects/playground/libs/libqgit2/>
+* libqgit2 (C++ Qt bindings) <https://projects.kde.org/projects/playground/libs/libqgit2/>
* libgit2-ocaml (ocaml bindings) <https://github.com/burdges/libgit2-ocaml>
* Geef (Erlang bindings) <https://github.com/schacon/geef>
* libgit2net (.NET bindings, low level) <https://github.com/txdv/libgit2net>
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 54116c22e..43bbe9e1c 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -28,16 +28,18 @@ GIT_BEGIN_DECL
*/
/**
- * Create a new unnamed remote
+ * Create a remote in memory
*
- * Useful when you don't want to store the remote
+ * Create a remote with the default refspecs in memory. You can use
+ * this when you have a URL instead of a remote's name.
*
* @param out pointer to the new remote object
* @param repo the associtated repository
* @param url the remote repository's URL
+ * @param name the remote's name
* @return GIT_SUCCESS or an error code
*/
-int git_remote_new(git_remote **out, git_repository *repo, const char *url);
+int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name);
/**
* Get the information for a particular remote
@@ -98,7 +100,8 @@ GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction);
/**
* Get a list of refs at the remote
*
- * The remote (or more exactly its transport) must be connected.
+ * The remote (or more exactly its transport) must be connected. The
+ * memory belongs to the remote.
*
* @param refs where to store the refs
* @param remote the remote
@@ -107,20 +110,13 @@ GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction);
GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headarray *refs);
/**
- * Negotiate what data needs to be exchanged to synchroize the remtoe
- * and local references
- *
- * @param remote the remote you want to negotiate with
- */
-GIT_EXTERN(int) git_remote_negotiate(git_remote *remote);
-
-/**
* Download the packfile
*
- * The packfile is downloaded with a temporary filename, as it's final
- * name is not known yet. If there was no packfile needed (all the
- * objects were available locally), filename will be NULL and the
- * function will return success.
+ * Negotiate what objects should be downloaded and download the
+ * packfile with those objects. The packfile is downloaded with a
+ * temporary filename, as it's final name is not known yet. If there
+ * was no packfile needed (all the objects were available locally),
+ * filename will be NULL and the function will return success.
*
* @param remote the remote to download from
* @param filename where to store the temproray filename
@@ -129,6 +125,26 @@ GIT_EXTERN(int) git_remote_negotiate(git_remote *remote);
GIT_EXTERN(int) git_remote_download(char **filename, git_remote *remote);
/**
+ * Check whether the remote is connected
+ *
+ * Check whether the remote's underlying transport is connected to the
+ * remote host.
+ *
+ * @return 1 if it's connected, 0 otherwise.
+ */
+GIT_EXTERN(int) git_remote_connected(git_remote *remote);
+
+/**
+ * Disconnect from the remote
+ *
+ * Close the connection to the remote and free the underlying
+ * transport.
+ *
+ * @param remote the remote to disconnect from
+ */
+GIT_EXTERN(void) git_remote_disconnect(git_remote *remote);
+
+/**
* Free the memory associated with a remote
*
* @param remote the remote to free
diff --git a/include/git2/repository.h b/include/git2/repository.h
index 161826b26..2e9baf6c0 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -277,7 +277,7 @@ GIT_EXTERN(const char *) git_repository_path(git_repository *repo, git_repositor
* Check if a repository is bare
*
* @param repo Repo to test
- * @return 1 if the repository is empty, 0 otherwise.
+ * @return 1 if the repository is bare, 0 otherwise.
*/
GIT_EXTERN(int) git_repository_is_bare(git_repository *repo);
diff --git a/include/git2/transport.h b/include/git2/transport.h
index ddae32d40..f56a2f40a 100644
--- a/include/git2/transport.h
+++ b/include/git2/transport.h
@@ -27,6 +27,14 @@ GIT_BEGIN_DECL
*/
GIT_EXTERN(int) git_transport_new(git_transport **transport, const char *url);
+/**
+ * Return whether a string is a valid transport URL
+ *
+ * @param tranport the url to check
+ * @param 1 if the url is valid, 0 otherwise
+ */
+GIT_EXTERN(int) git_transport_valid_url(const char *url);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/tree.h b/include/git2/tree.h
index bd89de34f..8ac8b1682 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -308,9 +308,10 @@ enum git_treewalk_mode {
* @param tree The tree to walk
* @param callback Function to call on each tree entry
* @param mode Traversal mode (pre or post-order)
+ * @param payload Opaque pointer to be passed on each callback
* @return GIT_SUCCESS or an error code
*/
-GIT_EXTERN(int) git_tree_walk(git_tree *walk, git_treewalk_cb callback, int mode, void *payload);
+GIT_EXTERN(int) git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload);
/** @} */
GIT_END_DECL
diff --git a/src/config_file.c b/src/config_file.c
index aec29d4e2..87a430759 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -877,7 +877,7 @@ static int config_write(diskfile_backend *cfg, cvar_t *var)
int section_matches = 0, last_section_matched = 0;
char *current_section = NULL;
char *var_name, *var_value, *data_start;
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
const char *pre_end = NULL, *post_start = NULL;
/* We need to read in our own config file */
diff --git a/src/fetch.c b/src/fetch.c
index af7dbaffd..a42732925 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -138,7 +138,7 @@ int git_fetch_download_pack(char **out, git_remote *remote)
int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_size,
GIT_SOCKET fd, git_repository *repo)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
int error;
char buff[1024], path[GIT_PATH_MAX];
static const char suff[] = "/objects/pack/pack-received";
diff --git a/src/filebuf.c b/src/filebuf.c
index 199418032..6600bfa4b 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -66,13 +66,22 @@ void git_filebuf_cleanup(git_filebuf *file)
if (file->digest)
git_hash_free_ctx(file->digest);
- git__free(file->buffer);
- git__free(file->z_buf);
+ if (file->buffer)
+ git__free(file->buffer);
- deflateEnd(&file->zs);
+ /* use the presence of z_buf to decide if we need to deflateEnd */
+ if (file->z_buf) {
+ git__free(file->z_buf);
+ deflateEnd(&file->zs);
+ }
- git__free(file->path_original);
- git__free(file->path_lock);
+ if (file->path_original)
+ git__free(file->path_original);
+ if (file->path_lock)
+ git__free(file->path_lock);
+
+ memset(file, 0x0, sizeof(git_filebuf));
+ file->fd = -1;
}
GIT_INLINE(int) flush_buffer(git_filebuf *file)
@@ -137,6 +146,9 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
assert(file && path);
+ if (file->buffer)
+ return git__throw(GIT_EINVALIDARGS, "Tried to reopen an open filebuf");
+
memset(file, 0x0, sizeof(git_filebuf));
file->buf_size = WRITE_BUFFER_SIZE;
diff --git a/src/filebuf.h b/src/filebuf.h
index d08505e8d..6c283bc5c 100644
--- a/src/filebuf.h
+++ b/src/filebuf.h
@@ -44,6 +44,21 @@ struct git_filebuf {
typedef struct git_filebuf git_filebuf;
+#define GIT_FILEBUF_INIT {0}
+
+/* The git_filebuf object lifecycle is:
+ * - Allocate git_filebuf, preferably using GIT_FILEBUF_INIT.
+ * - Call git_filebuf_open() to initialize the filebuf for use.
+ * - Make as many calls to git_filebuf_write(), git_filebuf_printf(),
+ * git_filebuf_reserve() as you like.
+ * - While you are writing, you may call git_filebuf_hash() to get
+ * the hash of all you have written so far.
+ * - To close the git_filebuf, you may call git_filebuf_commit() or
+ * git_filebuf_commit_at() to save the file, or
+ * git_filebuf_cleanup() to abandon the file. All of these will
+ * clear the git_filebuf object.
+ */
+
int git_filebuf_write(git_filebuf *lock, const void *buff, size_t len);
int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);
int git_filebuf_printf(git_filebuf *file, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
diff --git a/src/index.c b/src/index.c
index 1a9745a2c..aad117164 100644
--- a/src/index.c
+++ b/src/index.c
@@ -248,7 +248,7 @@ int git_index_read(git_index *index)
int git_index_write(git_index *index)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
struct stat indexst;
int error;
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 57a0b0a8e..f1789e071 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -769,7 +769,7 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v
{
int error, header_len;
char final_path[GIT_PATH_MAX], header[64];
- git_filebuf fbuf;
+ git_filebuf fbuf = GIT_FILEBUF_INIT;
loose_backend *backend;
backend = (loose_backend *)_backend;
diff --git a/src/protocol.c b/src/protocol.c
new file mode 100644
index 000000000..1f39f105b
--- /dev/null
+++ b/src/protocol.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#include "common.h"
+#include "protocol.h"
+#include "pkt.h"
+#include "buffer.h"
+
+int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
+{
+ git_buf *buf = &p->buf;
+ git_vector *refs = p->refs;
+ int error;
+ const char *line_end, *ptr;
+
+ if (len == 0) { /* EOF */
+ if (buf->size != 0)
+ return p->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
+ else
+ return 0;
+ }
+
+ git_buf_put(buf, data, len);
+ ptr = buf->ptr;
+ while (1) {
+ git_pkt *pkt;
+
+ if (buf->size == 0)
+ return 0;
+
+ error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
+ if (error == GIT_ESHORTBUFFER)
+ return 0; /* Ask for more */
+ if (error < GIT_SUCCESS)
+ return p->error = git__rethrow(error, "Failed to parse pkt-line");
+
+ git_buf_consume(buf, line_end);
+ error = git_vector_insert(refs, pkt);
+ if (error < GIT_SUCCESS)
+ return p->error = git__rethrow(error, "Failed to add pkt to list");
+
+ if (pkt->type == GIT_PKT_FLUSH)
+ p->flush = 1;
+ }
+
+ return error;
+}
diff --git a/src/protocol.h b/src/protocol.h
new file mode 100644
index 000000000..e3315738a
--- /dev/null
+++ b/src/protocol.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_protocol_h__
+#define INCLUDE_protocol_h__
+
+#include "transport.h"
+#include "buffer.h"
+
+typedef struct {
+ git_transport *transport;
+ git_vector *refs;
+ git_buf buf;
+ int error;
+ unsigned int flush :1;
+} git_protocol;
+
+int git_protocol_store_refs(git_protocol *p, const char *data, size_t len);
+
+#endif
diff --git a/src/reflog.c b/src/reflog.c
index f52ae585f..fbaaaea67 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -41,7 +41,7 @@ static int reflog_write(const char *log_path, const char *oid_old,
{
int error;
git_buf log = GIT_BUF_INIT;
- git_filebuf fbuf;
+ git_filebuf fbuf = GIT_FILEBUF_INIT;
assert(log_path && oid_old && oid_new && committer);
diff --git a/src/refs.c b/src/refs.c
index dfdde080f..2374cc72f 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -286,7 +286,7 @@ cleanup:
static int loose_write(git_reference *ref)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
char ref_path[GIT_PATH_MAX];
int error;
struct stat st;
@@ -745,7 +745,7 @@ static int packed_sort(const void *a, const void *b)
*/
static int packed_write(git_repository *repo)
{
- git_filebuf pack_file;
+ git_filebuf pack_file = GIT_FILEBUF_INIT;
int error;
unsigned int i;
char pack_file_path[GIT_PATH_MAX];
diff --git a/src/refspec.c b/src/refspec.c
index e60e8f5b5..62683e7b7 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -23,8 +23,13 @@ int git_refspec_parse(git_refspec *refspec, const char *str)
}
delim = strchr(str, ':');
- if (delim == NULL)
- return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'");
+ if (delim == NULL) {
+ refspec->src = git__strdup(str);
+ if (refspec->src == NULL)
+ return GIT_ENOMEM;
+
+ return GIT_SUCCESS;
+ }
refspec->src = git__strndup(str, delim - str);
if (refspec->src == NULL)
diff --git a/src/refspec.h b/src/refspec.h
index 58f3fe472..7c389719b 100644
--- a/src/refspec.h
+++ b/src/refspec.h
@@ -10,9 +10,12 @@
#include "git2/refspec.h"
struct git_refspec {
- int force;
+ struct git_refspec *next;
char *src;
char *dst;
+ unsigned int force :1,
+ pattern :1,
+ matching :1;
};
int git_refspec_parse(struct git_refspec *refspec, const char *str);
diff --git a/src/remote.c b/src/remote.c
index 3ff08a21e..a222023d8 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -56,22 +56,34 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha
return refspec_parse(refspec, val);
}
-int git_remote_new(git_remote **out, git_repository *repo, const char *url)
+int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)
{
git_remote *remote;
+ /* name is optional */
+ assert(out && repo && url);
+
remote = git__malloc(sizeof(git_remote));
if (remote == NULL)
return GIT_ENOMEM;
memset(remote, 0x0, sizeof(git_remote));
remote->repo = repo;
+
remote->url = git__strdup(url);
if (remote->url == NULL) {
git__free(remote);
return GIT_ENOMEM;
}
+ if (name != NULL) {
+ remote->name = git__strdup(name);
+ if (remote->name == NULL) {
+ git__free(remote);
+ return GIT_ENOMEM;
+ }
+ }
+
*out = remote;
return GIT_SUCCESS;
}
@@ -83,6 +95,8 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name)
const char *val;
int ret, error, buf_len;
+ assert(out && cfg && name);
+
remote = git__malloc(sizeof(git_remote));
if (remote == NULL)
return GIT_ENOMEM;
@@ -157,23 +171,27 @@ cleanup:
return error;
}
-const char *git_remote_name(struct git_remote *remote)
+const char *git_remote_name(git_remote *remote)
{
+ assert(remote);
return remote->name;
}
-const char *git_remote_url(struct git_remote *remote)
+const char *git_remote_url(git_remote *remote)
{
+ assert(remote);
return remote->url;
}
-const git_refspec *git_remote_fetchspec(struct git_remote *remote)
+const git_refspec *git_remote_fetchspec(git_remote *remote)
{
+ assert(remote);
return &remote->fetch;
}
-const git_refspec *git_remote_pushspec(struct git_remote *remote)
+const git_refspec *git_remote_pushspec(git_remote *remote)
{
+ assert(remote);
return &remote->push;
}
@@ -182,6 +200,8 @@ int git_remote_connect(git_remote *remote, int direction)
int error;
git_transport *t;
+ assert(remote);
+
error = git_transport_new(&t, remote->url);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to create transport");
@@ -203,20 +223,23 @@ cleanup:
int git_remote_ls(git_remote *remote, git_headarray *refs)
{
+ assert(remote && refs);
return remote->transport->ls(remote->transport, refs);
}
-int git_remote_negotiate(git_remote *remote)
-{
- return git_fetch_negotiate(remote);
-}
-
int git_remote_download(char **filename, git_remote *remote)
{
+ int error;
+
+ assert(filename && remote);
+
+ if ((error = git_fetch_negotiate(remote)) < 0)
+ return git__rethrow(error, "Error negotiating");
+
return git_fetch_download_pack(filename, remote);
}
-int git_remote_update_tips(struct git_remote *remote)
+int git_remote_update_tips(git_remote *remote)
{
int error = GIT_SUCCESS;
unsigned int i = 0;
@@ -226,6 +249,8 @@ int git_remote_update_tips(struct git_remote *remote)
git_reference *ref;
struct git_refspec *spec = &remote->fetch;
+ assert(remote);
+
memset(refname, 0x0, sizeof(refname));
if (refs->len == 0)
@@ -236,6 +261,7 @@ int git_remote_update_tips(struct git_remote *remote)
if (!strcmp(head->name, GIT_HEAD_FILE)) {
error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1);
i = 1;
+ git_reference_free(ref);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to update FETCH_HEAD");
}
@@ -250,11 +276,32 @@ int git_remote_update_tips(struct git_remote *remote)
error = git_reference_create_oid(&ref, remote->repo, refname, &head->oid, 1);
if (error < GIT_SUCCESS)
return error;
+
+ git_reference_free(ref);
}
return GIT_SUCCESS;
}
+int git_remote_connected(git_remote *remote)
+{
+ assert(remote);
+ return remote->transport == NULL ? 0 : remote->transport->connected;
+}
+
+void git_remote_disconnect(git_remote *remote)
+{
+ assert(remote);
+
+ if (remote->transport != NULL) {
+ if (remote->transport->connected)
+ remote->transport->close(remote->transport);
+
+ remote->transport->free(remote->transport);
+ remote->transport = NULL;
+ }
+}
+
void git_remote_free(git_remote *remote)
{
if (remote == NULL)
@@ -266,11 +313,6 @@ void git_remote_free(git_remote *remote)
git__free(remote->push.dst);
git__free(remote->url);
git__free(remote->name);
- if (remote->transport != NULL) {
- if (remote->transport->connected)
- remote->transport->close(remote->transport);
-
- remote->transport->free(remote->transport);
- }
+ git_remote_disconnect(remote);
git__free(remote);
}
diff --git a/src/transport.c b/src/transport.c
index 8d69db53e..0d67e1967 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -10,7 +10,7 @@
#include "git2/net.h"
#include "transport.h"
-struct {
+static struct {
char *prefix;
git_transport_cb fn;
} transports[] = {
@@ -23,26 +23,20 @@ struct {
{NULL, 0}
};
-static git_transport_cb transport_new_fn(const char *url)
+#define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0]))
+
+static git_transport_cb transport_find_fn(const char *url)
{
- int i = 0;
+ size_t i = 0;
- while (1) {
- if (transports[i].prefix == NULL)
- break;
+ /* TODO: Parse "example.com:project.git" as an SSH URL */
+ for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
if (!strncasecmp(url, transports[i].prefix, strlen(transports[i].prefix)))
return transports[i].fn;
-
- ++i;
}
- /*
- * If we still haven't found the transport, we assume we mean a
- * local file.
- * TODO: Parse "example.com:project.git" as an SSH URL
- */
- return git_transport_local;
+ return NULL;
}
/**************
@@ -55,13 +49,25 @@ int git_transport_dummy(git_transport **GIT_UNUSED(transport))
return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry");
}
+int git_transport_valid_url(const char *url)
+{
+ return transport_find_fn(url) != NULL;
+}
+
int git_transport_new(git_transport **out, const char *url)
{
git_transport_cb fn;
git_transport *transport;
int error;
- fn = transport_new_fn(url);
+ fn = transport_find_fn(url);
+
+ /*
+ * If we haven't found the transport, we assume we mean a
+ * local file.
+ */
+ if (fn == NULL)
+ fn = &git_transport_local;
error = fn(&transport);
if (error < GIT_SUCCESS)
diff --git a/src/transports/git.c b/src/transports/git.c
index c2014529b..2ee2e4831 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -20,9 +20,11 @@
#include "filebuf.h"
#include "repository.h"
#include "fetch.h"
+#include "protocol.h"
typedef struct {
git_transport parent;
+ git_protocol proto;
GIT_SOCKET socket;
git_vector refs;
git_remote_head **heads;
@@ -126,11 +128,7 @@ static int do_connect(transport_git *t, const char *url)
static int store_refs(transport_git *t)
{
gitno_buffer *buf = &t->buf;
- git_vector *refs = &t->refs;
int error = GIT_SUCCESS;
- const char *line_end, *ptr;
- git_pkt *pkt;
-
while (1) {
error = gitno_recv(buf);
@@ -139,34 +137,20 @@ static int store_refs(transport_git *t)
if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */
return GIT_SUCCESS;
- ptr = buf->data;
- while (1) {
- if (buf->offset == 0)
- break;
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- /*
- * If the error is GIT_ESHORTBUFFER, it means the buffer
- * isn't long enough to satisfy the request. Break out and
- * wait for more input.
- * On any other error, fail.
- */
- if (error == GIT_ESHORTBUFFER) {
- break;
- }
- if (error < GIT_SUCCESS) {
- return error;
- }
-
- /* Get rid of the part we've used already */
- gitno_consume(buf, line_end);
+ error = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
+ if (error == GIT_ESHORTBUFFER) {
+ gitno_consume_n(buf, buf->len);
+ continue;
+ }
- error = git_vector_insert(refs, pkt);
- if (error < GIT_SUCCESS)
- return error;
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to store refs");
- if (pkt->type == GIT_PKT_FLUSH)
- return GIT_SUCCESS;
+ gitno_consume_n(buf, buf->offset);
+ if (t->proto.flush) { /* No more refs */
+ t->proto.flush = 0;
+ return GIT_SUCCESS;
}
}
@@ -476,6 +460,7 @@ static void git_free(git_transport *transport)
git_vector_free(refs);
git__free(t->heads);
+ git_buf_free(&t->proto.buf);
git__free(t->parent.url);
git__free(t);
}
@@ -501,6 +486,8 @@ int git_transport_git(git_transport **out)
t->parent.download_pack = git_download_pack;
t->parent.close = git_close;
t->parent.free = git_free;
+ t->proto.refs = &t->refs;
+ t->proto.transport = (git_transport *) t;
*out = (git_transport *) t;
diff --git a/src/transports/http.c b/src/transports/http.c
index 66b6f252c..ae0c56a73 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -19,6 +19,7 @@
#include "fetch.h"
#include "filebuf.h"
#include "repository.h"
+#include "protocol.h"
enum last_cb {
NONE,
@@ -28,6 +29,7 @@ enum last_cb {
typedef struct {
git_transport parent;
+ git_protocol proto;
git_vector refs;
git_vector common;
int socket;
@@ -186,47 +188,8 @@ static int on_headers_complete(http_parser *parser)
static int on_body_store_refs(http_parser *parser, const char *str, size_t len)
{
transport_http *t = (transport_http *) parser->data;
- git_buf *buf = &t->buf;
- git_vector *refs = &t->refs;
- int error;
- const char *line_end, *ptr;
- static int first_pkt = 1;
-
- if (len == 0) { /* EOF */
- if (buf->size != 0)
- return t->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
- else
- return 0;
- }
-
- git_buf_put(buf, str, len);
- ptr = buf->ptr;
- while (1) {
- git_pkt *pkt;
-
- if (buf->size == 0)
- return 0;
-
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
- if (error == GIT_ESHORTBUFFER)
- return 0; /* Ask for more */
- if (error < GIT_SUCCESS)
- return t->error = git__rethrow(error, "Failed to parse pkt-line");
-
- git_buf_consume(buf, line_end);
- if (first_pkt) {
- first_pkt = 0;
- if (pkt->type != GIT_PKT_COMMENT)
- return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
- }
-
- error = git_vector_insert(refs, pkt);
- if (error < GIT_SUCCESS)
- return t->error = git__rethrow(error, "Failed to add pkt to list");
- }
-
- return error;
+ return git_protocol_store_refs(&t->proto, str, len);
}
static int on_message_complete(http_parser *parser)
@@ -243,6 +206,7 @@ static int store_refs(transport_http *t)
http_parser_settings settings;
char buffer[1024];
gitno_buffer buf;
+ git_pkt *pkt;
http_parser_init(&t->parser, HTTP_RESPONSE);
t->parser.data = t;
@@ -273,6 +237,12 @@ static int store_refs(transport_http *t)
return GIT_SUCCESS;
}
+ pkt = git_vector_get(&t->refs, 0);
+ if (pkt == NULL || pkt->type != GIT_PKT_COMMENT)
+ return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
+ else
+ git_vector_remove(&t->refs, 0);
+
return error;
}
@@ -750,6 +720,7 @@ static void http_free(git_transport *transport)
}
git_vector_free(common);
git_buf_free(&t->buf);
+ git_buf_free(&t->proto.buf);
git__free(t->heads);
git__free(t->content_type);
git__free(t->host);
@@ -775,6 +746,8 @@ int git_transport_http(git_transport **out)
t->parent.download_pack = http_download_pack;
t->parent.close = http_close;
t->parent.free = http_free;
+ t->proto.refs = &t->refs;
+ t->proto.transport = (git_transport *) t;
#ifdef GIT_WIN32
/* on win32, the WSA context needs to be initialized
diff --git a/tests-clay/buf/basic.c b/tests-clay/buf/basic.c
new file mode 100644
index 000000000..860564d13
--- /dev/null
+++ b/tests-clay/buf/basic.c
@@ -0,0 +1,29 @@
+#include "clay_libgit2.h"
+#include "buffer.h"
+
+static const char *test_string = "Have you seen that? Have you seeeen that??";
+
+void test_buf_basic__resize(void)
+{
+ git_buf buf1 = GIT_BUF_INIT;
+ git_buf_puts(&buf1, test_string);
+ cl_assert(git_buf_oom(&buf1) == 0);
+ cl_assert(strcmp(git_buf_cstr(&buf1), test_string) == 0);
+
+ git_buf_puts(&buf1, test_string);
+ cl_assert(strlen(git_buf_cstr(&buf1)) == strlen(test_string) * 2);
+ git_buf_free(&buf1);
+}
+
+void test_buf_basic__printf(void)
+{
+ git_buf buf2 = GIT_BUF_INIT;
+ git_buf_printf(&buf2, "%s %s %d ", "shoop", "da", 23);
+ cl_assert(git_buf_oom(&buf2) == 0);
+ cl_assert(strcmp(git_buf_cstr(&buf2), "shoop da 23 ") == 0);
+
+ git_buf_printf(&buf2, "%s %d", "woop", 42);
+ cl_assert(git_buf_oom(&buf2) == 0);
+ cl_assert(strcmp(git_buf_cstr(&buf2), "shoop da 23 woop 42") == 0);
+ git_buf_free(&buf2);
+} \ No newline at end of file
diff --git a/tests-clay/clay.h b/tests-clay/clay.h
index db3a475b2..812209be1 100644
--- a/tests-clay/clay.h
+++ b/tests-clay/clay.h
@@ -57,6 +57,8 @@ void cl_fixture_cleanup(const char *fixture_name);
/**
* Test method declarations
*/
+extern void test_buf_basic__printf(void);
+extern void test_buf_basic__resize(void);
extern void test_config_stress__cleanup(void);
extern void test_config_stress__dont_break_on_invalid_input(void);
extern void test_config_stress__initialize(void);
@@ -68,6 +70,9 @@ extern void test_core_dirent__traverse_weird_filenames(void);
extern void test_core_filebuf__0(void);
extern void test_core_filebuf__1(void);
extern void test_core_filebuf__2(void);
+extern void test_core_filebuf__3(void);
+extern void test_core_filebuf__4(void);
+extern void test_core_filebuf__5(void);
extern void test_core_oid__initialize(void);
extern void test_core_oid__streq(void);
extern void test_core_path__0(void);
diff --git a/tests-clay/clay_libgit2.h b/tests-clay/clay_libgit2.h
index a5208962e..8784b7e61 100644
--- a/tests-clay/clay_libgit2.h
+++ b/tests-clay/clay_libgit2.h
@@ -16,7 +16,7 @@
git_clearerror(); \
if ((expr) != GIT_SUCCESS) \
clay__assert(0, __FILE__, __LINE__, "Function call failed: " #expr, git_lasterror(), 1); \
- } while(0);
+ } while(0)
/**
* Wrapper for `clay_must_fail` -- this one is
diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c
index 4ad6fc467..6d964b1ba 100644
--- a/tests-clay/clay_main.c
+++ b/tests-clay/clay_main.c
@@ -104,6 +104,10 @@ static void clay_unsandbox(void);
static int clay_sandbox(void);
/* Autogenerated test data by clay */
+static const struct clay_func _clay_cb_buf_basic[] = {
+ {"printf", &test_buf_basic__printf},
+ {"resize", &test_buf_basic__resize}
+};
static const struct clay_func _clay_cb_config_stress[] = {
{"dont_break_on_invalid_input", &test_config_stress__dont_break_on_invalid_input}
};
@@ -117,7 +121,10 @@ static const struct clay_func _clay_cb_core_dirent[] = {
static const struct clay_func _clay_cb_core_filebuf[] = {
{"0", &test_core_filebuf__0},
{"1", &test_core_filebuf__1},
- {"2", &test_core_filebuf__2}
+ {"2", &test_core_filebuf__2},
+ {"3", &test_core_filebuf__3},
+ {"4", &test_core_filebuf__4},
+ {"5", &test_core_filebuf__5}
};
static const struct clay_func _clay_cb_core_oid[] = {
{"streq", &test_core_oid__streq}
@@ -216,6 +223,12 @@ static const struct clay_func _clay_cb_status_worktree[] = {
static const struct clay_suite _clay_suites[] = {
{
+ "buf::basic",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clay_cb_buf_basic, 2
+ },
+ {
"config::stress",
{"initialize", &test_config_stress__initialize},
{"cleanup", &test_config_stress__cleanup},
@@ -231,7 +244,7 @@ static const struct clay_suite _clay_suites[] = {
"core::filebuf",
{NULL, NULL},
{NULL, NULL},
- _clay_cb_core_filebuf, 3
+ _clay_cb_core_filebuf, 6
},
{
"core::oid",
@@ -349,8 +362,8 @@ static const struct clay_suite _clay_suites[] = {
}
};
-static size_t _clay_suite_count = 22;
-static size_t _clay_callback_count = 65;
+static size_t _clay_suite_count = 23;
+static size_t _clay_callback_count = 70;
/* Core test functions */
static void
diff --git a/tests-clay/config/stress.c b/tests-clay/config/stress.c
index 7b81400c1..832321556 100644
--- a/tests-clay/config/stress.c
+++ b/tests-clay/config/stress.c
@@ -8,7 +8,7 @@
void test_config_stress__initialize(void)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
git_filebuf_open(&file, TEST_CONFIG, 0);
diff --git a/tests-clay/core/filebuf.c b/tests-clay/core/filebuf.c
index e1ecb2798..5b233fe8e 100644
--- a/tests-clay/core/filebuf.c
+++ b/tests-clay/core/filebuf.c
@@ -4,7 +4,7 @@
/* make sure git_filebuf_open doesn't delete an existing lock */
void test_core_filebuf__0(void)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
int fd;
char test[] = "test", testlock[] = "test.lock";
@@ -23,7 +23,7 @@ void test_core_filebuf__0(void)
/* make sure GIT_FILEBUF_APPEND works as expected */
void test_core_filebuf__1(void)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
int fd;
char test[] = "test";
@@ -43,7 +43,7 @@ void test_core_filebuf__1(void)
/* make sure git_filebuf_write writes large buffer correctly */
void test_core_filebuf__2(void)
{
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
char test[] = "test";
unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */
@@ -56,3 +56,51 @@ void test_core_filebuf__2(void)
cl_must_pass(p_unlink(test));
}
+
+/* make sure git_filebuf_open won't reopen an open buffer */
+void test_core_filebuf__3(void)
+{
+ git_filebuf file = GIT_FILEBUF_INIT;
+ char test[] = "test";
+
+ cl_git_pass(git_filebuf_open(&file, test, 0));
+ cl_git_fail(git_filebuf_open(&file, test, 0));
+
+ git_filebuf_cleanup(&file);
+}
+
+
+/* make sure git_filebuf_cleanup clears the buffer */
+void test_core_filebuf__4(void)
+{
+ git_filebuf file = GIT_FILEBUF_INIT;
+ char test[] = "test";
+
+ cl_assert(file.buffer == NULL);
+
+ cl_git_pass(git_filebuf_open(&file, test, 0));
+ cl_assert(file.buffer != NULL);
+
+ git_filebuf_cleanup(&file);
+ cl_assert(file.buffer == NULL);
+}
+
+
+/* make sure git_filebuf_commit clears the buffer */
+void test_core_filebuf__5(void)
+{
+ git_filebuf file = GIT_FILEBUF_INIT;
+ char test[] = "test";
+
+ cl_assert(file.buffer == NULL);
+
+ cl_git_pass(git_filebuf_open(&file, test, 0));
+ cl_assert(file.buffer != NULL);
+ cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
+ cl_assert(file.buffer != NULL);
+
+ cl_git_pass(git_filebuf_commit(&file, 0666));
+ cl_assert(file.buffer == NULL);
+
+ cl_must_pass(p_unlink(test));
+}
diff --git a/tests-clay/index/rename.c b/tests-clay/index/rename.c
index ba72b62f7..f81125434 100644
--- a/tests-clay/index/rename.c
+++ b/tests-clay/index/rename.c
@@ -8,7 +8,7 @@ static void file_create(const char *filename, const char *content)
fd = p_creat(filename, 0666);
cl_assert(fd != 0);
cl_git_pass(p_write(fd, content, strlen(content)));
- cl_git_pass(p_close(fd))
+ cl_git_pass(p_close(fd));
}
void test_index_rename__single_file(void)
diff --git a/tests/t00-core.c b/tests/t00-core.c
index 94824b438..16a5c6f93 100644
--- a/tests/t00-core.c
+++ b/tests/t00-core.c
@@ -462,7 +462,7 @@ BEGIN_TEST(dirent4, "make sure that strange looking filenames ('..c') are traver
END_TEST
BEGIN_TEST(filebuf0, "make sure git_filebuf_open doesn't delete an existing lock")
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
int fd;
char test[] = "test", testlock[] = "test.lock";
@@ -475,7 +475,7 @@ BEGIN_TEST(filebuf0, "make sure git_filebuf_open doesn't delete an existing lock
END_TEST
BEGIN_TEST(filebuf1, "make sure GIT_FILEBUF_APPEND works as expected")
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
int fd;
char test[] = "test";
@@ -492,7 +492,7 @@ BEGIN_TEST(filebuf1, "make sure GIT_FILEBUF_APPEND works as expected")
END_TEST
BEGIN_TEST(filebuf2, "make sure git_filebuf_write writes large buffer correctly")
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
char test[] = "test";
unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */
diff --git a/tests/t06-index.c b/tests/t06-index.c
index 44562d004..7b0f05129 100644
--- a/tests/t06-index.c
+++ b/tests/t06-index.c
@@ -163,7 +163,7 @@ END_TEST
BEGIN_TEST(add0, "add a new file to the index")
git_index *index;
- git_filebuf file;
+ git_filebuf file = GIT_FILEBUF_INIT;
git_repository *repo;
git_index_entry *entry;
git_oid id1;
diff --git a/tests/t15-config.c b/tests/t15-config.c
index a97f82067..9f0deb3e3 100644
--- a/tests/t15-config.c
+++ b/tests/t15-config.c
@@ -306,7 +306,7 @@ END_TEST
BEGIN_TEST(config16, "add a variable in a new section")
git_config *cfg;
int32_t i;
- git_filebuf buf;
+ git_filebuf buf = GIT_FILEBUF_INIT;
/* By freeing the config, we make sure we flush the values */
must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config10"));