Unverified Commit 80742e15 by Edward Thomson Committed by GitHub

Merge pull request #6456 from libgit2/ethomson/sha256_experimental

SHA256: more SHA256 support
parents f7963f28 e3cd8591
...@@ -232,7 +232,7 @@ jobs: ...@@ -232,7 +232,7 @@ jobs:
env: env:
CC: clang CC: clang
CMAKE_GENERATOR: Ninja CMAKE_GENERATOR: Ninja
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON
os: ubuntu-latest os: ubuntu-latest
- name: "macOS (SHA256)" - name: "macOS (SHA256)"
id: macos id: macos
......
...@@ -265,10 +265,40 @@ jobs: ...@@ -265,10 +265,40 @@ jobs:
RUN_INVASIVE_TESTS: true RUN_INVASIVE_TESTS: true
SKIP_PROXY_TESTS: true SKIP_PROXY_TESTS: true
os: ubuntu-latest os: ubuntu-latest
# Experimental: SHA256 support
- name: "Linux (SHA256, Xenial, Clang, OpenSSL)"
id: xenial-clang-openssl
container:
name: xenial
env:
CC: clang
CMAKE_GENERATOR: Ninja
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
os: ubuntu-latest
- name: "macOS (SHA256)"
id: macos
os: macos-10.15
env:
CC: clang
CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON
PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
SKIP_SSH_TESTS: true
SKIP_NEGOTIATE_TESTS: true
setup-script: osx
- name: "Windows (SHA256, amd64, Visual Studio)"
id: windows-amd64-vs
os: windows-2019
env:
ARCH: amd64
CMAKE_GENERATOR: Visual Studio 16 2019
CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON
SKIP_SSH_TESTS: true
SKIP_NEGOTIATE_TESTS: true
fail-fast: false fail-fast: false
name: "Build ${{ matrix.platform.name }}"
env: ${{ matrix.platform.env }} env: ${{ matrix.platform.env }}
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }}
name: "Build ${{ matrix.platform.name }}"
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@v3 uses: actions/checkout@v3
......
...@@ -7,11 +7,13 @@ RUN apt-get update && \ ...@@ -7,11 +7,13 @@ RUN apt-get update && \
clang \ clang \
cmake \ cmake \
curl \ curl \
gettext \
gcc \ gcc \
git \
krb5-user \ krb5-user \
libcurl4-gnutls-dev \ libcurl4-gnutls-dev \
libexpat1-dev \
libgcrypt20-dev \ libgcrypt20-dev \
libintl-perl \
libkrb5-dev \ libkrb5-dev \
libpcre3-dev \ libpcre3-dev \
libssl-dev \ libssl-dev \
...@@ -28,7 +30,17 @@ RUN apt-get update && \ ...@@ -28,7 +30,17 @@ RUN apt-get update && \
&& \ && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
FROM apt AS mbedtls FROM apt AS git
RUN cd /tmp && \
curl --location --silent --show-error https://github.com/git/git/archive/refs/tags/v2.39.1.tar.gz | \
tar -xz && \
cd git-2.39.1 && \
make && \
make prefix=/usr install && \
cd .. && \
rm -rf git-2.39.1
FROM git AS mbedtls
RUN cd /tmp && \ RUN cd /tmp && \
curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.16.2.tar.gz | \ curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.16.2.tar.gz | \
tar -xz && \ tar -xz && \
......
...@@ -37,6 +37,11 @@ cleanup() { ...@@ -37,6 +37,11 @@ cleanup() {
kill $GIT_NAMESPACE_PID kill $GIT_NAMESPACE_PID
fi fi
if [ ! -z "$GIT_SHA256_PID" ]; then
echo "Stopping git daemon (sha256)..."
kill $GIT_SHA256_PID
fi
if [ ! -z "$PROXY_BASIC_PID" ]; then if [ ! -z "$PROXY_BASIC_PID" ]; then
echo "Stopping proxy (Basic)..." echo "Stopping proxy (Basic)..."
kill $PROXY_BASIC_PID kill $PROXY_BASIC_PID
...@@ -145,6 +150,12 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then ...@@ -145,6 +150,12 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
cp -R "${SOURCE_DIR}/tests/resources/namespace.git" "${GIT_NAMESPACE_DIR}/namespace.git" cp -R "${SOURCE_DIR}/tests/resources/namespace.git" "${GIT_NAMESPACE_DIR}/namespace.git"
GIT_NAMESPACE="name1" git daemon --listen=localhost --port=9419 --export-all --enable=receive-pack --base-path="${GIT_NAMESPACE_DIR}" "${GIT_NAMESPACE_DIR}" & GIT_NAMESPACE="name1" git daemon --listen=localhost --port=9419 --export-all --enable=receive-pack --base-path="${GIT_NAMESPACE_DIR}" "${GIT_NAMESPACE_DIR}" &
GIT_NAMESPACE_PID=$! GIT_NAMESPACE_PID=$!
echo "Starting git daemon (sha256)..."
GIT_SHA256_DIR=`mktemp -d ${TMPDIR}/git_sha256.XXXXXXXX`
cp -R "${SOURCE_DIR}/tests/resources/testrepo_256.git" "${GIT_SHA256_DIR}/testrepo_256.git"
git daemon --listen=localhost --port=9420 --export-all --enable=receive-pack --base-path="${GIT_SHA256_DIR}" "${GIT_SHA256_DIR}" &
GIT_SHA256_PID=$!
fi fi
if [ -z "$SKIP_PROXY_TESTS" ]; then if [ -z "$SKIP_PROXY_TESTS" ]; then
...@@ -291,6 +302,14 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then ...@@ -291,6 +302,14 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
run_test gitdaemon_namespace run_test gitdaemon_namespace
unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_URL
unset GITTEST_REMOTE_BRANCH unset GITTEST_REMOTE_BRANCH
echo ""
echo "Running gitdaemon (sha256) tests"
echo ""
export GITTEST_REMOTE_URL="git://localhost:9420/testrepo_256.git"
run_test gitdaemon_sha256
unset GITTEST_REMOTE_URL
fi fi
if [ -z "$SKIP_PROXY_TESTS" ]; then if [ -z "$SKIP_PROXY_TESTS" ]; then
......
...@@ -13,7 +13,7 @@ if(EXPERIMENTAL_SHA256) ...@@ -13,7 +13,7 @@ if(EXPERIMENTAL_SHA256)
set(EXPERIMENTAL 1) set(EXPERIMENTAL 1)
set(GIT_EXPERIMENTAL_SHA256 1) set(GIT_EXPERIMENTAL_SHA256 1)
add_compile_definitions(GIT_EXPERIMENTAL_SHA256) add_definitions(-DGIT_EXPERIMENTAL_SHA256=1)
else() else()
add_feature_info("SHA256 API" OFF "experimental SHA256 APIs") add_feature_info("SHA256 API" OFF "experimental SHA256 APIs")
endif() endif()
......
...@@ -28,11 +28,18 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv) ...@@ -28,11 +28,18 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (git_indexer_new(&idx, ".", 0, NULL, NULL) < 0) { #ifdef GIT_EXPERIMENTAL_SHA256
error = git_indexer_new(&idx, ".", git_repository_oid_type(repo), NULL);
#else
error = git_indexer_new(&idx, ".", 0, NULL, NULL);
#endif
if (error < 0) {
puts("bad idx"); puts("bad idx");
return -1; return -1;
} }
if ((fd = open(argv[1], 0)) < 0) { if ((fd = open(argv[1], 0)) < 0) {
perror("open"); perror("open");
return -1; return -1;
......
...@@ -39,7 +39,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ...@@ -39,7 +39,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
* to do. * to do.
*/ */
for (i = 0; i < ARRAY_SIZE(types); i++) { for (i = 0; i < ARRAY_SIZE(types); i++) {
if (git_object__from_raw(&object, (const char *) data, size, types[i]) < 0) if (git_object__from_raw(&object, (const char *) data, size, types[i], GIT_OID_SHA1) < 0)
continue; continue;
git_object_free(object); git_object_free(object);
object = NULL; object = NULL;
......
...@@ -67,6 +67,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ...@@ -67,6 +67,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
git_str path = GIT_STR_INIT; git_str path = GIT_STR_INIT;
git_oid oid; git_oid oid;
bool append_hash = false; bool append_hash = false;
int error;
if (size == 0) if (size == 0)
return 0; return 0;
...@@ -82,7 +83,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ...@@ -82,7 +83,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
abort(); abort();
} }
if (git_indexer_new(&indexer, ".", 0, odb, NULL) < 0) { #ifdef GIT_EXPERIMENTAL_SHA256
error = git_indexer_new(&indexer, ".", GIT_OID_SHA1, NULL);
#else
error = git_indexer_new(&indexer, ".", 0, odb, NULL);
#endif
if (error < 0) {
fprintf(stderr, "Failed to create the indexer: %s\n", fprintf(stderr, "Failed to create the indexer: %s\n",
git_error_last()->message); git_error_last()->message);
abort(); abort();
......
...@@ -62,6 +62,19 @@ typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *st ...@@ -62,6 +62,19 @@ typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *st
typedef struct git_indexer_options { typedef struct git_indexer_options {
unsigned int version; unsigned int version;
#ifdef GIT_EXPERIMENTAL_SHA256
/** permissions to use creating packfile or 0 for defaults */
unsigned int mode;
/**
* object database from which to read base objects when
* fixing thin packs. This can be NULL if there are no thin
* packs; if a thin pack is encountered, an error will be
* returned if there are bases missing.
*/
git_odb *odb;
#endif
/** progress_cb function to call with progress information */ /** progress_cb function to call with progress information */
git_indexer_progress_cb progress_cb; git_indexer_progress_cb progress_cb;
...@@ -87,6 +100,21 @@ GIT_EXTERN(int) git_indexer_options_init( ...@@ -87,6 +100,21 @@ GIT_EXTERN(int) git_indexer_options_init(
git_indexer_options *opts, git_indexer_options *opts,
unsigned int version); unsigned int version);
#ifdef GIT_EXPERIMENTAL_SHA256
/**
* Create a new indexer instance
*
* @param out where to store the indexer instance
* @param path to the directory where the packfile should be stored
* @param oid_type the oid type to use for objects
* @return 0 or an error code.
*/
GIT_EXTERN(int) git_indexer_new(
git_indexer **out,
const char *path,
git_oid_t oid_type,
git_indexer_options *opts);
#else
/** /**
* Create a new indexer instance * Create a new indexer instance
* *
...@@ -106,6 +134,7 @@ GIT_EXTERN(int) git_indexer_new( ...@@ -106,6 +134,7 @@ GIT_EXTERN(int) git_indexer_new(
unsigned int mode, unsigned int mode,
git_odb *odb, git_odb *odb,
git_indexer_options *opts); git_indexer_options *opts);
#endif
/** /**
* Add data to the indexer * Add data to the indexer
......
...@@ -225,6 +225,7 @@ GIT_EXTERN(int) git_object_peel( ...@@ -225,6 +225,7 @@ GIT_EXTERN(int) git_object_peel(
*/ */
GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source);
#ifdef GIT_EXPERIMENTAL_SHA256
/** /**
* Analyzes a buffer of raw object content and determines its validity. * Analyzes a buffer of raw object content and determines its validity.
* Tree, commit, and tag objects will be parsed and ensured that they * Tree, commit, and tag objects will be parsed and ensured that they
...@@ -238,14 +239,39 @@ GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); ...@@ -238,14 +239,39 @@ GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source);
* @param valid Output pointer to set with validity of the object content * @param valid Output pointer to set with validity of the object content
* @param buf The contents to validate * @param buf The contents to validate
* @param len The length of the buffer * @param len The length of the buffer
* @param type The type of the object in the buffer * @param object_type The type of the object in the buffer
* @param oid_type The object ID type for the OIDs in the given buffer
* @return 0 on success or an error code * @return 0 on success or an error code
*/ */
GIT_EXTERN(int) git_object_rawcontent_is_valid( GIT_EXTERN(int) git_object_rawcontent_is_valid(
int *valid, int *valid,
const char *buf, const char *buf,
size_t len, size_t len,
git_object_t type); git_object_t object_type,
git_oid_t oid_type);
#else
/**
* Analyzes a buffer of raw object content and determines its validity.
* Tree, commit, and tag objects will be parsed and ensured that they
* are valid, parseable content. (Blobs are always valid by definition.)
* An error message will be set with an informative message if the object
* is not valid.
*
* @warning This function is experimental and its signature may change in
* the future.
*
* @param valid Output pointer to set with validity of the object content
* @param buf The contents to validate
* @param len The length of the buffer
* @param object_type The type of the object in the buffer
* @return 0 on success or an error code
*/
GIT_EXTERN(int) git_object_rawcontent_is_valid(
int *valid,
const char *buf,
size_t len,
git_object_t object_type);
#endif
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -24,6 +24,26 @@ GIT_BEGIN_DECL ...@@ -24,6 +24,26 @@ GIT_BEGIN_DECL
* Constructors for in-box ODB backends. * Constructors for in-box ODB backends.
*/ */
/** Options for configuring a packfile object backend. */
typedef struct {
unsigned int version; /**< version for the struct */
/**
* Type of object IDs to use for this object database, or
* 0 for default (currently SHA1).
*/
git_oid_t oid_type;
} git_odb_backend_pack_options;
/* The current version of the diff options structure */
#define GIT_ODB_BACKEND_PACK_OPTIONS_VERSION 1
/* Stack initializer for odb pack backend options. Alternatively use
* `git_odb_backend_pack_options_init` programmatic initialization.
*/
#define GIT_ODB_BACKEND_PACK_OPTIONS_INIT \
{ GIT_ODB_BACKEND_PACK_OPTIONS_VERSION }
/** /**
* Create a backend for the packfiles. * Create a backend for the packfiles.
* *
...@@ -32,7 +52,38 @@ GIT_BEGIN_DECL ...@@ -32,7 +52,38 @@ GIT_BEGIN_DECL
* *
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); #ifdef GIT_EXPERIMENTAL_SHA256
GIT_EXTERN(int) git_odb_backend_pack(
git_odb_backend **out,
const char *objects_dir,
const git_odb_backend_pack_options *opts);
#else
GIT_EXTERN(int) git_odb_backend_pack(
git_odb_backend **out,
const char *objects_dir);
#endif
/**
* Create a backend out of a single packfile
*
* This can be useful for inspecting the contents of a single
* packfile.
*
* @param out location to store the odb backend pointer
* @param index_file path to the packfile's .idx file
*
* @return 0 or an error code
*/
#ifdef GIT_EXPERIMENTAL_SHA256
GIT_EXTERN(int) git_odb_backend_one_pack(
git_odb_backend **out,
const char *index_file,
const git_odb_backend_pack_options *opts);
#else
GIT_EXTERN(int) git_odb_backend_one_pack(
git_odb_backend **out,
const char *index_file);
#endif
typedef enum { typedef enum {
GIT_ODB_BACKEND_LOOSE_FSYNC = (1 << 0) GIT_ODB_BACKEND_LOOSE_FSYNC = (1 << 0)
...@@ -100,19 +151,6 @@ GIT_EXTERN(int) git_odb_backend_loose( ...@@ -100,19 +151,6 @@ GIT_EXTERN(int) git_odb_backend_loose(
unsigned int file_mode); unsigned int file_mode);
#endif #endif
/**
* Create a backend out of a single packfile
*
* This can be useful for inspecting the contents of a single
* packfile.
*
* @param out location to store the odb backend pointer
* @param index_file path to the packfile's .idx file
*
* @return 0 or an error code
*/
GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file);
/** Streaming mode */ /** Streaming mode */
typedef enum { typedef enum {
GIT_STREAM_RDONLY = (1 << 1), GIT_STREAM_RDONLY = (1 << 1),
......
...@@ -351,6 +351,15 @@ typedef struct { ...@@ -351,6 +351,15 @@ typedef struct {
* pointing to this URL. * pointing to this URL.
*/ */
const char *origin_url; const char *origin_url;
#ifdef GIT_EXPERIMENTAL_SHA256
/**
*
* Type of object IDs to use for this repository, or 0 for
* default (currently SHA1).
*/
git_oid_t oid_type;
#endif
} git_repository_init_options; } git_repository_init_options;
#define GIT_REPOSITORY_INIT_OPTIONS_VERSION 1 #define GIT_REPOSITORY_INIT_OPTIONS_VERSION 1
...@@ -949,6 +958,14 @@ GIT_EXTERN(int) git_repository_ident(const char **name, const char **email, cons ...@@ -949,6 +958,14 @@ GIT_EXTERN(int) git_repository_ident(const char **name, const char **email, cons
*/ */
GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, const char *email); GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, const char *email);
/**
* Gets the object type used by this repository.
*
* @param repo the repository
* @return the object id type
*/
GIT_EXTERN(git_oid_t) git_repository_oid_type(git_repository *repo);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -57,6 +57,18 @@ struct git_transport { ...@@ -57,6 +57,18 @@ struct git_transport {
unsigned int *capabilities, unsigned int *capabilities,
git_transport *transport); git_transport *transport);
#ifdef GIT_EXPERIMENTAL_SHA256
/**
* Gets the object type for the remote repository.
*
* This function may be called after a successful call to
* `connect()`.
*/
int GIT_CALLBACK(oid_type)(
git_oid_t *object_type,
git_transport *transport);
#endif
/** /**
* Get the list of available references in the remote repository. * Get the list of available references in the remote repository.
* *
......
...@@ -49,26 +49,37 @@ static void print_help(void) ...@@ -49,26 +49,37 @@ static void print_help(void)
cli_opt_help_fprint(stdout, opts); cli_opt_help_fprint(stdout, opts);
} }
static int hash_buf(git_odb *odb, git_str *buf, git_object_t type) static int hash_buf(
git_odb *odb,
git_str *buf,
git_object_t object_type,
git_oid_t oid_type)
{ {
git_oid oid; git_oid oid;
if (!literally) { if (!literally) {
int valid = 0; int valid = 0;
if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, type) < 0 || !valid) #ifdef GIT_EXPERIMENTAL_SHA256
if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, object_type, oid_type) < 0 || !valid)
return cli_error_git();
#else
GIT_UNUSED(oid_type);
if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, object_type) < 0 || !valid)
return cli_error_git(); return cli_error_git();
#endif
} }
if (write_object) { if (write_object) {
if (git_odb_write(&oid, odb, buf->ptr, buf->size, type) < 0) if (git_odb_write(&oid, odb, buf->ptr, buf->size, object_type) < 0)
return cli_error_git(); return cli_error_git();
} else { } else {
#ifdef GIT_EXPERIMENTAL_SHA256 #ifdef GIT_EXPERIMENTAL_SHA256
if (git_odb_hash(&oid, buf->ptr, buf->size, type, GIT_OID_SHA1) < 0) if (git_odb_hash(&oid, buf->ptr, buf->size, object_type, GIT_OID_SHA1) < 0)
return cli_error_git(); return cli_error_git();
#else #else
if (git_odb_hash(&oid, buf->ptr, buf->size, type) < 0) if (git_odb_hash(&oid, buf->ptr, buf->size, object_type) < 0)
return cli_error_git(); return cli_error_git();
#endif #endif
} }
...@@ -83,9 +94,10 @@ int cmd_hash_object(int argc, char **argv) ...@@ -83,9 +94,10 @@ int cmd_hash_object(int argc, char **argv)
{ {
git_repository *repo = NULL; git_repository *repo = NULL;
git_odb *odb = NULL; git_odb *odb = NULL;
git_oid_t oid_type;
git_str buf = GIT_STR_INIT; git_str buf = GIT_STR_INIT;
cli_opt invalid_opt; cli_opt invalid_opt;
git_object_t type = GIT_OBJECT_BLOB; git_object_t object_type = GIT_OBJECT_BLOB;
char **filename; char **filename;
int ret = 0; int ret = 0;
...@@ -97,7 +109,7 @@ int cmd_hash_object(int argc, char **argv) ...@@ -97,7 +109,7 @@ int cmd_hash_object(int argc, char **argv)
return 0; return 0;
} }
if (type_name && (type = git_object_string2type(type_name)) == GIT_OBJECT_INVALID) if (type_name && (object_type = git_object_string2type(type_name)) == GIT_OBJECT_INVALID)
return cli_error_usage("invalid object type '%s'", type_name); return cli_error_usage("invalid object type '%s'", type_name);
if (write_object && if (write_object &&
...@@ -107,6 +119,8 @@ int cmd_hash_object(int argc, char **argv) ...@@ -107,6 +119,8 @@ int cmd_hash_object(int argc, char **argv)
goto done; goto done;
} }
oid_type = git_repository_oid_type(repo);
/* /*
* TODO: we're reading blobs, we shouldn't pull them all into main * TODO: we're reading blobs, we shouldn't pull them all into main
* memory, we should just stream them into the odb instead. * memory, we should just stream them into the odb instead.
...@@ -118,7 +132,7 @@ int cmd_hash_object(int argc, char **argv) ...@@ -118,7 +132,7 @@ int cmd_hash_object(int argc, char **argv)
goto done; goto done;
} }
if ((ret = hash_buf(odb, &buf, type)) != 0) if ((ret = hash_buf(odb, &buf, object_type, oid_type)) != 0)
goto done; goto done;
} else { } else {
for (filename = filenames; *filename; filename++) { for (filename = filenames; *filename; filename++) {
...@@ -127,7 +141,7 @@ int cmd_hash_object(int argc, char **argv) ...@@ -127,7 +141,7 @@ int cmd_hash_object(int argc, char **argv)
goto done; goto done;
} }
if ((ret = hash_buf(odb, &buf, type)) != 0) if ((ret = hash_buf(odb, &buf, object_type, oid_type)) != 0)
goto done; goto done;
} }
} }
......
...@@ -52,11 +52,12 @@ void git_blob__free(void *_blob) ...@@ -52,11 +52,12 @@ void git_blob__free(void *_blob)
git__free(blob); git__free(blob);
} }
int git_blob__parse_raw(void *_blob, const char *data, size_t size) int git_blob__parse_raw(void *_blob, const char *data, size_t size, git_oid_t oid_type)
{ {
git_blob *blob = (git_blob *) _blob; git_blob *blob = (git_blob *) _blob;
GIT_ASSERT_ARG(blob); GIT_ASSERT_ARG(blob);
GIT_UNUSED(oid_type);
blob->raw = 1; blob->raw = 1;
blob->data.raw.data = data; blob->data.raw.data = data;
...@@ -64,11 +65,12 @@ int git_blob__parse_raw(void *_blob, const char *data, size_t size) ...@@ -64,11 +65,12 @@ int git_blob__parse_raw(void *_blob, const char *data, size_t size)
return 0; return 0;
} }
int git_blob__parse(void *_blob, git_odb_object *odb_obj) int git_blob__parse(void *_blob, git_odb_object *odb_obj, git_oid_t oid_type)
{ {
git_blob *blob = (git_blob *) _blob; git_blob *blob = (git_blob *) _blob;
GIT_ASSERT_ARG(blob); GIT_ASSERT_ARG(blob);
GIT_UNUSED(oid_type);
git_cached_obj_incref((git_cached_obj *)odb_obj); git_cached_obj_incref((git_cached_obj *)odb_obj);
blob->raw = 0; blob->raw = 0;
......
...@@ -36,8 +36,8 @@ struct git_blob { ...@@ -36,8 +36,8 @@ struct git_blob {
} while(0) } while(0)
void git_blob__free(void *blob); void git_blob__free(void *blob);
int git_blob__parse(void *blob, git_odb_object *obj); int git_blob__parse(void *blob, git_odb_object *obj, git_oid_t oid_type);
int git_blob__parse_raw(void *blob, const char *data, size_t size); int git_blob__parse_raw(void *blob, const char *data, size_t size, git_oid_t oid_type);
int git_blob__getbuf(git_str *buffer, git_blob *blob); int git_blob__getbuf(git_str *buffer, git_blob *blob);
extern int git_blob__create_from_paths( extern int git_blob__create_from_paths(
......
...@@ -393,12 +393,19 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c ...@@ -393,12 +393,19 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
return error; return error;
} }
static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch) static int clone_into(
git_repository *repo,
git_remote *_remote,
const git_fetch_options *opts,
const git_checkout_options *co_opts,
const char *branch)
{ {
int error; int error;
git_str reflog_message = GIT_STR_INIT; git_str reflog_message = GIT_STR_INIT;
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_fetch_options fetch_opts; git_fetch_options fetch_opts;
git_remote *remote; git_remote *remote;
git_oid_t oid_type;
GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(repo);
GIT_ASSERT_ARG(_remote); GIT_ASSERT_ARG(_remote);
...@@ -414,8 +421,25 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch ...@@ -414,8 +421,25 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
fetch_opts.update_fetchhead = 0; fetch_opts.update_fetchhead = 0;
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0)
return error;
git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
/*
* Connect to the server so that we can identify the remote
* object format.
*/
if ((error = git_remote_connect_ext(remote, GIT_DIRECTION_FETCH,
&connect_opts)) < 0)
goto cleanup;
if ((error = git_remote_oid_type(&oid_type, remote)) < 0 ||
(error = git_repository__set_objectformat(repo, oid_type)) < 0)
goto cleanup;
if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0)
goto cleanup; goto cleanup;
...@@ -423,6 +447,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch ...@@ -423,6 +447,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
cleanup: cleanup:
git_remote_free(remote); git_remote_free(remote);
git_remote_connect_options_dispose(&connect_opts);
git_str_dispose(&reflog_message); git_str_dispose(&reflog_message);
return error; return error;
......
...@@ -390,7 +390,11 @@ int git_commit_amend( ...@@ -390,7 +390,11 @@ int git_commit_amend(
return error; return error;
} }
static int commit_parse(git_commit *commit, const char *data, size_t size, unsigned int flags) static int commit_parse(
git_commit *commit,
const char *data,
size_t size,
git_commit__parse_options *opts)
{ {
const char *buffer_start = data, *buffer; const char *buffer_start = data, *buffer;
const char *buffer_end = buffer_start + size; const char *buffer_end = buffer_start + size;
...@@ -401,6 +405,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig ...@@ -401,6 +405,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
GIT_ASSERT_ARG(commit); GIT_ASSERT_ARG(commit);
GIT_ASSERT_ARG(data); GIT_ASSERT_ARG(data);
GIT_ASSERT_ARG(opts);
buffer = buffer_start; buffer = buffer_start;
...@@ -409,13 +414,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig ...@@ -409,13 +414,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
GIT_ERROR_CHECK_ARRAY(commit->parent_ids); GIT_ERROR_CHECK_ARRAY(commit->parent_ids);
/* The tree is always the first field */ /* The tree is always the first field */
if (!(flags & GIT_COMMIT_PARSE_QUICK)) { if (!(opts->flags & GIT_COMMIT_PARSE_QUICK)) {
if (git_object__parse_oid_header(&commit->tree_id, if (git_object__parse_oid_header(&commit->tree_id,
&buffer, buffer_end, "tree ", &buffer, buffer_end, "tree ",
GIT_OID_SHA1) < 0) opts->oid_type) < 0)
goto bad_buffer; goto bad_buffer;
} else { } else {
size_t tree_len = strlen("tree ") + GIT_OID_SHA1_HEXSIZE + 1; size_t tree_len = strlen("tree ") + git_oid_hexsize(opts->oid_type) + 1;
if (buffer + tree_len > buffer_end) if (buffer + tree_len > buffer_end)
goto bad_buffer; goto bad_buffer;
buffer += tree_len; buffer += tree_len;
...@@ -427,14 +433,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig ...@@ -427,14 +433,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
while (git_object__parse_oid_header(&parent_id, while (git_object__parse_oid_header(&parent_id,
&buffer, buffer_end, "parent ", &buffer, buffer_end, "parent ",
GIT_OID_SHA1) == 0) { opts->oid_type) == 0) {
git_oid *new_id = git_array_alloc(commit->parent_ids); git_oid *new_id = git_array_alloc(commit->parent_ids);
GIT_ERROR_CHECK_ALLOC(new_id); GIT_ERROR_CHECK_ALLOC(new_id);
git_oid_cpy(new_id, &parent_id); git_oid_cpy(new_id, &parent_id);
} }
if (!(flags & GIT_COMMIT_PARSE_QUICK)) { if (!opts || !(opts->flags & GIT_COMMIT_PARSE_QUICK)) {
commit->author = git__malloc(sizeof(git_signature)); commit->author = git__malloc(sizeof(git_signature));
GIT_ERROR_CHECK_ALLOC(commit->author); GIT_ERROR_CHECK_ALLOC(commit->author);
...@@ -458,7 +464,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig ...@@ -458,7 +464,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < 0) if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < 0)
return error; return error;
if (flags & GIT_COMMIT_PARSE_QUICK) if (opts && opts->flags & GIT_COMMIT_PARSE_QUICK)
return 0; return 0;
/* Parse add'l header entries */ /* Parse add'l header entries */
...@@ -503,19 +509,39 @@ bad_buffer: ...@@ -503,19 +509,39 @@ bad_buffer:
return GIT_EINVALID; return GIT_EINVALID;
} }
int git_commit__parse_raw(void *commit, const char *data, size_t size) int git_commit__parse(
void *commit,
git_odb_object *odb_obj,
git_oid_t oid_type)
{ {
return commit_parse(commit, data, size, 0); git_commit__parse_options parse_options = {0};
parse_options.oid_type = oid_type;
return git_commit__parse_ext(commit, odb_obj, &parse_options);
} }
int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) int git_commit__parse_raw(
void *commit,
const char *data,
size_t size,
git_oid_t oid_type)
{ {
return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags); git_commit__parse_options parse_options = {0};
parse_options.oid_type = oid_type;
return commit_parse(commit, data, size, &parse_options);
} }
int git_commit__parse(void *_commit, git_odb_object *odb_obj) int git_commit__parse_ext(
git_commit *commit,
git_odb_object *odb_obj,
git_commit__parse_options *parse_opts)
{ {
return git_commit__parse_ext(_commit, odb_obj, 0); return commit_parse(
commit,
git_odb_object_data(odb_obj),
git_odb_object_size(odb_obj),
parse_opts);
} }
#define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \ #define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \
...@@ -985,11 +1011,14 @@ int git_commit_create_with_signature( ...@@ -985,11 +1011,14 @@ int git_commit_create_with_signature(
git_str commit = GIT_STR_INIT; git_str commit = GIT_STR_INIT;
git_commit *parsed; git_commit *parsed;
git_array_oid_t parents = GIT_ARRAY_INIT; git_array_oid_t parents = GIT_ARRAY_INIT;
git_commit__parse_options parse_opts = {0};
parse_opts.oid_type = repo->oid_type;
/* The first step is to verify that all the tree and parents exist */ /* The first step is to verify that all the tree and parents exist */
parsed = git__calloc(1, sizeof(git_commit)); parsed = git__calloc(1, sizeof(git_commit));
GIT_ERROR_CHECK_ALLOC(parsed); GIT_ERROR_CHECK_ALLOC(parsed);
if (commit_parse(parsed, commit_content, strlen(commit_content), 0) < 0) { if (commit_parse(parsed, commit_content, strlen(commit_content), &parse_opts) < 0) {
error = -1; error = -1;
goto cleanup; goto cleanup;
} }
......
...@@ -33,6 +33,16 @@ struct git_commit { ...@@ -33,6 +33,16 @@ struct git_commit {
char *body; char *body;
}; };
typedef struct {
git_oid_t oid_type;
unsigned int flags;
} git_commit__parse_options;
typedef enum {
/** Only parse parents and committer info */
GIT_COMMIT_PARSE_QUICK = (1 << 0)
} git_commit__parse_flags;
int git_commit__header_field( int git_commit__header_field(
git_str *out, git_str *out,
const git_commit *commit, const git_commit *commit,
...@@ -56,14 +66,22 @@ int git_commit__create_buffer( ...@@ -56,14 +66,22 @@ int git_commit__create_buffer(
size_t parent_count, size_t parent_count,
const git_commit *parents[]); const git_commit *parents[]);
void git_commit__free(void *commit); int git_commit__parse(
int git_commit__parse(void *commit, git_odb_object *obj); void *commit,
int git_commit__parse_raw(void *commit, const char *data, size_t size); git_odb_object *obj,
git_oid_t oid_type);
typedef enum { int git_commit__parse_raw(
GIT_COMMIT_PARSE_QUICK = (1 << 0) /**< Only parse parents and committer info */ void *commit,
} git_commit__parse_flags; const char *data,
size_t size,
git_oid_t oid_type);
int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags); int git_commit__parse_ext(
git_commit *commit,
git_odb_object *odb_obj,
git_commit__parse_options *parse_opts);
void git_commit__free(void *commit);
#endif #endif
...@@ -538,7 +538,7 @@ int git_commit_graph_entry_find( ...@@ -538,7 +538,7 @@ int git_commit_graph_entry_find(
hi = ntohl(file->oid_fanout[(int)short_oid->id[0]]); hi = ntohl(file->oid_fanout[(int)short_oid->id[0]]);
lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(file->oid_fanout[(int)short_oid->id[0] - 1])); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(file->oid_fanout[(int)short_oid->id[0] - 1]));
pos = git_pack__lookup_sha1(file->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id); pos = git_pack__lookup_id(file->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id, GIT_OID_SHA1);
if (pos >= 0) { if (pos >= 0) {
/* An object matching exactly the oid was found */ /* An object matching exactly the oid was found */
...@@ -726,7 +726,8 @@ int git_commit_graph_writer_add_index_file( ...@@ -726,7 +726,8 @@ int git_commit_graph_writer_add_index_file(
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
error = git_mwindow_get_pack(&p, idx_path); /* TODO: SHA256 */
error = git_mwindow_get_pack(&p, idx_path, 0);
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
......
...@@ -124,13 +124,17 @@ static int commit_quick_parse( ...@@ -124,13 +124,17 @@ static int commit_quick_parse(
{ {
git_oid *parent_oid; git_oid *parent_oid;
git_commit *commit; git_commit *commit;
git_commit__parse_options parse_opts = {
GIT_OID_SHA1,
GIT_COMMIT_PARSE_QUICK
};
size_t i; size_t i;
commit = git__calloc(1, sizeof(*commit)); commit = git__calloc(1, sizeof(*commit));
GIT_ERROR_CHECK_ALLOC(commit); GIT_ERROR_CHECK_ALLOC(commit);
commit->object.repo = walk->repo; commit->object.repo = walk->repo;
if (git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK) < 0) { if (git_commit__parse_ext(commit, obj, &parse_opts) < 0) {
git__free(commit); git__free(commit);
return -1; return -1;
} }
......
...@@ -95,7 +95,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts) ...@@ -95,7 +95,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
git_remote_head **heads; git_remote_head **heads;
git_refspec tagspec, head, *spec; git_refspec tagspec, head, *spec;
int error = 0; int error = 0;
git_odb *odb;
size_t i, heads_len; size_t i, heads_len;
unsigned int remote_caps; unsigned int remote_caps;
unsigned int oid_mask = GIT_REMOTE_CAPABILITY_TIP_OID | unsigned int oid_mask = GIT_REMOTE_CAPABILITY_TIP_OID |
...@@ -126,9 +125,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts) ...@@ -126,9 +125,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
goto cleanup; goto cleanup;
} }
if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0)
goto cleanup;
if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 || if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 ||
(error = git_remote_capabilities(&remote_caps, remote)) < 0) (error = git_remote_capabilities(&remote_caps, remote)) < 0)
goto cleanup; goto cleanup;
......
...@@ -392,7 +392,7 @@ int git_midx_entry_find( ...@@ -392,7 +392,7 @@ int git_midx_entry_find(
hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]); hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]);
lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1])); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1]));
pos = git_pack__lookup_sha1(idx->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id); pos = git_pack__lookup_id(idx->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id, GIT_OID_SHA1);
if (pos >= 0) { if (pos >= 0) {
/* An object matching exactly the oid was found */ /* An object matching exactly the oid was found */
...@@ -549,7 +549,8 @@ int git_midx_writer_add( ...@@ -549,7 +549,8 @@ int git_midx_writer_add(
if (error < 0) if (error < 0)
return error; return error;
error = git_mwindow_get_pack(&p, git_str_cstr(&idx_path_buf)); /* TODO: SHA256 */
error = git_mwindow_get_pack(&p, git_str_cstr(&idx_path_buf), 0);
git_str_dispose(&idx_path_buf); git_str_dispose(&idx_path_buf);
if (error < 0) if (error < 0)
return error; return error;
......
...@@ -61,7 +61,10 @@ int git_mwindow_global_init(void) ...@@ -61,7 +61,10 @@ int git_mwindow_global_init(void)
return git_runtime_shutdown_register(git_mwindow_global_shutdown); return git_runtime_shutdown_register(git_mwindow_global_shutdown);
} }
int git_mwindow_get_pack(struct git_pack_file **out, const char *path) int git_mwindow_get_pack(
struct git_pack_file **out,
const char *path,
git_oid_t oid_type)
{ {
struct git_pack_file *pack; struct git_pack_file *pack;
char *packname; char *packname;
...@@ -86,7 +89,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path) ...@@ -86,7 +89,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
} }
/* If we didn't find it, we need to create it */ /* If we didn't find it, we need to create it */
if ((error = git_packfile_alloc(&pack, path)) < 0) { if ((error = git_packfile_alloc(&pack, path, oid_type)) < 0) {
git_mutex_unlock(&git__mwindow_mutex); git_mutex_unlock(&git__mwindow_mutex);
return error; return error;
} }
......
...@@ -48,7 +48,10 @@ void git_mwindow_close(git_mwindow **w_cursor); ...@@ -48,7 +48,10 @@ void git_mwindow_close(git_mwindow **w_cursor);
extern int git_mwindow_global_init(void); extern int git_mwindow_global_init(void);
struct git_pack_file; /* just declaration to avoid cyclical includes */ struct git_pack_file; /* just declaration to avoid cyclical includes */
int git_mwindow_get_pack(struct git_pack_file **out, const char *path); int git_mwindow_get_pack(
struct git_pack_file **out,
const char *path,
git_oid_t oid_type);
int git_mwindow_put_pack(struct git_pack_file *pack); int git_mwindow_put_pack(struct git_pack_file *pack);
#endif #endif
...@@ -27,8 +27,8 @@ typedef struct { ...@@ -27,8 +27,8 @@ typedef struct {
const char *str; /* type name string */ const char *str; /* type name string */
size_t size; /* size in bytes of the object structure */ size_t size; /* size in bytes of the object structure */
int (*parse)(void *self, git_odb_object *obj); int (*parse)(void *self, git_odb_object *obj, git_oid_t oid_type);
int (*parse_raw)(void *self, const char *data, size_t size); int (*parse_raw)(void *self, const char *data, size_t size, git_oid_t oid_type);
void (*free)(void *self); void (*free)(void *self);
} git_object_def; } git_object_def;
...@@ -60,7 +60,8 @@ int git_object__from_raw( ...@@ -60,7 +60,8 @@ int git_object__from_raw(
git_object **object_out, git_object **object_out,
const char *data, const char *data,
size_t size, size_t size,
git_object_t type) git_object_t object_type,
git_oid_t oid_type)
{ {
git_object_def *def; git_object_def *def;
git_object *object; git_object *object;
...@@ -71,12 +72,15 @@ int git_object__from_raw( ...@@ -71,12 +72,15 @@ int git_object__from_raw(
*object_out = NULL; *object_out = NULL;
/* Validate type match */ /* Validate type match */
if (type != GIT_OBJECT_BLOB && type != GIT_OBJECT_TREE && type != GIT_OBJECT_COMMIT && type != GIT_OBJECT_TAG) { if (object_type != GIT_OBJECT_BLOB &&
object_type != GIT_OBJECT_TREE &&
object_type != GIT_OBJECT_COMMIT &&
object_type != GIT_OBJECT_TAG) {
git_error_set(GIT_ERROR_INVALID, "the requested type is invalid"); git_error_set(GIT_ERROR_INVALID, "the requested type is invalid");
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
if ((object_size = git_object__size(type)) == 0) { if ((object_size = git_object__size(object_type)) == 0) {
git_error_set(GIT_ERROR_INVALID, "the requested type is invalid"); git_error_set(GIT_ERROR_INVALID, "the requested type is invalid");
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
...@@ -85,15 +89,15 @@ int git_object__from_raw( ...@@ -85,15 +89,15 @@ int git_object__from_raw(
object = git__calloc(1, object_size); object = git__calloc(1, object_size);
GIT_ERROR_CHECK_ALLOC(object); GIT_ERROR_CHECK_ALLOC(object);
object->cached.flags = GIT_CACHE_STORE_PARSED; object->cached.flags = GIT_CACHE_STORE_PARSED;
object->cached.type = type; object->cached.type = object_type;
if ((error = git_odb__hash(&object->cached.oid, data, size, type, GIT_OID_SHA1)) < 0) if ((error = git_odb__hash(&object->cached.oid, data, size, object_type, oid_type)) < 0)
return error; return error;
/* Parse raw object data */ /* Parse raw object data */
def = &git_objects_table[type]; def = &git_objects_table[object_type];
GIT_ASSERT(def->free && def->parse_raw); GIT_ASSERT(def->free && def->parse_raw);
if ((error = def->parse_raw(object, data, size)) < 0) { if ((error = def->parse_raw(object, data, size, oid_type)) < 0) {
def->free(object); def->free(object);
return error; return error;
} }
...@@ -143,7 +147,7 @@ int git_object__from_odb_object( ...@@ -143,7 +147,7 @@ int git_object__from_odb_object(
def = &git_objects_table[odb_obj->cached.type]; def = &git_objects_table[odb_obj->cached.type];
GIT_ASSERT(def->free && def->parse); GIT_ASSERT(def->free && def->parse);
if ((error = def->parse(object, odb_obj)) < 0) { if ((error = def->parse(object, odb_obj, repo->oid_type)) < 0) {
/* /*
* parse returns EINVALID on invalid data; downgrade * parse returns EINVALID on invalid data; downgrade
* that to a normal -1 error code. * that to a normal -1 error code.
...@@ -357,12 +361,11 @@ static int dereference_object(git_object **dereferenced, git_object *obj) ...@@ -357,12 +361,11 @@ static int dereference_object(git_object **dereferenced, git_object *obj)
static int peel_error(int error, const git_oid *oid, git_object_t type) static int peel_error(int error, const git_oid *oid, git_object_t type)
{ {
const char *type_name; const char *type_name;
char hex_oid[GIT_OID_SHA1_HEXSIZE + 1]; char hex_oid[GIT_OID_MAX_HEXSIZE + 1];
type_name = git_object_type2string(type); type_name = git_object_type2string(type);
git_oid_fmt(hex_oid, oid); git_oid_nfmt(hex_oid, GIT_OID_MAX_HEXSIZE + 1, oid);
hex_oid[GIT_OID_SHA1_HEXSIZE] = '\0';
git_error_set(GIT_ERROR_OBJECT, "the git_object of id '%s' can not be " git_error_set(GIT_ERROR_OBJECT, "the git_object of id '%s' can not be "
"successfully peeled into a %s (git_object_t=%i).", hex_oid, type_name, type); "successfully peeled into a %s (git_object_t=%i).", hex_oid, type_name, type);
...@@ -576,21 +579,29 @@ int git_object_rawcontent_is_valid( ...@@ -576,21 +579,29 @@ int git_object_rawcontent_is_valid(
int *valid, int *valid,
const char *buf, const char *buf,
size_t len, size_t len,
git_object_t type) git_object_t object_type
#ifdef GIT_EXPERIMENTAL_SHA256
, git_oid_t oid_type
#endif
)
{ {
git_object *obj = NULL; git_object *obj = NULL;
int error; int error;
#ifndef GIT_EXPERIMENTAL_SHA256
git_oid_t oid_type = GIT_OID_SHA1;
#endif
GIT_ASSERT_ARG(valid); GIT_ASSERT_ARG(valid);
GIT_ASSERT_ARG(buf); GIT_ASSERT_ARG(buf);
/* Blobs are always valid; don't bother parsing. */ /* Blobs are always valid; don't bother parsing. */
if (type == GIT_OBJECT_BLOB) { if (object_type == GIT_OBJECT_BLOB) {
*valid = 1; *valid = 1;
return 0; return 0;
} }
error = git_object__from_raw(&obj, buf, len, type); error = git_object__from_raw(&obj, buf, len, object_type, oid_type);
git_object_free(obj); git_object_free(obj);
if (error == 0) { if (error == 0) {
...@@ -611,7 +622,7 @@ int git_object__parse_oid_header( ...@@ -611,7 +622,7 @@ int git_object__parse_oid_header(
const char *header, const char *header,
git_oid_t oid_type) git_oid_t oid_type)
{ {
const size_t sha_len = GIT_OID_SHA1_HEXSIZE; const size_t sha_len = git_oid_hexsize(oid_type);
const size_t header_len = strlen(header); const size_t header_len = strlen(header);
const char *buffer = *buffer_out; const char *buffer = *buffer_out;
......
...@@ -33,7 +33,8 @@ int git_object__from_raw( ...@@ -33,7 +33,8 @@ int git_object__from_raw(
git_object **object_out, git_object **object_out,
const char *data, const char *data,
size_t size, size_t size,
git_object_t type); git_object_t object_type,
git_oid_t oid_type);
int git_object__from_odb_object( int git_object__from_odb_object(
git_object **object_out, git_object **object_out,
......
...@@ -684,6 +684,7 @@ int git_odb__add_default_backends( ...@@ -684,6 +684,7 @@ int git_odb__add_default_backends(
ino_t inode; ino_t inode;
git_odb_backend *loose, *packed; git_odb_backend *loose, *packed;
git_odb_backend_loose_options loose_opts = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT; git_odb_backend_loose_options loose_opts = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT;
git_odb_backend_pack_options pack_opts = GIT_ODB_BACKEND_PACK_OPTIONS_INIT;
/* TODO: inodes are not really relevant on Win32, so we need to find /* TODO: inodes are not really relevant on Win32, so we need to find
* a cross-platform workaround for this */ * a cross-platform workaround for this */
...@@ -722,6 +723,7 @@ int git_odb__add_default_backends( ...@@ -722,6 +723,7 @@ int git_odb__add_default_backends(
loose_opts.flags |= GIT_ODB_BACKEND_LOOSE_FSYNC; loose_opts.flags |= GIT_ODB_BACKEND_LOOSE_FSYNC;
loose_opts.oid_type = db->options.oid_type; loose_opts.oid_type = db->options.oid_type;
pack_opts.oid_type = db->options.oid_type;
/* add the loose object backend */ /* add the loose object backend */
if (git_odb__backend_loose(&loose, objects_dir, &loose_opts) < 0 || if (git_odb__backend_loose(&loose, objects_dir, &loose_opts) < 0 ||
...@@ -729,8 +731,17 @@ int git_odb__add_default_backends( ...@@ -729,8 +731,17 @@ int git_odb__add_default_backends(
return -1; return -1;
/* add the packed file backend */ /* add the packed file backend */
if (git_odb_backend_pack(&packed, objects_dir) < 0 || #ifdef GIT_EXPERIMENTAL_SHA256
add_backend_internal(db, packed, git_odb__packed_priority, as_alternates, inode) < 0) if (git_odb_backend_pack(&packed, objects_dir, &pack_opts) < 0)
return -1;
#else
GIT_UNUSED(pack_opts);
if (git_odb_backend_pack(&packed, objects_dir) < 0)
return -1;
#endif
if (add_backend_internal(db, packed, git_odb__packed_priority, as_alternates, inode) < 0)
return -1; return -1;
if (git_mutex_lock(&db->lock) < 0) { if (git_mutex_lock(&db->lock) < 0) {
......
...@@ -66,6 +66,47 @@ GIT_INLINE(size_t) git_oid_hexsize(git_oid_t type) ...@@ -66,6 +66,47 @@ GIT_INLINE(size_t) git_oid_hexsize(git_oid_t type)
return 0; return 0;
} }
GIT_INLINE(const char *) git_oid_type_name(git_oid_t type)
{
switch (type) {
case GIT_OID_SHA1:
return "sha1";
#ifdef GIT_EXPERIMENTAL_SHA256
case GIT_OID_SHA256:
return "sha256";
#endif
}
return "unknown";
}
GIT_INLINE(git_oid_t) git_oid_type_fromstr(const char *name)
{
if (strcmp(name, "sha1") == 0)
return GIT_OID_SHA1;
#ifdef GIT_EXPERIMENTAL_SHA256
if (strcmp(name, "sha256") == 0)
return GIT_OID_SHA256;
#endif
return 0;
}
GIT_INLINE(git_oid_t) git_oid_type_fromstrn(const char *name, size_t len)
{
if (len == CONST_STRLEN("sha1") && strncmp(name, "sha1", len) == 0)
return GIT_OID_SHA1;
#ifdef GIT_EXPERIMENTAL_SHA256
if (len == CONST_STRLEN("sha256") && strncmp(name, "sha256", len) == 0)
return GIT_OID_SHA256;
#endif
return 0;
}
GIT_INLINE(git_hash_algorithm_t) git_oid_algorithm(git_oid_t type) GIT_INLINE(git_hash_algorithm_t) git_oid_algorithm(git_oid_t type)
{ {
switch (type) { switch (type) {
......
...@@ -1407,7 +1407,18 @@ int git_packbuilder_write( ...@@ -1407,7 +1407,18 @@ int git_packbuilder_write(
opts.progress_cb = progress_cb; opts.progress_cb = progress_cb;
opts.progress_cb_payload = progress_cb_payload; opts.progress_cb_payload = progress_cb_payload;
if ((error = git_indexer_new(&indexer, path, mode, pb->odb, &opts)) < 0) /* TODO: SHA256 */
#ifdef GIT_EXPERIMENTAL_SHA256
opts.mode = mode;
opts.odb = pb->odb;
error = git_indexer_new(&indexer, path, GIT_OID_SHA1, &opts);
#else
error = git_indexer_new(&indexer, path, mode, pb->odb, &opts);
#endif
if (error < 0)
goto cleanup; goto cleanup;
if (!git_repository__configmap_lookup(&t, pb->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) if (!git_repository__configmap_lookup(&t, pb->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t)
......
...@@ -99,13 +99,19 @@ struct git_pack_file { ...@@ -99,13 +99,19 @@ struct git_pack_file {
uint32_t num_objects; uint32_t num_objects;
uint32_t num_bad_objects; uint32_t num_bad_objects;
git_oid *bad_object_sha1; /* array of git_oid */ git_oid *bad_object_ids; /* array of git_oid */
git_oid_t oid_type;
unsigned oid_hexsize:7,
oid_size:6,
pack_local:1,
pack_keep:1,
has_cache:1;
int index_version; int index_version;
git_time_t mtime; git_time_t mtime;
unsigned pack_local:1, pack_keep:1, has_cache:1;
git_oidmap *idx_cache; git_oidmap *idx_cache;
unsigned char **oids; unsigned char **ids;
git_pack_cache bases; /* delta base cache */ git_pack_cache bases; /* delta base cache */
...@@ -116,21 +122,26 @@ struct git_pack_file { ...@@ -116,21 +122,26 @@ struct git_pack_file {
}; };
/** /**
* Return the position where an OID (or a prefix) would be inserted within the * Return the position where an OID (or a prefix) would be inserted within
* OID Lookup Table of an .idx file. This performs binary search between the lo * the OID Lookup Table of an .idx file. This performs binary search
* and hi indices. * between the lo and hi indices.
* *
* The stride parameter is provided because .idx files version 1 store the OIDs * The stride parameter is provided because .idx files version 1 store the
* interleaved with the 4-byte file offsets of the objects within the .pack * OIDs interleaved with the 4-byte file offsets of the objects within the
* file (stride = 24), whereas files with version 2 store them in a contiguous * .pack file (stride = oid_size + 4), whereas files with version 2 store
* flat array (stride = 20). * them in a contiguous flat array (stride = oid_size).
*/ */
int git_pack__lookup_sha1(const void *oid_lookup_table, size_t stride, unsigned lo, int git_pack__lookup_id(
unsigned hi, const unsigned char *oid_prefix); const void *id_lookup_table,
size_t stride,
unsigned lo,
unsigned hi,
const unsigned char *id_prefix,
const git_oid_t oid_type);
struct git_pack_entry { struct git_pack_entry {
off64_t offset; off64_t offset;
git_oid sha1; git_oid id;
struct git_pack_file *p; struct git_pack_file *p;
}; };
...@@ -174,12 +185,15 @@ int get_delta_base( ...@@ -174,12 +185,15 @@ int get_delta_base(
off64_t delta_obj_offset); off64_t delta_obj_offset);
void git_packfile_free(struct git_pack_file *p, bool unlink_packfile); void git_packfile_free(struct git_pack_file *p, bool unlink_packfile);
int git_packfile_alloc(struct git_pack_file **pack_out, const char *path); int git_packfile_alloc(
struct git_pack_file **pack_out,
const char *path,
git_oid_t oid_type);
int git_pack_entry_find( int git_pack_entry_find(
struct git_pack_entry *e, struct git_pack_entry *e,
struct git_pack_file *p, struct git_pack_file *p,
const git_oid *short_oid, const git_oid *short_id,
size_t len); size_t len);
int git_pack_foreach_entry( int git_pack_foreach_entry(
struct git_pack_file *p, struct git_pack_file *p,
......
...@@ -60,15 +60,17 @@ typedef struct refdb_fs_backend { ...@@ -60,15 +60,17 @@ typedef struct refdb_fs_backend {
/* path to common objects' directory */ /* path to common objects' directory */
char *commonpath; char *commonpath;
git_sortedcache *refcache; git_oid_t oid_type;
int fsync : 1,
sorted : 1;
int peeling_mode; int peeling_mode;
git_iterator_flag_t iterator_flags; git_iterator_flag_t iterator_flags;
uint32_t direach_flags; uint32_t direach_flags;
int fsync; git_sortedcache *refcache;
git_map packed_refs_map; git_map packed_refs_map;
git_mutex prlock; /* protect packed_refs_map */ git_mutex prlock; /* protect packed_refs_map */
git_futils_filestamp packed_refs_stamp; git_futils_filestamp packed_refs_stamp;
bool sorted;
} refdb_fs_backend; } refdb_fs_backend;
static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name); static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
...@@ -113,6 +115,7 @@ static int packed_reload(refdb_fs_backend *backend) ...@@ -113,6 +115,7 @@ static int packed_reload(refdb_fs_backend *backend)
{ {
int error; int error;
git_str packedrefs = GIT_STR_INIT; git_str packedrefs = GIT_STR_INIT;
size_t oid_hexsize = git_oid_hexsize(backend->oid_type);
char *scan, *eof, *eol; char *scan, *eof, *eol;
if (!backend->gitpath) if (!backend->gitpath)
...@@ -158,9 +161,9 @@ static int packed_reload(refdb_fs_backend *backend) ...@@ -158,9 +161,9 @@ static int packed_reload(refdb_fs_backend *backend)
/* parse "<OID> <refname>\n" */ /* parse "<OID> <refname>\n" */
if (git_oid__fromstr(&oid, scan, GIT_OID_SHA1) < 0) if (git_oid__fromstr(&oid, scan, backend->oid_type) < 0)
goto parse_failed; goto parse_failed;
scan += GIT_OID_SHA1_HEXSIZE; scan += oid_hexsize;
if (*scan++ != ' ') if (*scan++ != ' ')
goto parse_failed; goto parse_failed;
...@@ -179,9 +182,9 @@ static int packed_reload(refdb_fs_backend *backend) ...@@ -179,9 +182,9 @@ static int packed_reload(refdb_fs_backend *backend)
/* look for optional "^<OID>\n" */ /* look for optional "^<OID>\n" */
if (*scan == '^') { if (*scan == '^') {
if (git_oid__fromstr(&oid, scan + 1, GIT_OID_SHA1) < 0) if (git_oid__fromstr(&oid, scan + 1, backend->oid_type) < 0)
goto parse_failed; goto parse_failed;
scan += GIT_OID_SHA1_HEXSIZE + 1; scan += oid_hexsize + 1;
if (scan < eof) { if (scan < eof) {
if (!(eol = strchr(scan, '\n'))) if (!(eol = strchr(scan, '\n')))
...@@ -214,19 +217,23 @@ parse_failed: ...@@ -214,19 +217,23 @@ parse_failed:
} }
static int loose_parse_oid( static int loose_parse_oid(
git_oid *oid, const char *filename, git_str *file_content) git_oid *oid,
const char *filename,
git_str *file_content,
git_oid_t oid_type)
{ {
const char *str = git_str_cstr(file_content); const char *str = git_str_cstr(file_content);
size_t oid_hexsize = git_oid_hexsize(oid_type);
if (git_str_len(file_content) < GIT_OID_SHA1_HEXSIZE) if (git_str_len(file_content) < oid_hexsize)
goto corrupted; goto corrupted;
/* we need to get 40 OID characters from the file */ /* we need to get 40 OID characters from the file */
if (git_oid__fromstr(oid, str, GIT_OID_SHA1) < 0) if (git_oid__fromstr(oid, str, oid_type) < 0)
goto corrupted; goto corrupted;
/* If the file is longer than 40 chars, the 41st must be a space */ /* If the file is longer than 40 chars, the 41st must be a space */
str += GIT_OID_SHA1_HEXSIZE; str += oid_hexsize;
if (*str == '\0' || git__isspace(*str)) if (*str == '\0' || git__isspace(*str))
return 0; return 0;
...@@ -266,7 +273,7 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name) ...@@ -266,7 +273,7 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
goto done; goto done;
/* parse OID from file */ /* parse OID from file */
if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0) if ((error = loose_parse_oid(&oid, name, &ref_file, backend->oid_type)) < 0)
goto done; goto done;
if ((error = git_sortedcache_wlock(backend->refcache)) < 0) if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
...@@ -437,7 +444,7 @@ static int loose_lookup( ...@@ -437,7 +444,7 @@ static int loose_lookup(
} else { } else {
git_oid oid; git_oid oid;
if (!(error = loose_parse_oid(&oid, ref_name, &ref_file)) && if (!(error = loose_parse_oid(&oid, ref_name, &ref_file, backend->oid_type)) &&
out != NULL) out != NULL)
*out = git_reference__alloc(ref_name, &oid, NULL); *out = git_reference__alloc(ref_name, &oid, NULL);
} }
...@@ -615,19 +622,24 @@ static const char *end_of_record(const char *p, const char *end) ...@@ -615,19 +622,24 @@ static const char *end_of_record(const char *p, const char *end)
return p; return p;
} }
static int static int cmp_record_to_refname(
cmp_record_to_refname(const char *rec, size_t data_end, const char *ref_name) const char *rec,
size_t data_end,
const char *ref_name,
git_oid_t oid_type)
{ {
const size_t ref_len = strlen(ref_name); const size_t ref_len = strlen(ref_name);
int cmp_val; int cmp_val;
const char *end; const char *end;
size_t oid_hexsize = git_oid_hexsize(oid_type);
rec += GIT_OID_SHA1_HEXSIZE + 1; /* <oid> + space */ rec += oid_hexsize + 1; /* <oid> + space */
if (data_end < GIT_OID_SHA1_HEXSIZE + 3) {
/* an incomplete (corrupt) record is treated as less than ref_name */ /* an incomplete (corrupt) record is treated as less than ref_name */
if (data_end < oid_hexsize + 3)
return -1; return -1;
}
data_end -= GIT_OID_SHA1_HEXSIZE + 1; data_end -= oid_hexsize + 1;
end = memchr(rec, '\n', data_end); end = memchr(rec, '\n', data_end);
if (end) if (end)
...@@ -675,6 +687,7 @@ static int packed_lookup( ...@@ -675,6 +687,7 @@ static int packed_lookup(
{ {
int error = 0; int error = 0;
const char *left, *right, *data_end; const char *left, *right, *data_end;
size_t oid_hexsize = git_oid_hexsize(backend->oid_type);
if ((error = packed_map_check(backend)) < 0) if ((error = packed_map_check(backend)) < 0)
return error; return error;
...@@ -698,7 +711,7 @@ static int packed_lookup( ...@@ -698,7 +711,7 @@ static int packed_lookup(
mid = left + (right - left) / 2; mid = left + (right - left) / 2;
rec = start_of_record(left, mid); rec = start_of_record(left, mid);
compare = cmp_record_to_refname(rec, data_end - rec, ref_name); compare = cmp_record_to_refname(rec, data_end - rec, ref_name, backend->oid_type);
if (compare < 0) { if (compare < 0) {
left = end_of_record(mid, right); left = end_of_record(mid, right);
...@@ -708,11 +721,11 @@ static int packed_lookup( ...@@ -708,11 +721,11 @@ static int packed_lookup(
const char *eol; const char *eol;
git_oid oid, peel, *peel_ptr = NULL; git_oid oid, peel, *peel_ptr = NULL;
if (data_end - rec < GIT_OID_SHA1_HEXSIZE || if (data_end - rec < (long)oid_hexsize ||
git_oid__fromstr(&oid, rec, GIT_OID_SHA1) < 0) { git_oid__fromstr(&oid, rec, backend->oid_type) < 0) {
goto parse_failed; goto parse_failed;
} }
rec += GIT_OID_SHA1_HEXSIZE + 1; rec += oid_hexsize + 1;
if (!(eol = memchr(rec, '\n', data_end - rec))) { if (!(eol = memchr(rec, '\n', data_end - rec))) {
goto parse_failed; goto parse_failed;
} }
...@@ -724,8 +737,8 @@ static int packed_lookup( ...@@ -724,8 +737,8 @@ static int packed_lookup(
if (*rec == '^') { if (*rec == '^') {
rec++; rec++;
if (data_end - rec < GIT_OID_SHA1_HEXSIZE || if (data_end - rec < (long)oid_hexsize ||
git_oid__fromstr(&peel, rec, GIT_OID_SHA1) < 0) { git_oid__fromstr(&peel, rec, backend->oid_type) < 0) {
goto parse_failed; goto parse_failed;
} }
peel_ptr = &peel; peel_ptr = &peel;
...@@ -1108,7 +1121,7 @@ static int loose_commit(git_filebuf *file, const git_reference *ref) ...@@ -1108,7 +1121,7 @@ static int loose_commit(git_filebuf *file, const git_reference *ref)
GIT_ASSERT_ARG(ref); GIT_ASSERT_ARG(ref);
if (ref->type == GIT_REFERENCE_DIRECT) { if (ref->type == GIT_REFERENCE_DIRECT) {
char oid[GIT_OID_SHA1_HEXSIZE + 1]; char oid[GIT_OID_MAX_HEXSIZE + 1];
git_oid_nfmt(oid, sizeof(oid), &ref->target.oid); git_oid_nfmt(oid, sizeof(oid), &ref->target.oid);
git_filebuf_printf(file, "%s\n", oid); git_filebuf_printf(file, "%s\n", oid);
...@@ -1224,7 +1237,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) ...@@ -1224,7 +1237,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref)
*/ */
static int packed_write_ref(struct packref *ref, git_filebuf *file) static int packed_write_ref(struct packref *ref, git_filebuf *file)
{ {
char oid[GIT_OID_SHA1_HEXSIZE + 1]; char oid[GIT_OID_MAX_HEXSIZE + 1];
git_oid_nfmt(oid, sizeof(oid), &ref->oid); git_oid_nfmt(oid, sizeof(oid), &ref->oid);
/* /*
...@@ -1238,7 +1251,7 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file) ...@@ -1238,7 +1251,7 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file)
* The required peels have already been loaded into `ref->peel_target`. * The required peels have already been loaded into `ref->peel_target`.
*/ */
if (ref->flags & PACKREF_HAS_PEEL) { if (ref->flags & PACKREF_HAS_PEEL) {
char peel[GIT_OID_SHA1_HEXSIZE + 1]; char peel[GIT_OID_MAX_HEXSIZE + 1];
git_oid_nfmt(peel, sizeof(peel), &ref->peel); git_oid_nfmt(peel, sizeof(peel), &ref->peel);
if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0) if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0)
...@@ -1302,7 +1315,7 @@ static int packed_remove_loose(refdb_fs_backend *backend) ...@@ -1302,7 +1315,7 @@ static int packed_remove_loose(refdb_fs_backend *backend)
continue; continue;
/* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */ /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
if (loose_parse_oid(&current_id, lock.path_original, &ref_content) < 0) if (loose_parse_oid(&current_id, lock.path_original, &ref_content, backend->oid_type) < 0)
continue; continue;
/* If the ref moved since we packed it, we must not delete it */ /* If the ref moved since we packed it, we must not delete it */
...@@ -1891,7 +1904,10 @@ done: ...@@ -1891,7 +1904,10 @@ done:
return out; return out;
} }
static int reflog_alloc(git_reflog **reflog, const char *name) static int reflog_alloc(
git_reflog **reflog,
const char *name,
git_oid_t oid_type)
{ {
git_reflog *log; git_reflog *log;
...@@ -1903,6 +1919,8 @@ static int reflog_alloc(git_reflog **reflog, const char *name) ...@@ -1903,6 +1919,8 @@ static int reflog_alloc(git_reflog **reflog, const char *name)
log->ref_name = git__strdup(name); log->ref_name = git__strdup(name);
GIT_ERROR_CHECK_ALLOC(log->ref_name); GIT_ERROR_CHECK_ALLOC(log->ref_name);
log->oid_type = oid_type;
if (git_vector_init(&log->entries, 0, NULL) < 0) { if (git_vector_init(&log->entries, 0, NULL) < 0) {
git__free(log->ref_name); git__free(log->ref_name);
git__free(log); git__free(log);
...@@ -2032,7 +2050,10 @@ static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *nam ...@@ -2032,7 +2050,10 @@ static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *nam
return has_reflog(backend->repo, name); return has_reflog(backend->repo, name);
} }
static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name) static int refdb_reflog_fs__read(
git_reflog **out,
git_refdb_backend *_backend,
const char *name)
{ {
int error = -1; int error = -1;
git_str log_path = GIT_STR_INIT; git_str log_path = GIT_STR_INIT;
...@@ -2048,7 +2069,7 @@ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, ...@@ -2048,7 +2069,7 @@ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend,
backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
repo = backend->repo; repo = backend->repo;
if (reflog_alloc(&log, name) < 0) if (reflog_alloc(&log, name, backend->oid_type) < 0)
return -1; return -1;
if (reflog_path(&log_path, repo, name) < 0) if (reflog_path(&log_path, repo, name) < 0)
...@@ -2086,11 +2107,11 @@ static int serialize_reflog_entry( ...@@ -2086,11 +2107,11 @@ static int serialize_reflog_entry(
const git_signature *committer, const git_signature *committer,
const char *msg) const char *msg)
{ {
char raw_old[GIT_OID_SHA1_HEXSIZE+1]; char raw_old[GIT_OID_MAX_HEXSIZE + 1];
char raw_new[GIT_OID_SHA1_HEXSIZE+1]; char raw_new[GIT_OID_MAX_HEXSIZE + 1];
git_oid_tostr(raw_old, GIT_OID_SHA1_HEXSIZE+1, oid_old); git_oid_tostr(raw_old, GIT_OID_MAX_HEXSIZE + 1, oid_old);
git_oid_tostr(raw_new, GIT_OID_SHA1_HEXSIZE+1, oid_new); git_oid_tostr(raw_new, GIT_OID_MAX_HEXSIZE + 1, oid_new);
git_str_clear(buf); git_str_clear(buf);
...@@ -2189,10 +2210,16 @@ success: ...@@ -2189,10 +2210,16 @@ success:
} }
/* Append to the reflog, must be called under reference lock */ /* Append to the reflog, must be called under reference lock */
static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message) static int reflog_append(
refdb_fs_backend *backend,
const git_reference *ref,
const git_oid *old,
const git_oid *new,
const git_signature *who,
const char *message)
{ {
int error, is_symbolic, open_flags; int error, is_symbolic, open_flags;
git_oid old_id = GIT_OID_SHA1_ZERO, new_id = GIT_OID_SHA1_ZERO; git_oid old_id, new_id;
git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; git_str buf = GIT_STR_INIT, path = GIT_STR_INIT;
git_repository *repo = backend->repo; git_repository *repo = backend->repo;
...@@ -2206,6 +2233,9 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co ...@@ -2206,6 +2233,9 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
/* From here on is_symbolic also means that it's HEAD */ /* From here on is_symbolic also means that it's HEAD */
git_oid_clear(&old_id, backend->oid_type);
git_oid_clear(&new_id, backend->oid_type);
if (old) { if (old) {
git_oid_cpy(&old_id, old); git_oid_cpy(&old_id, old);
} else { } else {
...@@ -2402,6 +2432,7 @@ int git_refdb_backend_fs( ...@@ -2402,6 +2432,7 @@ int git_refdb_backend_fs(
goto fail; goto fail;
backend->repo = repository; backend->repo = repository;
backend->oid_type = repository->oid_type;
if (repository->gitdir) { if (repository->gitdir) {
backend->gitpath = setup_namespace(repository, repository->gitdir); backend->gitpath = setup_namespace(repository, repository->gitdir);
......
...@@ -71,7 +71,11 @@ int git_reflog_write(git_reflog *reflog) ...@@ -71,7 +71,11 @@ int git_reflog_write(git_reflog *reflog)
return db->backend->reflog_write(db->backend, reflog); return db->backend->reflog_write(db->backend, reflog);
} }
int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg) int git_reflog_append(
git_reflog *reflog,
const git_oid *new_oid,
const git_signature *committer,
const char *msg)
{ {
const git_reflog_entry *previous; const git_reflog_entry *previous;
git_reflog_entry *entry; git_reflog_entry *entry;
...@@ -104,7 +108,7 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_sign ...@@ -104,7 +108,7 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_sign
previous = git_reflog_entry_byindex(reflog, 0); previous = git_reflog_entry_byindex(reflog, 0);
if (previous == NULL) if (previous == NULL)
git_oid__fromstr(&entry->oid_old, GIT_OID_SHA1_HEXZERO, GIT_OID_SHA1); git_oid_clear(&entry->oid_old, reflog->oid_type);
else else
git_oid_cpy(&entry->oid_old, &previous->oid_cur); git_oid_cpy(&entry->oid_old, &previous->oid_cur);
...@@ -218,12 +222,8 @@ int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry) ...@@ -218,12 +222,8 @@ int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry)
/* If the oldest entry has just been removed... */ /* If the oldest entry has just been removed... */
if (idx == entrycount - 1) { if (idx == entrycount - 1) {
git_oid zero = GIT_OID_SHA1_ZERO;
/* ...clear the oid_old member of the "new" oldest entry */ /* ...clear the oid_old member of the "new" oldest entry */
if (git_oid_cpy(&entry->oid_old, &zero) < 0) git_oid_clear(&entry->oid_old, reflog->oid_type);
return -1;
return 0; return 0;
} }
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
#define GIT_REFLOG_DIR_MODE 0777 #define GIT_REFLOG_DIR_MODE 0777
#define GIT_REFLOG_FILE_MODE 0666 #define GIT_REFLOG_FILE_MODE 0666
#define GIT_REFLOG_SIZE_MIN (2*GIT_OID_SHA1_HEXSIZE+2+17)
struct git_reflog_entry { struct git_reflog_entry {
git_oid oid_old; git_oid oid_old;
git_oid oid_cur; git_oid oid_cur;
...@@ -30,6 +28,7 @@ struct git_reflog_entry { ...@@ -30,6 +28,7 @@ struct git_reflog_entry {
struct git_reflog { struct git_reflog {
git_refdb *db; git_refdb *db;
char *ref_name; char *ref_name;
git_oid_t oid_type;
git_vector entries; git_vector entries;
}; };
......
...@@ -1026,6 +1026,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote) ...@@ -1026,6 +1026,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote)
return remote->transport->capabilities(out, remote->transport); return remote->transport->capabilities(out, remote->transport);
} }
int git_remote_oid_type(git_oid_t *out, git_remote *remote)
{
GIT_ASSERT_ARG(remote);
if (!remote->transport) {
git_error_set(GIT_ERROR_NET, "this remote has never connected");
*out = 0;
return -1;
}
#ifdef GIT_EXPERIMENTAL_SHA256
return remote->transport->oid_type(out, remote->transport);
#else
*out = GIT_OID_SHA1;
return 0;
#endif
}
static int lookup_config(char **out, git_config *cfg, const char *name) static int lookup_config(char **out, git_config *cfg, const char *name)
{ {
git_config_entry *ce = NULL; git_config_entry *ce = NULL;
...@@ -1225,24 +1243,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote) ...@@ -1225,24 +1243,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote)
return 0; return 0;
} }
#define copy_opts(out, in) \
if (in) { \
(out)->callbacks = (in)->callbacks; \
(out)->proxy_opts = (in)->proxy_opts; \
(out)->custom_headers = (in)->custom_headers; \
(out)->follow_redirects = (in)->follow_redirects; \
}
GIT_INLINE(int) connect_opts_from_fetch_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_fetch_options *fetch_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
copy_opts(&tmp, fetch_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
static int connect_or_reset_options( static int connect_or_reset_options(
git_remote *remote, git_remote *remote,
int direction, int direction,
...@@ -1330,7 +1330,8 @@ int git_remote_download( ...@@ -1330,7 +1330,8 @@ int git_remote_download(
return -1; return -1;
} }
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0) if (git_remote_connect_options__from_fetch_opts(&connect_opts,
remote, opts) < 0)
return -1; return -1;
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
...@@ -1350,6 +1351,8 @@ int git_remote_fetch( ...@@ -1350,6 +1351,8 @@ int git_remote_fetch(
bool prune = false; bool prune = false;
git_str reflog_msg_buf = GIT_STR_INIT; git_str reflog_msg_buf = GIT_STR_INIT;
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
unsigned int capabilities;
git_oid_t oid_type;
GIT_ASSERT_ARG(remote); GIT_ASSERT_ARG(remote);
...@@ -1358,7 +1361,8 @@ int git_remote_fetch( ...@@ -1358,7 +1361,8 @@ int git_remote_fetch(
return -1; return -1;
} }
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0) if (git_remote_connect_options__from_fetch_opts(&connect_opts,
remote, opts) < 0)
return -1; return -1;
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
...@@ -1369,6 +1373,10 @@ int git_remote_fetch( ...@@ -1369,6 +1373,10 @@ int git_remote_fetch(
tagopt = opts->download_tags; tagopt = opts->download_tags;
} }
if ((error = git_remote_capabilities(&capabilities, remote)) < 0 ||
(error = git_remote_oid_type(&oid_type, remote)) < 0)
return error;
/* Connect and download everything */ /* Connect and download everything */
error = git_remote__download(remote, refspecs, opts); error = git_remote__download(remote, refspecs, opts);
...@@ -2896,16 +2904,6 @@ done: ...@@ -2896,16 +2904,6 @@ done:
return error; return error;
} }
GIT_INLINE(int) connect_opts_from_push_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_push_options *push_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
copy_opts(&tmp, push_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
int git_remote_upload( int git_remote_upload(
git_remote *remote, git_remote *remote,
const git_strarray *refspecs, const git_strarray *refspecs,
...@@ -2924,7 +2922,8 @@ int git_remote_upload( ...@@ -2924,7 +2922,8 @@ int git_remote_upload(
return -1; return -1;
} }
if ((error = connect_opts_from_push_opts(&connect_opts, remote, opts)) < 0) if ((error = git_remote_connect_options__from_push_opts(
&connect_opts, remote, opts)) < 0)
goto cleanup; goto cleanup;
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0) if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0)
...@@ -2985,7 +2984,8 @@ int git_remote_push( ...@@ -2985,7 +2984,8 @@ int git_remote_push(
return -1; return -1;
} }
if (connect_opts_from_push_opts(&connect_opts, remote, opts) < 0) if (git_remote_connect_options__from_push_opts(&connect_opts,
remote, opts) < 0)
return -1; return -1;
if ((error = git_remote_upload(remote, refspecs, opts)) < 0) if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "refspec.h" #include "refspec.h"
#include "vector.h" #include "vector.h"
#include "net.h" #include "net.h"
#include "proxy.h"
#define GIT_REMOTE_ORIGIN "origin" #define GIT_REMOTE_ORIGIN "origin"
...@@ -56,5 +57,44 @@ int git_remote_connect_options_normalize( ...@@ -56,5 +57,44 @@ int git_remote_connect_options_normalize(
const git_remote_connect_options *src); const git_remote_connect_options *src);
int git_remote_capabilities(unsigned int *out, git_remote *remote); int git_remote_capabilities(unsigned int *out, git_remote *remote);
int git_remote_oid_type(git_oid_t *out, git_remote *remote);
#define git_remote_connect_options__copy_opts(out, in) \
if (in) { \
(out)->callbacks = (in)->callbacks; \
(out)->proxy_opts = (in)->proxy_opts; \
(out)->custom_headers = (in)->custom_headers; \
(out)->follow_redirects = (in)->follow_redirects; \
}
GIT_INLINE(int) git_remote_connect_options__from_fetch_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_fetch_options *fetch_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_remote_connect_options__copy_opts(&tmp, fetch_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
GIT_INLINE(int) git_remote_connect_options__from_push_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_push_options *push_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_remote_connect_options__copy_opts(&tmp, push_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
#undef git_remote_connect_options__copy_opts
GIT_INLINE(void) git_remote_connect_options__dispose(
git_remote_connect_options *opts)
{
git_proxy_options_dispose(&opts->proxy_opts);
git_strarray_dispose(&opts->custom_headers);
}
#endif #endif
...@@ -67,6 +67,7 @@ static const struct { ...@@ -67,6 +67,7 @@ static const struct {
static int check_repositoryformatversion(int *version, git_config *config); static int check_repositoryformatversion(int *version, git_config *config);
static int check_extensions(git_config *config, int version); static int check_extensions(git_config *config, int version);
static int load_global_config(git_config **config); static int load_global_config(git_config **config);
static int load_objectformat(git_repository *repo, git_config *config);
#define GIT_COMMONDIR_FILE "commondir" #define GIT_COMMONDIR_FILE "commondir"
#define GIT_GITDIR_FILE "gitdir" #define GIT_GITDIR_FILE "gitdir"
...@@ -75,8 +76,8 @@ static int load_global_config(git_config **config); ...@@ -75,8 +76,8 @@ static int load_global_config(git_config **config);
#define GIT_BRANCH_DEFAULT "master" #define GIT_BRANCH_DEFAULT "master"
#define GIT_REPO_VERSION 0 #define GIT_REPO_VERSION_DEFAULT 0
#define GIT_REPO_MAX_VERSION 1 #define GIT_REPO_VERSION_MAX 1
git_str git_repository__reserved_names_win32[] = { git_str git_repository__reserved_names_win32[] = {
{ DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
...@@ -240,7 +241,7 @@ GIT_INLINE(int) validate_repo_path(git_str *path) ...@@ -240,7 +241,7 @@ GIT_INLINE(int) validate_repo_path(git_str *path)
*/ */
static size_t suffix_len = static size_t suffix_len =
CONST_STRLEN("objects/pack/pack-.pack.lock") + CONST_STRLEN("objects/pack/pack-.pack.lock") +
GIT_OID_SHA1_HEXSIZE; GIT_OID_MAX_HEXSIZE;
return git_fs_path_validate_str_length_with_suffix( return git_fs_path_validate_str_length_with_suffix(
path, suffix_len); path, suffix_len);
...@@ -1015,7 +1016,8 @@ int git_repository_open_ext( ...@@ -1015,7 +1016,8 @@ int git_repository_open_ext(
if (error < 0 && error != GIT_ENOTFOUND) if (error < 0 && error != GIT_ENOTFOUND)
goto cleanup; goto cleanup;
if (config && (error = check_repositoryformatversion(&version, config)) < 0) if (config &&
(error = check_repositoryformatversion(&version, config)) < 0)
goto cleanup; goto cleanup;
if ((error = check_extensions(config, version)) < 0) if ((error = check_extensions(config, version)) < 0)
...@@ -1030,6 +1032,13 @@ int git_repository_open_ext( ...@@ -1030,6 +1032,13 @@ int git_repository_open_ext(
goto cleanup; goto cleanup;
} }
if (version > 0) {
if ((error = load_objectformat(repo, config)) < 0)
goto cleanup;
} else {
repo->oid_type = GIT_OID_SHA1;
}
/* /*
* Ensure that the git directory and worktree are * Ensure that the git directory and worktree are
* owned by the current user. * owned by the current user.
...@@ -1269,11 +1278,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) ...@@ -1269,11 +1278,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
*out = git_atomic_load(repo->_odb); *out = git_atomic_load(repo->_odb);
if (*out == NULL) { if (*out == NULL) {
git_str odb_path = GIT_STR_INIT; git_str odb_path = GIT_STR_INIT;
git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT;
git_odb *odb; git_odb *odb;
odb_opts.oid_type = repo->oid_type;
if ((error = git_repository__item_path(&odb_path, repo, if ((error = git_repository__item_path(&odb_path, repo,
GIT_REPOSITORY_ITEM_OBJECTS)) < 0 || GIT_REPOSITORY_ITEM_OBJECTS)) < 0 ||
(error = git_odb__new(&odb, NULL)) < 0) (error = git_odb__new(&odb, &odb_opts)) < 0)
return error; return error;
GIT_REFCOUNT_OWN(odb, repo); GIT_REFCOUNT_OWN(odb, repo);
...@@ -1531,6 +1543,7 @@ static int check_repositoryformatversion(int *version, git_config *config) ...@@ -1531,6 +1543,7 @@ static int check_repositoryformatversion(int *version, git_config *config)
int error; int error;
error = git_config_get_int32(version, config, "core.repositoryformatversion"); error = git_config_get_int32(version, config, "core.repositoryformatversion");
/* git ignores this if the config variable isn't there */ /* git ignores this if the config variable isn't there */
if (error == GIT_ENOTFOUND) if (error == GIT_ENOTFOUND)
return 0; return 0;
...@@ -1538,10 +1551,15 @@ static int check_repositoryformatversion(int *version, git_config *config) ...@@ -1538,10 +1551,15 @@ static int check_repositoryformatversion(int *version, git_config *config)
if (error < 0) if (error < 0)
return -1; return -1;
if (GIT_REPO_MAX_VERSION < *version) { if (*version < 0) {
git_error_set(GIT_ERROR_REPOSITORY,
"invalid repository version %d", *version);
}
if (GIT_REPO_VERSION_MAX < *version) {
git_error_set(GIT_ERROR_REPOSITORY, git_error_set(GIT_ERROR_REPOSITORY,
"unsupported repository version %d; only versions up to %d are supported", "unsupported repository version %d; only versions up to %d are supported",
*version, GIT_REPO_MAX_VERSION); *version, GIT_REPO_VERSION_MAX);
return -1; return -1;
} }
...@@ -1549,7 +1567,8 @@ static int check_repositoryformatversion(int *version, git_config *config) ...@@ -1549,7 +1567,8 @@ static int check_repositoryformatversion(int *version, git_config *config)
} }
static const char *builtin_extensions[] = { static const char *builtin_extensions[] = {
"noop" "noop",
"objectformat"
}; };
static git_vector user_extensions = GIT_VECTOR_INIT; static git_vector user_extensions = GIT_VECTOR_INIT;
...@@ -1613,6 +1632,79 @@ static int check_extensions(git_config *config, int version) ...@@ -1613,6 +1632,79 @@ static int check_extensions(git_config *config, int version)
return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL); return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL);
} }
static int load_objectformat(git_repository *repo, git_config *config)
{
git_config_entry *entry = NULL;
int error;
if ((error = git_config_get_entry(&entry, config, "extensions.objectformat")) < 0) {
if (error == GIT_ENOTFOUND) {
repo->oid_type = GIT_OID_SHA1;
git_error_clear();
error = 0;
}
goto done;
}
if ((repo->oid_type = git_oid_type_fromstr(entry->value)) == 0) {
git_error_set(GIT_ERROR_REPOSITORY,
"unknown object format '%s'", entry->value);
error = GIT_EINVALID;
}
done:
git_config_entry_free(entry);
return error;
}
int git_repository__set_objectformat(
git_repository *repo,
git_oid_t oid_type)
{
git_config *cfg;
/*
* Older clients do not necessarily understand the
* `objectformat` extension, even when it's set to an
* object format that they understand (SHA1). Do not set
* the objectformat extension unless we're not using the
* default object format.
*/
if (oid_type == GIT_OID_DEFAULT)
return 0;
if (!git_repository_is_empty(repo) && repo->oid_type != oid_type) {
git_error_set(GIT_ERROR_REPOSITORY,
"cannot change object id type of existing repository");
return -1;
}
if (git_repository_config__weakptr(&cfg, repo) < 0)
return -1;
if (git_config_set_int32(cfg,
"core.repositoryformatversion", 1) < 0 ||
git_config_set_string(cfg, "extensions.objectformat",
git_oid_type_name(oid_type)) < 0)
return -1;
/*
* During repo init, we may create some backends with the
* default oid type. Clear them so that we create them with
* the proper oid type.
*/
if (repo->oid_type != oid_type) {
set_index(repo, NULL);
set_odb(repo, NULL);
set_refdb(repo, NULL);
repo->oid_type = oid_type;
}
return 0;
}
int git_repository__extensions(char ***out, size_t *out_len) int git_repository__extensions(char ***out, size_t *out_len)
{ {
git_vector extensions; git_vector extensions;
...@@ -1891,19 +1983,21 @@ static int repo_init_config( ...@@ -1891,19 +1983,21 @@ static int repo_init_config(
const char *repo_dir, const char *repo_dir,
const char *work_dir, const char *work_dir,
uint32_t flags, uint32_t flags,
uint32_t mode) uint32_t mode,
git_oid_t oid_type)
{ {
int error = 0; int error = 0;
git_str cfg_path = GIT_STR_INIT, worktree_path = GIT_STR_INIT; git_str cfg_path = GIT_STR_INIT, worktree_path = GIT_STR_INIT;
git_config *config = NULL; git_config *config = NULL;
bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0); bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0); bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
int version = 0; int version = GIT_REPO_VERSION_DEFAULT;
if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0) if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
goto cleanup; goto cleanup;
if (is_reinit && (error = check_repositoryformatversion(&version, config)) < 0) if (is_reinit &&
(error = check_repositoryformatversion(&version, config)) < 0)
goto cleanup; goto cleanup;
if ((error = check_extensions(config, version)) < 0) if ((error = check_extensions(config, version)) < 0)
...@@ -1914,7 +2008,7 @@ static int repo_init_config( ...@@ -1914,7 +2008,7 @@ static int repo_init_config(
goto cleanup; } while (0) goto cleanup; } while (0)
SET_REPO_CONFIG(bool, "core.bare", is_bare); SET_REPO_CONFIG(bool, "core.bare", is_bare);
SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION); SET_REPO_CONFIG(int32, "core.repositoryformatversion", version);
if ((error = repo_init_fs_configs( if ((error = repo_init_fs_configs(
config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0) config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
...@@ -1947,6 +2041,11 @@ static int repo_init_config( ...@@ -1947,6 +2041,11 @@ static int repo_init_config(
SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
} }
if (oid_type != GIT_OID_SHA1) {
SET_REPO_CONFIG(int32, "core.repositoryformatversion", 1);
SET_REPO_CONFIG(string, "extensions.objectformat", git_oid_type_name(oid_type));
}
cleanup: cleanup:
git_str_dispose(&cfg_path); git_str_dispose(&cfg_path);
git_str_dispose(&worktree_path); git_str_dispose(&worktree_path);
...@@ -2427,6 +2526,7 @@ int git_repository_init_ext( ...@@ -2427,6 +2526,7 @@ int git_repository_init_ext(
common_path = GIT_STR_INIT; common_path = GIT_STR_INIT;
const char *wd; const char *wd;
bool is_valid; bool is_valid;
git_oid_t oid_type = GIT_OID_DEFAULT;
int error; int error;
GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(out);
...@@ -2435,6 +2535,11 @@ int git_repository_init_ext( ...@@ -2435,6 +2535,11 @@ int git_repository_init_ext(
GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options"); GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
#ifdef GIT_EXPERIMENTAL_SHA256
if (opts->oid_type)
oid_type = opts->oid_type;
#endif
if ((error = repo_init_directories(&repo_path, &wd_path, given_repo, opts)) < 0) if ((error = repo_init_directories(&repo_path, &wd_path, given_repo, opts)) < 0)
goto out; goto out;
...@@ -2453,13 +2558,13 @@ int git_repository_init_ext( ...@@ -2453,13 +2558,13 @@ int git_repository_init_ext(
opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT; opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
if ((error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0) if ((error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode, oid_type)) < 0)
goto out; goto out;
/* TODO: reinitialize the templates */ /* TODO: reinitialize the templates */
} else { } else {
if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 || if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 ||
(error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0 || (error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode, oid_type)) < 0 ||
(error = repo_init_head(repo_path.ptr, opts->initial_head)) < 0) (error = repo_init_head(repo_path.ptr, opts->initial_head)) < 0)
goto out; goto out;
} }
...@@ -2922,14 +3027,14 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head ...@@ -2922,14 +3027,14 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head
{ {
git_filebuf file = GIT_FILEBUF_INIT; git_filebuf file = GIT_FILEBUF_INIT;
git_str file_path = GIT_STR_INIT; git_str file_path = GIT_STR_INIT;
char orig_head_str[GIT_OID_SHA1_HEXSIZE]; char orig_head_str[GIT_OID_MAX_HEXSIZE];
int error = 0; int error = 0;
git_oid_fmt(orig_head_str, orig_head); git_oid_fmt(orig_head_str, orig_head);
if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 && if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 &&
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 && (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 &&
(error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_SHA1_HEXSIZE, orig_head_str)) == 0) (error = git_filebuf_printf(&file, "%.*s\n", (int)git_oid_hexsize(repo->oid_type), orig_head_str)) == 0)
error = git_filebuf_commit(&file); error = git_filebuf_commit(&file);
if (error < 0) if (error < 0)
...@@ -3042,7 +3147,7 @@ int git_repository_hashfile( ...@@ -3042,7 +3147,7 @@ int git_repository_hashfile(
goto cleanup; goto cleanup;
} }
error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, GIT_OID_SHA1, fl); error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, repo->oid_type, fl);
cleanup: cleanup:
if (fd >= 0) if (fd >= 0)
...@@ -3389,3 +3494,8 @@ int git_repository_submodule_cache_clear(git_repository *repo) ...@@ -3389,3 +3494,8 @@ int git_repository_submodule_cache_clear(git_repository *repo)
repo->submodule_cache = NULL; repo->submodule_cache = NULL;
return error; return error;
} }
git_oid_t git_repository_oid_type(git_repository *repo)
{
return repo ? repo->oid_type : 0;
}
...@@ -153,6 +153,7 @@ struct git_repository { ...@@ -153,6 +153,7 @@ struct git_repository {
unsigned is_bare:1; unsigned is_bare:1;
unsigned is_worktree:1; unsigned is_worktree:1;
git_oid_t oid_type;
unsigned int lru_counter; unsigned int lru_counter;
...@@ -256,4 +257,12 @@ int git_repository__extensions(char ***out, size_t *out_len); ...@@ -256,4 +257,12 @@ int git_repository__extensions(char ***out, size_t *out_len);
int git_repository__set_extensions(const char **extensions, size_t len); int git_repository__set_extensions(const char **extensions, size_t len);
void git_repository__free_extensions(void); void git_repository__free_extensions(void);
/*
* Set the object format (OID type) for a repository; this will set
* both the configuration and the internal value for the oid type.
*/
int git_repository__set_objectformat(
git_repository *repo,
git_oid_t oid_type);
#endif #endif
...@@ -15,21 +15,28 @@ ...@@ -15,21 +15,28 @@
#include "git2.h" #include "git2.h"
static int maybe_sha_or_abbrev(git_object **out, git_repository *repo, const char *spec, size_t speclen) static int maybe_sha_or_abbrev(
git_object **out,
git_repository *repo,
const char *spec,
size_t speclen)
{ {
git_oid oid; git_oid oid;
if (git_oid__fromstrn(&oid, spec, speclen, GIT_OID_SHA1) < 0) if (git_oid__fromstrn(&oid, spec, speclen, repo->oid_type) < 0)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJECT_ANY); return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJECT_ANY);
} }
static int maybe_sha(git_object **out, git_repository *repo, const char *spec) static int maybe_sha(
git_object **out,
git_repository *repo,
const char *spec)
{ {
size_t speclen = strlen(spec); size_t speclen = strlen(spec);
if (speclen != GIT_OID_SHA1_HEXSIZE) if (speclen != git_oid_hexsize(repo->oid_type))
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
return maybe_sha_or_abbrev(out, repo, spec, speclen); return maybe_sha_or_abbrev(out, repo, spec, speclen);
...@@ -110,8 +117,8 @@ static int revparse_lookup_object( ...@@ -110,8 +117,8 @@ static int revparse_lookup_object(
if (error != GIT_ENOTFOUND) if (error != GIT_ENOTFOUND)
return error; return error;
if ((strlen(spec) < GIT_OID_SHA1_HEXSIZE) && if ((strlen(spec) < git_oid_hexsize(repo->oid_type)) &&
((error = maybe_abbrev(object_out, repo, spec)) != GIT_ENOTFOUND)) ((error = maybe_abbrev(object_out, repo, spec)) != GIT_ENOTFOUND))
return error; return error;
if ((error = maybe_describe(object_out, repo, spec)) != GIT_ENOTFOUND) if ((error = maybe_describe(object_out, repo, spec)) != GIT_ENOTFOUND)
......
...@@ -135,9 +135,11 @@ static ssize_t socket_write(git_stream *stream, const char *data, size_t len, in ...@@ -135,9 +135,11 @@ static ssize_t socket_write(git_stream *stream, const char *data, size_t len, in
git_socket_stream *st = (git_socket_stream *) stream; git_socket_stream *st = (git_socket_stream *) stream;
ssize_t written; ssize_t written;
assert(flags == 0);
errno = 0; errno = 0;
if ((written = p_send(st->s, data, len, flags)) < 0) { if ((written = p_send(st->s, data, len, 0)) < 0) {
net_set_error("error sending data"); net_set_error("error sending data");
return -1; return -1;
} }
......
...@@ -65,7 +65,11 @@ static int tag_error(const char *str) ...@@ -65,7 +65,11 @@ static int tag_error(const char *str)
return GIT_EINVALID; return GIT_EINVALID;
} }
static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) static int tag_parse(
git_tag *tag,
const char *buffer,
const char *buffer_end,
git_oid_t oid_type)
{ {
static const char *tag_types[] = { static const char *tag_types[] = {
NULL, "commit\n", "tree\n", "blob\n", "tag\n" NULL, "commit\n", "tree\n", "blob\n", "tag\n"
...@@ -76,7 +80,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) ...@@ -76,7 +80,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
int error; int error;
if (git_object__parse_oid_header(&tag->target, if (git_object__parse_oid_header(&tag->target,
&buffer, buffer_end, "object ", GIT_OID_SHA1) < 0) &buffer, buffer_end, "object ", oid_type) < 0)
return tag_error("object field invalid"); return tag_error("object field invalid");
if (buffer + 5 >= buffer_end) if (buffer + 5 >= buffer_end)
...@@ -161,18 +165,25 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) ...@@ -161,18 +165,25 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
return 0; return 0;
} }
int git_tag__parse_raw(void *_tag, const char *data, size_t size) int git_tag__parse_raw(
void *_tag,
const char *data,
size_t size,
git_oid_t oid_type)
{ {
return tag_parse(_tag, data, data + size); return tag_parse(_tag, data, data + size, oid_type);
} }
int git_tag__parse(void *_tag, git_odb_object *odb_obj) int git_tag__parse(
void *_tag,
git_odb_object *odb_obj,
git_oid_t oid_type)
{ {
git_tag *tag = _tag; git_tag *tag = _tag;
const char *buffer = git_odb_object_data(odb_obj); const char *buffer = git_odb_object_data(odb_obj);
const char *buffer_end = buffer + git_odb_object_size(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj);
return tag_parse(tag, buffer, buffer_end); return tag_parse(tag, buffer, buffer_end, oid_type);
} }
static int retrieve_tag_reference( static int retrieve_tag_reference(
...@@ -374,7 +385,7 @@ int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *b ...@@ -374,7 +385,7 @@ int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *b
return -1; return -1;
/* validate the buffer */ /* validate the buffer */
if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) if (tag_parse(&tag, buffer, buffer + strlen(buffer), repo->oid_type) < 0)
return -1; return -1;
/* validate the target */ /* validate the target */
......
...@@ -25,7 +25,7 @@ struct git_tag { ...@@ -25,7 +25,7 @@ struct git_tag {
}; };
void git_tag__free(void *tag); void git_tag__free(void *tag);
int git_tag__parse(void *tag, git_odb_object *obj); int git_tag__parse(void *tag, git_odb_object *obj, git_oid_t oid_type);
int git_tag__parse_raw(void *tag, const char *data, size_t size); int git_tag__parse_raw(void *tag, const char *data, size_t size, git_oid_t oid_type);
#endif #endif
...@@ -266,6 +266,17 @@ static int local_capabilities(unsigned int *capabilities, git_transport *transpo ...@@ -266,6 +266,17 @@ static int local_capabilities(unsigned int *capabilities, git_transport *transpo
return 0; return 0;
} }
#ifdef GIT_EXPERIMENTAL_SHA256
static int local_oid_type(git_oid_t *out, git_transport *transport)
{
transport_local *t = (transport_local *)transport;
*out = t->repo->oid_type;
return 0;
}
#endif
static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport) static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport)
{ {
transport_local *t = (transport_local *)transport; transport_local *t = (transport_local *)transport;
...@@ -732,6 +743,9 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param) ...@@ -732,6 +743,9 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
t->parent.connect = local_connect; t->parent.connect = local_connect;
t->parent.set_connect_opts = local_set_connect_opts; t->parent.set_connect_opts = local_set_connect_opts;
t->parent.capabilities = local_capabilities; t->parent.capabilities = local_capabilities;
#ifdef GIT_EXPERIMENTAL_SHA256
t->parent.oid_type = local_oid_type;
#endif
t->parent.negotiate_fetch = local_negotiate_fetch; t->parent.negotiate_fetch = local_negotiate_fetch;
t->parent.download_pack = local_download_pack; t->parent.download_pack = local_download_pack;
t->parent.push = local_push; t->parent.push = local_push;
......
...@@ -54,6 +54,12 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp ...@@ -54,6 +54,12 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp
return -1; return -1;
} }
git__free(t->caps.object_format);
t->caps.object_format = NULL;
git__free(t->caps.agent);
t->caps.agent = NULL;
return 0; return 0;
} }
...@@ -242,6 +248,30 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr ...@@ -242,6 +248,30 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr
return 0; return 0;
} }
#ifdef GIT_EXPERIMENTAL_SHA256
static int git_smart__oid_type(git_oid_t *out, git_transport *transport)
{
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
*out = 0;
if (t->caps.object_format == NULL) {
*out = GIT_OID_DEFAULT;
} else {
*out = git_oid_type_fromstr(t->caps.object_format);
if (!*out) {
git_error_set(GIT_ERROR_INVALID,
"unknown object format '%s'",
t->caps.object_format);
return -1;
}
}
return 0;
}
#endif
static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport) static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport)
{ {
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
...@@ -386,6 +416,8 @@ static void git_smart__free(git_transport *transport) ...@@ -386,6 +416,8 @@ static void git_smart__free(git_transport *transport)
git_remote_connect_options_dispose(&t->connect_opts); git_remote_connect_options_dispose(&t->connect_opts);
git__free(t->caps.object_format);
git__free(t->caps.agent);
git__free(t); git__free(t);
} }
...@@ -452,6 +484,9 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) ...@@ -452,6 +484,9 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
t->parent.connect = git_smart__connect; t->parent.connect = git_smart__connect;
t->parent.set_connect_opts = git_smart__set_connect_opts; t->parent.set_connect_opts = git_smart__set_connect_opts;
t->parent.capabilities = git_smart__capabilities; t->parent.capabilities = git_smart__capabilities;
#ifdef GIT_EXPERIMENTAL_SHA256
t->parent.oid_type = git_smart__oid_type;
#endif
t->parent.close = git_smart__close; t->parent.close = git_smart__close;
t->parent.free = git_smart__free; t->parent.free = git_smart__free;
t->parent.negotiate_fetch = git_smart__negotiate_fetch; t->parent.negotiate_fetch = git_smart__negotiate_fetch;
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#define GIT_CAP_SYMREF "symref" #define GIT_CAP_SYMREF "symref"
#define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want" #define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want"
#define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want" #define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want"
#define GIT_CAP_OBJECT_FORMAT "object-format="
#define GIT_CAP_AGENT "agent="
extern bool git_smart__ofs_delta_enabled; extern bool git_smart__ofs_delta_enabled;
...@@ -133,6 +135,8 @@ typedef struct transport_smart_caps { ...@@ -133,6 +135,8 @@ typedef struct transport_smart_caps {
thin_pack:1, thin_pack:1,
want_tip_sha1:1, want_tip_sha1:1,
want_reachable_sha1:1; want_reachable_sha1:1;
char *object_format;
char *agent;
} transport_smart_caps; } transport_smart_caps;
typedef int (*packetsize_cb)(size_t received, void *payload); typedef int (*packetsize_cb)(size_t received, void *payload);
...@@ -182,7 +186,12 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream ...@@ -182,7 +186,12 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
int git_smart__update_heads(transport_smart *t, git_vector *symrefs); int git_smart__update_heads(transport_smart *t, git_vector *symrefs);
/* smart_pkt.c */ /* smart_pkt.c */
int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen); typedef struct {
git_oid_t oid_type;
int seen_capabilities: 1;
} git_pkt_parse_data;
int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen, git_pkt_parse_data *data);
int git_pkt_buffer_flush(git_str *buf); int git_pkt_buffer_flush(git_str *buf);
int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_send_flush(GIT_SOCKET s);
int git_pkt_buffer_done(git_str *buf); int git_pkt_buffer_done(git_str *buf);
......
...@@ -21,11 +21,14 @@ ...@@ -21,11 +21,14 @@
#include <ctype.h> #include <ctype.h>
#define PKT_LEN_SIZE 4 #define PKT_DONE_STR "0009done\n"
static const char pkt_done_str[] = "0009done\n"; #define PKT_FLUSH_STR "0000"
static const char pkt_flush_str[] = "0000"; #define PKT_HAVE_PREFIX "have "
static const char pkt_have_prefix[] = "0032have "; #define PKT_WANT_PREFIX "want "
static const char pkt_want_prefix[] = "0032want ";
#define PKT_LEN_SIZE 4
#define PKT_MAX_SIZE 0xffff
#define PKT_MAX_WANTLEN (PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) + GIT_OID_MAX_HEXSIZE + 1)
static int flush_pkt(git_pkt **out) static int flush_pkt(git_pkt **out)
{ {
...@@ -212,26 +215,87 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) ...@@ -212,26 +215,87 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
return 0; return 0;
} }
static int set_data(
git_pkt_parse_data *data,
const char *line,
size_t len)
{
const char *caps, *format_str = NULL, *eos;
size_t format_len;
git_oid_t remote_oid_type;
GIT_ASSERT_ARG(data);
if ((caps = memchr(line, '\0', len)) != NULL) {
caps++;
if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0)
format_str = caps + CONST_STRLEN("object-format=");
else if ((format_str = strstr(caps, " object-format=")) != NULL)
format_str += CONST_STRLEN(" object-format=");
}
if (format_str) {
if ((eos = strchr(format_str, ' ')) == NULL)
eos = strchr(format_str, '\0');
GIT_ASSERT(eos);
format_len = eos - format_str;
if ((remote_oid_type = git_oid_type_fromstrn(format_str, format_len)) == 0) {
git_error_set(GIT_ERROR_INVALID, "unknown remote object format '%.*s'", (int)format_len, format_str);
return -1;
}
} else {
remote_oid_type = GIT_OID_SHA1;
}
if (!data->oid_type) {
data->oid_type = remote_oid_type;
} else if (data->oid_type != remote_oid_type) {
git_error_set(GIT_ERROR_INVALID,
"the local object format '%s' does not match the remote object format '%s'",
git_oid_type_name(data->oid_type),
git_oid_type_name(remote_oid_type));
return -1;
}
return 0;
}
/* /*
* Parse an other-ref line. * Parse an other-ref line.
*/ */
static int ref_pkt(git_pkt **out, const char *line, size_t len) static int ref_pkt(
git_pkt **out,
const char *line,
size_t len,
git_pkt_parse_data *data)
{ {
git_pkt_ref *pkt; git_pkt_ref *pkt;
size_t alloclen; size_t alloclen, oid_hexsize;
pkt = git__calloc(1, sizeof(git_pkt_ref)); pkt = git__calloc(1, sizeof(git_pkt_ref));
GIT_ERROR_CHECK_ALLOC(pkt); GIT_ERROR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_REF; pkt->type = GIT_PKT_REF;
if (len < GIT_OID_SHA1_HEXSIZE || /* Determine OID type from capabilities */
git_oid__fromstr(&pkt->head.oid, line, GIT_OID_SHA1) < 0) if (!data->seen_capabilities && set_data(data, line, len) < 0)
return -1;
GIT_ASSERT(data->oid_type);
oid_hexsize = git_oid_hexsize(data->oid_type);
if (len < oid_hexsize ||
git_oid__fromstr(&pkt->head.oid, line, data->oid_type) < 0)
goto out_err; goto out_err;
line += GIT_OID_SHA1_HEXSIZE; line += oid_hexsize;
len -= GIT_OID_SHA1_HEXSIZE; len -= oid_hexsize;
if (git__prefixncmp(line, len, " ")) if (git__prefixncmp(line, len, " "))
goto out_err; goto out_err;
line++; line++;
len--; len--;
...@@ -248,8 +312,14 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) ...@@ -248,8 +312,14 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
memcpy(pkt->head.name, line, len); memcpy(pkt->head.name, line, len);
pkt->head.name[len] = '\0'; pkt->head.name[len] = '\0';
if (strlen(pkt->head.name) < len) if (strlen(pkt->head.name) < len) {
pkt->capabilities = strchr(pkt->head.name, '\0') + 1; if (!data->seen_capabilities)
pkt->capabilities = strchr(pkt->head.name, '\0') + 1;
else
goto out_err;
}
data->seen_capabilities = 1;
*out = (git_pkt *)pkt; *out = (git_pkt *)pkt;
return 0; return 0;
...@@ -418,7 +488,11 @@ static int parse_len(size_t *out, const char *line, size_t linelen) ...@@ -418,7 +488,11 @@ static int parse_len(size_t *out, const char *line, size_t linelen)
*/ */
int git_pkt_parse_line( int git_pkt_parse_line(
git_pkt **pkt, const char **endptr, const char *line, size_t linelen) git_pkt **pkt,
const char **endptr,
const char *line,
size_t linelen,
git_pkt_parse_data *data)
{ {
int error; int error;
size_t len; size_t len;
...@@ -493,7 +567,7 @@ int git_pkt_parse_line( ...@@ -493,7 +567,7 @@ int git_pkt_parse_line(
else if (!git__prefixncmp(line, len, "unpack")) else if (!git__prefixncmp(line, len, "unpack"))
error = unpack_pkt(pkt, line, len); error = unpack_pkt(pkt, line, len);
else else
error = ref_pkt(pkt, line, len); error = ref_pkt(pkt, line, len, data);
*endptr = line + len; *endptr = line + len;
...@@ -527,14 +601,21 @@ void git_pkt_free(git_pkt *pkt) ...@@ -527,14 +601,21 @@ void git_pkt_free(git_pkt *pkt)
int git_pkt_buffer_flush(git_str *buf) int git_pkt_buffer_flush(git_str *buf)
{ {
return git_str_put(buf, pkt_flush_str, strlen(pkt_flush_str)); return git_str_put(buf, PKT_FLUSH_STR, CONST_STRLEN(PKT_FLUSH_STR));
} }
static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf) static int buffer_want_with_caps(
const git_remote_head *head,
transport_smart_caps *caps,
git_oid_t oid_type,
git_str *buf)
{ {
git_str str = GIT_STR_INIT; git_str str = GIT_STR_INIT;
char oid[GIT_OID_SHA1_HEXSIZE +1] = {0}; char oid[GIT_OID_MAX_HEXSIZE];
size_t len; size_t oid_hexsize, len;
oid_hexsize = git_oid_hexsize(oid_type);
git_oid_fmt(oid, &head->oid);
/* Prefer multi_ack_detailed */ /* Prefer multi_ack_detailed */
if (caps->multi_ack_detailed) if (caps->multi_ack_detailed)
...@@ -560,19 +641,20 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca ...@@ -560,19 +641,20 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (git_str_oom(&str)) if (git_str_oom(&str))
return -1; return -1;
len = strlen("XXXXwant ") + GIT_OID_SHA1_HEXSIZE + 1 /* NUL */ + if (str.size > (PKT_MAX_SIZE - (PKT_MAX_WANTLEN + 1))) {
git_str_len(&str) + 1 /* LF */;
if (len > 0xffff) {
git_error_set(GIT_ERROR_NET, git_error_set(GIT_ERROR_NET,
"tried to produce packet with invalid length %" PRIuZ, len); "tried to produce packet with invalid caps length %" PRIuZ, str.size);
return -1; return -1;
} }
len = PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) +
oid_hexsize + 1 /* NUL */ +
git_str_len(&str) + 1 /* LF */;
git_str_grow_by(buf, len); git_str_grow_by(buf, len);
git_oid_fmt(oid, &head->oid);
git_str_printf(buf, git_str_printf(buf,
"%04xwant %s %s\n", (unsigned int)len, oid, git_str_cstr(&str)); "%04x%s%.*s %s\n", (unsigned int)len, PKT_WANT_PREFIX,
(int)oid_hexsize, oid, git_str_cstr(&str));
git_str_dispose(&str); git_str_dispose(&str);
GIT_ERROR_CHECK_ALLOC_STR(buf); GIT_ERROR_CHECK_ALLOC_STR(buf);
...@@ -591,8 +673,21 @@ int git_pkt_buffer_wants( ...@@ -591,8 +673,21 @@ int git_pkt_buffer_wants(
transport_smart_caps *caps, transport_smart_caps *caps,
git_str *buf) git_str *buf)
{ {
size_t i = 0;
const git_remote_head *head; const git_remote_head *head;
char oid[GIT_OID_MAX_HEXSIZE];
git_oid_t oid_type;
size_t oid_hexsize, want_len, i = 0;
#ifdef GIT_EXPERIMENTAL_SHA256
oid_type = count > 0 ? refs[0]->oid.type : GIT_OID_SHA1;
#else
oid_type = GIT_OID_SHA1;
#endif
oid_hexsize = git_oid_hexsize(oid_type);
want_len = PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) +
oid_hexsize + 1 /* LF */;
if (caps->common) { if (caps->common) {
for (; i < count; ++i) { for (; i < count; ++i) {
...@@ -601,23 +696,24 @@ int git_pkt_buffer_wants( ...@@ -601,23 +696,24 @@ int git_pkt_buffer_wants(
break; break;
} }
if (buffer_want_with_caps(refs[i], caps, buf) < 0) if (buffer_want_with_caps(refs[i], caps, oid_type, buf) < 0)
return -1; return -1;
i++; i++;
} }
for (; i < count; ++i) { for (; i < count; ++i) {
char oid[GIT_OID_SHA1_HEXSIZE];
head = refs[i]; head = refs[i];
if (head->local) if (head->local)
continue; continue;
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix));
git_str_put(buf, oid, GIT_OID_SHA1_HEXSIZE); git_str_printf(buf, "%04x%s%.*s\n",
git_str_putc(buf, '\n'); (unsigned int)want_len, PKT_WANT_PREFIX,
(int)oid_hexsize, oid);
if (git_str_oom(buf)) if (git_str_oom(buf))
return -1; return -1;
} }
...@@ -627,14 +723,27 @@ int git_pkt_buffer_wants( ...@@ -627,14 +723,27 @@ int git_pkt_buffer_wants(
int git_pkt_buffer_have(git_oid *oid, git_str *buf) int git_pkt_buffer_have(git_oid *oid, git_str *buf)
{ {
char oidhex[GIT_OID_SHA1_HEXSIZE + 1]; char oid_str[GIT_OID_MAX_HEXSIZE];
git_oid_t oid_type;
memset(oidhex, 0x0, sizeof(oidhex)); size_t oid_hexsize, have_len;
git_oid_fmt(oidhex, oid);
return git_str_printf(buf, "%s%s\n", pkt_have_prefix, oidhex); #ifdef GIT_EXPERIMENTAL_SHA256
oid_type = oid->type;
#else
oid_type = GIT_OID_SHA1;
#endif
oid_hexsize = git_oid_hexsize(oid_type);
have_len = PKT_LEN_SIZE + CONST_STRLEN(PKT_HAVE_PREFIX) +
oid_hexsize + 1 /* LF */;
git_oid_fmt(oid_str, oid);
return git_str_printf(buf, "%04x%s%.*s\n",
(unsigned int)have_len, PKT_HAVE_PREFIX,
(int)oid_hexsize, oid_str);
} }
int git_pkt_buffer_done(git_str *buf) int git_pkt_buffer_done(git_str *buf)
{ {
return git_str_puts(buf, pkt_done_str); return git_str_put(buf, PKT_DONE_STR, CONST_STRLEN(PKT_DONE_STR));
} }
...@@ -32,6 +32,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) ...@@ -32,6 +32,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
int error, flush = 0, recvd; int error, flush = 0, recvd;
const char *line_end = NULL; const char *line_end = NULL;
git_pkt *pkt = NULL; git_pkt *pkt = NULL;
git_pkt_parse_data pkt_parse_data = { 0 };
size_t i; size_t i;
/* Clear existing refs in case git_remote_connect() is called again /* Clear existing refs in case git_remote_connect() is called again
...@@ -45,7 +46,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) ...@@ -45,7 +46,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
do { do {
if (buf->offset > 0) if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset); error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset, &pkt_parse_data);
else else
error = GIT_EBUFS; error = GIT_EBUFS;
...@@ -133,9 +134,12 @@ on_invalid: ...@@ -133,9 +134,12 @@ on_invalid:
return -1; return -1;
} }
int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs) int git_smart__detect_caps(
git_pkt_ref *pkt,
transport_smart_caps *caps,
git_vector *symrefs)
{ {
const char *ptr; const char *ptr, *start;
/* No refs or capabilities, odd but not a problem */ /* No refs or capabilities, odd but not a problem */
if (pkt == NULL || pkt->capabilities == NULL) if (pkt == NULL || pkt->capabilities == NULL)
...@@ -217,6 +221,28 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec ...@@ -217,6 +221,28 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
continue; continue;
} }
if (!git__prefixcmp(ptr, GIT_CAP_OBJECT_FORMAT)) {
ptr += strlen(GIT_CAP_OBJECT_FORMAT);
start = ptr;
ptr = strchr(ptr, ' ');
if ((caps->object_format = git__strndup(start, (ptr - start))) == NULL)
return -1;
continue;
}
if (!git__prefixcmp(ptr, GIT_CAP_AGENT)) {
ptr += strlen(GIT_CAP_AGENT);
start = ptr;
ptr = strchr(ptr, ' ');
if ((caps->agent = git__strndup(start, (ptr - start))) == NULL)
return -1;
continue;
}
/* We don't know this capability, so skip it */ /* We don't know this capability, so skip it */
ptr = strchr(ptr, ' '); ptr = strchr(ptr, ' ');
} }
...@@ -228,11 +254,12 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf ...@@ -228,11 +254,12 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf
{ {
const char *ptr = buf->data, *line_end = ptr; const char *ptr = buf->data, *line_end = ptr;
git_pkt *pkt = NULL; git_pkt *pkt = NULL;
git_pkt_parse_data pkt_parse_data = { 0 };
int error = 0, ret; int error = 0, ret;
do { do {
if (buf->offset > 0) if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset); error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data);
else else
error = GIT_EBUFS; error = GIT_EBUFS;
...@@ -723,6 +750,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) ...@@ -723,6 +750,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_str *data_pkt_buf) static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_str *data_pkt_buf)
{ {
git_pkt *pkt; git_pkt *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
const char *line, *line_end = NULL; const char *line, *line_end = NULL;
size_t line_len; size_t line_len;
int error; int error;
...@@ -741,7 +769,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, ...@@ -741,7 +769,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
} }
while (line_len > 0) { while (line_len > 0) {
error = git_pkt_parse_line(&pkt, &line_end, line, line_len); error = git_pkt_parse_line(&pkt, &line_end, line, line_len, &pkt_parse_data);
if (error == GIT_EBUFS) { if (error == GIT_EBUFS) {
/* Buffer the data when the inner packet is split /* Buffer the data when the inner packet is split
...@@ -777,6 +805,7 @@ done: ...@@ -777,6 +805,7 @@ done:
static int parse_report(transport_smart *transport, git_push *push) static int parse_report(transport_smart *transport, git_push *push)
{ {
git_pkt *pkt = NULL; git_pkt *pkt = NULL;
git_pkt_parse_data pkt_parse_data = { 0 };
const char *line_end = NULL; const char *line_end = NULL;
gitno_buffer *buf = &transport->buffer; gitno_buffer *buf = &transport->buffer;
int error, recvd; int error, recvd;
...@@ -785,7 +814,8 @@ static int parse_report(transport_smart *transport, git_push *push) ...@@ -785,7 +814,8 @@ static int parse_report(transport_smart *transport, git_push *push)
for (;;) { for (;;) {
if (buf->offset > 0) if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, &line_end, error = git_pkt_parse_line(&pkt, &line_end,
buf->data, buf->offset); buf->data, buf->offset,
&pkt_parse_data);
else else
error = GIT_EBUFS; error = GIT_EBUFS;
......
...@@ -85,11 +85,17 @@ static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, co ...@@ -85,11 +85,17 @@ static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, co
char *filename_ptr; char *filename_ptr;
size_t tree_len; size_t tree_len;
#ifdef GIT_EXPERIMENTAL_SHA256
size_t oid_size = git_oid_size(id->type);
#else
size_t oid_size = GIT_OID_SHA1_SIZE;
#endif
TREE_ENTRY_CHECK_NAMELEN(filename_len); TREE_ENTRY_CHECK_NAMELEN(filename_len);
if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_SHA1_SIZE)) GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, oid_size))
return NULL; return NULL;
entry = git__calloc(1, tree_len); entry = git__calloc(1, tree_len);
...@@ -383,11 +389,12 @@ static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, ...@@ -383,11 +389,12 @@ static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len,
return 0; return 0;
} }
int git_tree__parse_raw(void *_tree, const char *data, size_t size) int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oid_type)
{ {
git_tree *tree = _tree; git_tree *tree = _tree;
const char *buffer; const char *buffer;
const char *buffer_end; const char *buffer_end;
const long oid_size = (long)git_oid_size(oid_type);
buffer = data; buffer = data;
buffer_end = buffer + size; buffer_end = buffer + size;
...@@ -414,35 +421,33 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size) ...@@ -414,35 +421,33 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size)
if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX) if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX)
return tree_parse_error("failed to parse tree: can't parse filename", NULL); return tree_parse_error("failed to parse tree: can't parse filename", NULL);
if ((buffer_end - (nul + 1)) < GIT_OID_SHA1_SIZE) if ((buffer_end - (nul + 1)) < (long)oid_size)
return tree_parse_error("failed to parse tree: can't parse OID", NULL); return tree_parse_error("failed to parse tree: can't parse OID", NULL);
/* Allocate the entry */ /* Allocate the entry */
{ entry = git_array_alloc(tree->entries);
entry = git_array_alloc(tree->entries); GIT_ERROR_CHECK_ALLOC(entry);
GIT_ERROR_CHECK_ALLOC(entry);
entry->attr = attr;
entry->filename_len = (uint16_t)filename_len;
entry->filename = buffer;
git_oid__fromraw(&entry->oid, ((unsigned char *) buffer + filename_len + 1), GIT_OID_SHA1);
}
entry->attr = attr;
entry->filename_len = (uint16_t)filename_len;
entry->filename = buffer;
buffer += filename_len + 1; buffer += filename_len + 1;
buffer += GIT_OID_SHA1_SIZE;
git_oid__fromraw(&entry->oid, (unsigned char *)buffer, oid_type);
buffer += oid_size;
} }
return 0; return 0;
} }
int git_tree__parse(void *_tree, git_odb_object *odb_obj) int git_tree__parse(void *_tree, git_odb_object *odb_obj, git_oid_t oid_type)
{ {
git_tree *tree = _tree; git_tree *tree = _tree;
const char *data = git_odb_object_data(odb_obj); const char *data = git_odb_object_data(odb_obj);
size_t size = git_odb_object_size(odb_obj); size_t size = git_odb_object_size(odb_obj);
int error; int error;
if ((error = git_tree__parse_raw(tree, data, size)) < 0 || if ((error = git_tree__parse_raw(tree, data, size, oid_type)) < 0 ||
(error = git_odb_object_dup(&tree->odb_obj, odb_obj)) < 0) (error = git_odb_object_dup(&tree->odb_obj, odb_obj)) < 0)
return error; return error;
...@@ -506,6 +511,7 @@ static int git_treebuilder__write_with_buffer( ...@@ -506,6 +511,7 @@ static int git_treebuilder__write_with_buffer(
git_odb *odb; git_odb *odb;
git_tree_entry *entry; git_tree_entry *entry;
git_vector entries = GIT_VECTOR_INIT; git_vector entries = GIT_VECTOR_INIT;
size_t oid_size = git_oid_size(bld->repo->oid_type);
git_str_clear(buf); git_str_clear(buf);
...@@ -529,7 +535,7 @@ static int git_treebuilder__write_with_buffer( ...@@ -529,7 +535,7 @@ static int git_treebuilder__write_with_buffer(
git_str_printf(buf, "%o ", entry->attr); git_str_printf(buf, "%o ", entry->attr);
git_str_put(buf, entry->filename, entry->filename_len + 1); git_str_put(buf, entry->filename, entry->filename_len + 1);
git_str_put(buf, (char *)entry->oid.id, GIT_OID_SHA1_SIZE); git_str_put(buf, (char *)entry->oid.id, oid_size);
if (git_str_oom(buf)) { if (git_str_oom(buf)) {
error = -1; error = -1;
......
...@@ -41,8 +41,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) ...@@ -41,8 +41,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
} }
void git_tree__free(void *tree); void git_tree__free(void *tree);
int git_tree__parse(void *tree, git_odb_object *obj); int git_tree__parse(void *tree, git_odb_object *obj, git_oid_t oid_type);
int git_tree__parse_raw(void *_tree, const char *data, size_t size); int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oid_type);
/** /**
* Write a tree to the given repository * Write a tree to the given repository
......
...@@ -23,6 +23,8 @@ typedef enum { ...@@ -23,6 +23,8 @@ typedef enum {
GIT_HASH_ALGORITHM_SHA256 GIT_HASH_ALGORITHM_SHA256
} git_hash_algorithm_t; } git_hash_algorithm_t;
#define GIT_HASH_MAX_SIZE GIT_HASH_SHA256_SIZE
typedef struct git_hash_ctx { typedef struct git_hash_ctx {
union { union {
git_hash_sha1_ctx sha1; git_hash_sha1_ctx sha1;
...@@ -45,4 +47,15 @@ int git_hash_vec(unsigned char *out, git_str_vec *vec, size_t n, git_hash_algori ...@@ -45,4 +47,15 @@ int git_hash_vec(unsigned char *out, git_str_vec *vec, size_t n, git_hash_algori
int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len); int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len);
GIT_INLINE(size_t) git_hash_size(git_hash_algorithm_t algorithm) {
switch (algorithm) {
case GIT_HASH_ALGORITHM_SHA1:
return GIT_HASH_SHA1_SIZE;
case GIT_HASH_ALGORITHM_SHA256:
return GIT_HASH_SHA256_SIZE;
default:
return 0;
}
}
#endif #endif
...@@ -477,6 +477,25 @@ int cl_repo_get_bool(git_repository *repo, const char *cfg) ...@@ -477,6 +477,25 @@ int cl_repo_get_bool(git_repository *repo, const char *cfg)
return val; return val;
} }
void cl_repo_set_int(git_repository *repo, const char *cfg, int value)
{
git_config *config;
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_set_int32(config, cfg, value));
git_config_free(config);
}
int cl_repo_get_int(git_repository *repo, const char *cfg)
{
int val = 0;
git_config *config;
cl_git_pass(git_repository_config(&config, repo));
if (git_config_get_int32(&val, config, cfg) < 0)
git_error_clear();
git_config_free(config);
return val;
}
void cl_repo_set_string(git_repository *repo, const char *cfg, const char *value) void cl_repo_set_string(git_repository *repo, const char *cfg, const char *value)
{ {
git_config *config; git_config *config;
......
...@@ -231,6 +231,9 @@ void cl_repo_commit_from_index( ...@@ -231,6 +231,9 @@ void cl_repo_commit_from_index(
void cl_repo_set_bool(git_repository *repo, const char *cfg, int value); void cl_repo_set_bool(git_repository *repo, const char *cfg, int value);
int cl_repo_get_bool(git_repository *repo, const char *cfg); int cl_repo_get_bool(git_repository *repo, const char *cfg);
void cl_repo_set_int(git_repository *repo, const char *cfg, int value);
int cl_repo_get_int(git_repository *repo, const char *cfg);
void cl_repo_set_string(git_repository *repo, const char *cfg, const char *value); void cl_repo_set_string(git_repository *repo, const char *cfg, const char *value);
/* /*
......
...@@ -70,6 +70,7 @@ add_clar_test(libgit2_tests online -v -sonline -xonline::customcert ...@@ -70,6 +70,7 @@ add_clar_test(libgit2_tests online -v -sonline -xonline::customcert
add_clar_test(libgit2_tests online_customcert -v -sonline::customcert) add_clar_test(libgit2_tests online_customcert -v -sonline::customcert)
add_clar_test(libgit2_tests gitdaemon -v -sonline::push) add_clar_test(libgit2_tests gitdaemon -v -sonline::push)
add_clar_test(libgit2_tests gitdaemon_namespace -v -sonline::clone::namespace) add_clar_test(libgit2_tests gitdaemon_namespace -v -sonline::clone::namespace)
add_clar_test(libgit2_tests gitdaemon_sha256 -v -sonline::clone::sha256)
add_clar_test(libgit2_tests ssh -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh -sonline::clone::ssh_auth_methods) add_clar_test(libgit2_tests ssh -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh -sonline::clone::ssh_auth_methods)
add_clar_test(libgit2_tests proxy -v -sonline::clone::proxy) add_clar_test(libgit2_tests proxy -v -sonline::clone::proxy)
add_clar_test(libgit2_tests auth_clone -v -sonline::clone::cred) add_clar_test(libgit2_tests auth_clone -v -sonline::clone::cred)
......
...@@ -287,7 +287,7 @@ static int parse_commit(git_commit **out, const char *buffer) ...@@ -287,7 +287,7 @@ static int parse_commit(git_commit **out, const char *buffer)
fake_odb_object.buffer = (char *)buffer; fake_odb_object.buffer = (char *)buffer;
fake_odb_object.cached.size = strlen(fake_odb_object.buffer); fake_odb_object.cached.size = strlen(fake_odb_object.buffer);
error = git_commit__parse(commit, &fake_odb_object); error = git_commit__parse(commit, &fake_odb_object, GIT_OID_SHA1);
*out = commit; *out = commit;
return error; return error;
......
...@@ -192,3 +192,22 @@ void test_core_oid__fmt_substr_sha1(void) ...@@ -192,3 +192,22 @@ void test_core_oid__fmt_substr_sha1(void)
git_oid_fmt_substr(buf, &id_sha1, 5, 6); git_oid_fmt_substr(buf, &id_sha1, 5, 6);
cl_assert_equal_s(buf, "12eea6"); cl_assert_equal_s(buf, "12eea6");
} }
void test_core_oid__type_lookup(void)
{
cl_assert_equal_i(GIT_OID_SHA1, git_oid_type_fromstr("sha1"));
cl_assert_equal_i(GIT_OID_SHA1, git_oid_type_fromstrn("sha1...", 4));
cl_assert_equal_s("sha1", git_oid_type_name(GIT_OID_SHA1));
#ifdef GIT_EXPERIMENTAL_SHA256
cl_assert_equal_i(GIT_OID_SHA256, git_oid_type_fromstr("sha256"));
cl_assert_equal_i(GIT_OID_SHA256, git_oid_type_fromstrn("sha256...", 6));
cl_assert_equal_s("sha256", git_oid_type_name(GIT_OID_SHA256));
#endif
cl_assert_equal_i(0, git_oid_type_fromstr("sha42"));
cl_assert_equal_i(0, git_oid_type_fromstrn("sha1", 3));
cl_assert_equal_i(0, git_oid_type_fromstrn("sha1...", 5));
cl_assert_equal_s("unknown", git_oid_type_name(0));
cl_assert_equal_s("unknown", git_oid_type_name(42));
}
...@@ -34,8 +34,9 @@ void test_core_opts__extensions_query(void) ...@@ -34,8 +34,9 @@ void test_core_opts__extensions_query(void)
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out));
cl_assert_equal_sz(out.count, 1); cl_assert_equal_sz(out.count, 2);
cl_assert_equal_s("noop", out.strings[0]); cl_assert_equal_s("noop", out.strings[0]);
cl_assert_equal_s("objectformat", out.strings[1]);
git_strarray_dispose(&out); git_strarray_dispose(&out);
} }
...@@ -48,9 +49,10 @@ void test_core_opts__extensions_add(void) ...@@ -48,9 +49,10 @@ void test_core_opts__extensions_add(void)
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in)));
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out));
cl_assert_equal_sz(out.count, 2); cl_assert_equal_sz(out.count, 3);
cl_assert_equal_s("noop", out.strings[0]); cl_assert_equal_s("noop", out.strings[0]);
cl_assert_equal_s("foo", out.strings[1]); cl_assert_equal_s("objectformat", out.strings[1]);
cl_assert_equal_s("foo", out.strings[2]);
git_strarray_dispose(&out); git_strarray_dispose(&out);
} }
...@@ -63,9 +65,10 @@ void test_core_opts__extensions_remove(void) ...@@ -63,9 +65,10 @@ void test_core_opts__extensions_remove(void)
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in)));
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out));
cl_assert_equal_sz(out.count, 2); cl_assert_equal_sz(out.count, 3);
cl_assert_equal_s("bar", out.strings[0]); cl_assert_equal_s("objectformat", out.strings[0]);
cl_assert_equal_s("baz", out.strings[1]); cl_assert_equal_s("bar", out.strings[1]);
cl_assert_equal_s("baz", out.strings[2]);
git_strarray_dispose(&out); git_strarray_dispose(&out);
} }
#include "clar_libgit2.h"
#include "repository.h"
#ifdef GIT_EXPERIMENTAL_SHA256
static git_repository *g_repo;
#endif
void test_object_lookup256__initialize(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
g_repo = cl_git_sandbox_init("testrepo_256.git");
#endif
}
void test_object_lookup256__cleanup(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_sandbox_cleanup();
#endif
}
void test_object_lookup256__lookup_wrong_type_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_TAG));
#endif
}
void test_object_lookup256__lookup_nonexisting_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *unknown = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstr(&oid, unknown, GIT_OID_SHA256));
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_ANY));
#endif
}
void test_object_lookup256__lookup_wrong_type_by_abbreviated_id_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "4d46d97";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstrn(&oid, commit, strlen(commit), GIT_OID_SHA256));
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup_prefix(&object, g_repo, &oid, strlen(commit), GIT_OBJECT_TAG));
#endif
}
void test_object_lookup256__lookup_wrong_type_eventually_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
git_object_free(object);
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_TAG));
#endif
}
void test_object_lookup256__lookup_corrupt_object_returns_error(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "5ca8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848",
*file = "objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848";
git_str path = GIT_STR_INIT, contents = GIT_STR_INIT;
git_oid oid;
git_object *object;
size_t i;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
cl_git_pass(git_str_joinpath(&path, git_repository_path(g_repo), file));
cl_git_pass(git_futils_readbuffer(&contents, path.ptr));
/* Corrupt and try to read the object */
for (i = 0; i < contents.size; i++) {
contents.ptr[i] ^= 0x1;
cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644));
cl_git_fail(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
contents.ptr[i] ^= 0x1;
}
/* Restore original content and assert we can read the object */
cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644));
cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
git_object_free(object);
git_str_dispose(&path);
git_str_dispose(&contents);
#endif
}
void test_object_lookup256__lookup_object_with_wrong_hash_returns_error(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *oldloose = "objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848",
*newloose = "objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26840",
*commit = "5ca8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26840";
git_str oldpath = GIT_STR_INIT, newpath = GIT_STR_INIT;
git_object *object;
git_oid oid;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
/* Copy object to another location with wrong hash */
cl_git_pass(git_str_joinpath(&oldpath, git_repository_path(g_repo), oldloose));
cl_git_pass(git_str_joinpath(&newpath, git_repository_path(g_repo), newloose));
cl_git_pass(git_futils_cp(oldpath.ptr, newpath.ptr, 0644));
/* Verify that lookup fails due to a hashsum mismatch */
cl_git_fail_with(GIT_EMISMATCH, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
/* Disable verification and try again */
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1));
git_object_free(object);
git_str_dispose(&oldpath);
git_str_dispose(&newpath);
#endif
}
...@@ -14,7 +14,7 @@ static void assert_tag_parses(const char *data, size_t datalen, ...@@ -14,7 +14,7 @@ static void assert_tag_parses(const char *data, size_t datalen,
if (!datalen) if (!datalen)
datalen = strlen(data); datalen = strlen(data);
cl_git_pass(git_object__from_raw((git_object **) &tag, data, datalen, GIT_OBJECT_TAG)); cl_git_pass(git_object__from_raw((git_object **) &tag, data, datalen, GIT_OBJECT_TAG, GIT_OID_SHA1));
cl_assert_equal_i(tag->type, GIT_OBJECT_TAG); cl_assert_equal_i(tag->type, GIT_OBJECT_TAG);
if (expected_oid) { if (expected_oid) {
...@@ -54,7 +54,7 @@ static void assert_tag_fails(const char *data, size_t datalen) ...@@ -54,7 +54,7 @@ static void assert_tag_fails(const char *data, size_t datalen)
git_object *object; git_object *object;
if (!datalen) if (!datalen)
datalen = strlen(data); datalen = strlen(data);
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TAG)); cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TAG, GIT_OID_SHA1));
} }
void test_object_tag_parse__valid_tag_parses(void) void test_object_tag_parse__valid_tag_parses(void)
......
...@@ -26,7 +26,7 @@ static void assert_tree_parses(const char *data, size_t datalen, ...@@ -26,7 +26,7 @@ static void assert_tree_parses(const char *data, size_t datalen,
if (!datalen) if (!datalen)
datalen = strlen(data); datalen = strlen(data);
cl_git_pass(git_object__from_raw((git_object **) &tree, data, datalen, GIT_OBJECT_TREE)); cl_git_pass(git_object__from_raw((git_object **) &tree, data, datalen, GIT_OBJECT_TREE, GIT_OID_SHA1));
cl_assert_equal_i(git_tree_entrycount(tree), expected_nentries); cl_assert_equal_i(git_tree_entrycount(tree), expected_nentries);
...@@ -51,7 +51,7 @@ static void assert_tree_fails(const char *data, size_t datalen) ...@@ -51,7 +51,7 @@ static void assert_tree_fails(const char *data, size_t datalen)
git_object *object; git_object *object;
if (!datalen) if (!datalen)
datalen = strlen(data); datalen = strlen(data);
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TREE)); cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TREE, GIT_OID_SHA1));
} }
void test_object_tree_parse__single_blob_parses(void) void test_object_tree_parse__single_blob_parses(void)
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#define VALID_COMMIT "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \ #define VALID_COMMIT_SHA1 \
"parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \ "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
"author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \ "parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \ "author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \
"\n" \ "committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"commit go here.\n" "\n" \
#define VALID_TREE "100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42" "commit go here.\n"
#define INVALID_COMMIT "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \ #define VALID_TREE_SHA1 \
"parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \ "100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \ #define INVALID_COMMIT_SHA1 \
"commit go here.\n" "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
#define INVALID_TREE "100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42" "parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
void test_object_validate__valid(void) "\n" \
"commit go here.\n"
#define INVALID_TREE_SHA1 \
"100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#define VALID_COMMIT_SHA256 \
"tree d0fc7f52dc42358506e7f3f3be72f5271994abb104b9397ab3e19bb42361504d\n" \
"parent 652412419a24ba62a1d897f40aeb80eecbf873797b04a1bbb8d71918653ef65b\n" \
"author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define VALID_TREE_SHA256 \
"100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#define INVALID_COMMIT_SHA256 \
"tree d0fc7f52dc42358506e7f3f3be72f5271994abb104b9397ab3e19bb42361504d\n" \
"parent 652412419a24ba62a1d897f40aeb80eecbf873797b04a1bbb8d71918653ef65b\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define INVALID_TREE_SHA256 \
"100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#ifdef GIT_EXPERIMENTAL_SHA256
# define sha1_rawcontent_is_valid(v, c, l, t) \
git_object_rawcontent_is_valid(v, c, l, t, GIT_OID_SHA1)
#else
# define sha1_rawcontent_is_valid(v, c, l, t) \
git_object_rawcontent_is_valid(v, c, l, t)
#endif
void test_object_validate__valid_sha1(void)
{
int valid;
cl_git_pass(sha1_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB));
cl_assert_equal_i(1, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB));
cl_assert_equal_i(1, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, VALID_COMMIT_SHA1, CONST_STRLEN(VALID_COMMIT_SHA1), GIT_OBJECT_COMMIT));
cl_assert_equal_i(1, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, VALID_TREE_SHA1, CONST_STRLEN(VALID_TREE_SHA1), GIT_OBJECT_TREE));
cl_assert_equal_i(1, valid);
}
void test_object_validate__cannot_parse_sha256_as_sha1(void)
{
int valid;
cl_git_pass(sha1_rawcontent_is_valid(&valid, VALID_COMMIT_SHA256, CONST_STRLEN(INVALID_COMMIT_SHA256), GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, INVALID_TREE_SHA256, CONST_STRLEN(INVALID_TREE_SHA256), GIT_OBJECT_TREE));
cl_assert_equal_i(0, valid);
}
void test_object_validate__invalid_sha1(void)
{ {
int valid; int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB)); cl_git_pass(sha1_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, INVALID_COMMIT_SHA1, CONST_STRLEN(INVALID_COMMIT_SHA1), GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, INVALID_TREE_SHA1, CONST_STRLEN(INVALID_TREE_SHA1), GIT_OBJECT_TREE));
cl_assert_equal_i(0, valid);
}
void test_object_validate__valid_sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB, GIT_OID_SHA256));
cl_assert_equal_i(1, valid); cl_assert_equal_i(1, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB)); cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB, GIT_OID_SHA256));
cl_assert_equal_i(1, valid); cl_assert_equal_i(1, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT, CONST_STRLEN(VALID_COMMIT), GIT_OBJECT_COMMIT)); cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT_SHA256, CONST_STRLEN(VALID_COMMIT_SHA256), GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(1, valid); cl_assert_equal_i(1, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_TREE, CONST_STRLEN(VALID_TREE), GIT_OBJECT_TREE)); cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_TREE_SHA256, CONST_STRLEN(VALID_TREE_SHA256), GIT_OBJECT_TREE, GIT_OID_SHA256));
cl_assert_equal_i(1, valid); cl_assert_equal_i(1, valid);
#endif
} }
void test_object_validate__invalid(void) void test_object_validate__invalid_sha256(void)
{ {
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
int valid; int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT)); cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid); cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT)); cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_COMMIT_SHA256, CONST_STRLEN(INVALID_COMMIT_SHA256), GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid); cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_COMMIT, CONST_STRLEN(INVALID_COMMIT), GIT_OBJECT_COMMIT)); cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE_SHA256, CONST_STRLEN(INVALID_TREE_SHA256), GIT_OBJECT_TREE, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
#endif
}
void test_object_validate__cannot_parse_sha1_as_sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT_SHA1, CONST_STRLEN(INVALID_COMMIT_SHA1), GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid); cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE, CONST_STRLEN(INVALID_TREE), GIT_OBJECT_TREE)); cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE_SHA1, CONST_STRLEN(INVALID_TREE_SHA1), GIT_OBJECT_TREE, GIT_OID_SHA256));
cl_assert_equal_i(0, valid); cl_assert_equal_i(0, valid);
#endif
} }
...@@ -52,7 +52,16 @@ void test_odb_foreach__one_pack(void) ...@@ -52,7 +52,16 @@ void test_odb_foreach__one_pack(void)
int nobj = 0; int nobj = 0;
cl_git_pass(git_odb__new(&_odb, NULL)); cl_git_pass(git_odb__new(&_odb, NULL));
cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_odb_backend_one_pack(&backend,
cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"),
NULL));
#else
cl_git_pass(git_odb_backend_one_pack(&backend,
cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
#endif
cl_git_pass(git_odb_add_backend(_odb, backend, 1)); cl_git_pass(git_odb_add_backend(_odb, backend, 1));
_repo = NULL; _repo = NULL;
......
/* Just a few to make sure it's working, the rest is tested already */
#ifdef GIT_EXPERIMENTAL_SHA256
static const char *packed_objects_one256[] = {
"ea926306b1bab6d3f25f45609907eb6dff91a1460b25e63bf4a0494c70e7a269",
"d048ba2ef4fafa502a44cbc1a50cd58359b9bc243b84a08f541a08ca5f621137",
"a66bda0109d2b3c9bc87970da81bd91076b5f871febbc860f09ae997668b6800",
"3609a41c0506fe19d01fb8b4729923362675f191fe5f63fab3111ef804c48fdf",
"22b6705b86e4aa9120eff203af24709d483698d9f78695e86e82de121784b570",
"6f11d93bfb269ee8c7a506178f60c430abfac5d424acfd9c0b0b27b98e6ab49b",
"0aefd477d9e5b3f8d708a3cf6d78be6b670dfa2e2ec41244634f3b8f115d8e04",
"580474d948cd2ebd2e5ce7a5b81b872d87ba4639c1ac4c0fa7a11a8eddf9827c",
"0636b4292bfdd7274a977cb6f8b2ded8f315ea1bcd8dbedfca37964c2ed3d085",
"19fb1c78b11f0f8bda658d6fa6cc63c0b573c0f6760ee5a9c2df6ce2cde00c5c",
"7f2f7afccb317bb3fdd28555f126846dc4eebe5d9ae7b8d8a1456e8ff85422ce",
"4066249c68b0d3c8b39ebe02c9188935900465acad02a49269710f56720fa58e",
"a560d1fa1edf114f57b402e16d662c17b1e3b7e8601ff7dcea6615ba7f1e48ef",
"58923faa87c7d559d308a114ec2b164e5d6046c889420ed1def6eef2d55106a2",
"753ddabab8ae9c1e733cda15e8e3c83dd43f5a2d939ae32cc3b30b0be1e91f96",
"46333d32b3801cf11d9f80b557245c9e32b0e05deca61dae968914fde159f0e5"
};
#endif
#include "clar_libgit2.h"
#include "odb.h"
#include "pack_data_256.h"
#ifdef GIT_EXPERIMENTAL_SHA256
static git_odb *_odb;
#endif
void test_odb_packed256__initialize(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
git_odb_options opts = GIT_ODB_OPTIONS_INIT;
opts.oid_type = GIT_OID_SHA256;
cl_git_pass(git_odb__open(
&_odb,
cl_fixture("testrepo_256.git/objects"),
&opts));
#endif
}
void test_odb_packed256__cleanup(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
git_odb_free(_odb);
_odb = NULL;
#endif
}
void test_odb_packed256__mass_read(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
unsigned int i;
for (i = 0; i < ARRAY_SIZE(packed_objects_256); ++i) {
git_oid id;
git_odb_object *obj;
cl_git_pass(git_oid__fromstr(&id, packed_objects_256[i], GIT_OID_SHA256));
cl_assert(git_odb_exists(_odb, &id) == 1);
cl_git_pass(git_odb_read(&obj, _odb, &id));
git_odb_object_free(obj);
}
#endif
}
void test_odb_packed256__read_header_0(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
unsigned int i;
for (i = 0; i < ARRAY_SIZE(packed_objects_256); ++i) {
git_oid id;
git_odb_object *obj;
size_t len;
git_object_t type;
cl_git_pass(git_oid__fromstr(&id, packed_objects_256[i], GIT_OID_SHA256));
cl_git_pass(git_odb_read(&obj, _odb, &id));
cl_git_pass(git_odb_read_header(&len, &type, _odb, &id));
cl_assert(obj->cached.size == len);
cl_assert(obj->cached.type == type);
git_odb_object_free(obj);
}
#endif
}
void test_odb_packed256__read_header_1(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
unsigned int i;
for (i = 0; i < ARRAY_SIZE(loose_objects_256); ++i) {
git_oid id;
git_odb_object *obj;
size_t len;
git_object_t type;
cl_git_pass(git_oid__fromstr(&id, loose_objects_256[i], GIT_OID_SHA256));
cl_assert(git_odb_exists(_odb, &id) == 1);
cl_git_pass(git_odb_read(&obj, _odb, &id));
cl_git_pass(git_odb_read_header(&len, &type, _odb, &id));
cl_assert(obj->cached.size == len);
cl_assert(obj->cached.type == type);
git_odb_object_free(obj);
}
#endif
}
...@@ -6,22 +6,29 @@ ...@@ -6,22 +6,29 @@
static git_odb *_odb; static git_odb *_odb;
void test_odb_packed_one__initialize(void) void test_odb_packedone__initialize(void)
{ {
git_odb_backend *backend = NULL; git_odb_backend *backend = NULL;
cl_git_pass(git_odb__new(&_odb, NULL)); cl_git_pass(git_odb__new(&_odb, NULL));
cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"))); #ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_odb_backend_one_pack(&backend,
cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"),
NULL));
#else
cl_git_pass(git_odb_backend_one_pack(&backend,
cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
#endif
cl_git_pass(git_odb_add_backend(_odb, backend, 1)); cl_git_pass(git_odb_add_backend(_odb, backend, 1));
} }
void test_odb_packed_one__cleanup(void) void test_odb_packedone__cleanup(void)
{ {
git_odb_free(_odb); git_odb_free(_odb);
_odb = NULL; _odb = NULL;
} }
void test_odb_packed_one__mass_read(void) void test_odb_packedone__mass_read(void)
{ {
unsigned int i; unsigned int i;
...@@ -37,7 +44,7 @@ void test_odb_packed_one__mass_read(void) ...@@ -37,7 +44,7 @@ void test_odb_packed_one__mass_read(void)
} }
} }
void test_odb_packed_one__read_header_0(void) void test_odb_packedone__read_header_0(void)
{ {
unsigned int i; unsigned int i;
......
#include "clar_libgit2.h"
#include "git2/odb_backend.h"
#include "pack_data_one256.h"
#include "pack.h"
#ifdef GIT_EXPERIMENTAL_SHA256
static git_odb *_odb;
#endif
void test_odb_packedone256__initialize(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
git_odb_backend *backend = NULL;
git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT;
git_odb_backend_pack_options backend_opts = GIT_ODB_BACKEND_PACK_OPTIONS_INIT;
odb_opts.oid_type = GIT_OID_SHA256;
backend_opts.oid_type = GIT_OID_SHA256;
cl_git_pass(git_odb__new(&_odb, &odb_opts));
cl_git_pass(git_odb_backend_one_pack(
&backend,
cl_fixture("testrepo_256.git/objects/pack/pack-e2f07f30db7e480ea84a0e64ee791b9b270067124b2609019b74f33f256f33fa.idx"),
&backend_opts));
cl_git_pass(git_odb_add_backend(_odb, backend, 1));
#endif
}
void test_odb_packedone256__cleanup(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
git_odb_free(_odb);
_odb = NULL;
#endif
}
void test_odb_packedone256__mass_read(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
unsigned int i;
for (i = 0; i < ARRAY_SIZE(packed_objects_one256); ++i) {
git_oid id;
git_odb_object *obj;
cl_git_pass(git_oid__fromstr(&id, packed_objects_one256[i], GIT_OID_SHA256));
cl_assert(git_odb_exists(_odb, &id) == 1);
cl_git_pass(git_odb_read(&obj, _odb, &id));
git_odb_object_free(obj);
}
#endif
}
void test_odb_packedone256__read_header_0(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
unsigned int i;
for (i = 0; i < ARRAY_SIZE(packed_objects_one256); ++i) {
git_oid id;
git_odb_object *obj;
size_t len;
git_object_t type;
cl_git_pass(git_oid__fromstr(&id, packed_objects_one256[i], GIT_OID_SHA256));
cl_git_pass(git_odb_read(&obj, _odb, &id));
cl_git_pass(git_odb_read_header(&len, &type, _odb, &id));
cl_assert(obj->cached.size == len);
cl_assert(obj->cached.type == type);
git_odb_object_free(obj);
}
#endif
}
...@@ -82,7 +82,11 @@ void test_odb_sorting__override_default_backend_priority(void) ...@@ -82,7 +82,11 @@ void test_odb_sorting__override_default_backend_priority(void)
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_LOOSE_PRIORITY, 5)); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_LOOSE_PRIORITY, 5));
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_PACKED_PRIORITY, 3)); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_PACKED_PRIORITY, 3));
git_odb_backend_pack(&packed, "./testrepo.git/objects"); git_odb_backend_pack(&packed, "./testrepo.git/objects"
#ifdef GIT_EXPERIMENTAL_SHA256
, NULL
#endif
);
git_odb__backend_loose(&loose, "./testrepo.git/objects", NULL); git_odb__backend_loose(&loose, "./testrepo.git/objects", NULL);
cl_git_pass(git_odb__open(&new_odb, cl_fixture("testrepo.git/objects"), NULL)); cl_git_pass(git_odb__open(&new_odb, cl_fixture("testrepo.git/objects"), NULL));
......
...@@ -1177,3 +1177,22 @@ void test_online_clone__namespace_with_specified_branch(void) ...@@ -1177,3 +1177,22 @@ void test_online_clone__namespace_with_specified_branch(void)
git_reference_free(head); git_reference_free(head);
} }
void test_online_clone__sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
git_reference *head;
if (!_remote_url)
cl_skip();
cl_git_pass(git_clone(&g_repo, _remote_url, "./sha256", &options));
cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE));
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head));
git_reference_free(head);
#endif
}
...@@ -100,7 +100,12 @@ void test_pack_indexer__out_of_order(void) ...@@ -100,7 +100,12 @@ void test_pack_indexer__out_of_order(void)
git_indexer *idx = 0; git_indexer *idx = 0;
git_indexer_progress stats = { 0 }; git_indexer_progress stats = { 0 };
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, out_of_order_pack, out_of_order_pack_len, &stats)); idx, out_of_order_pack, out_of_order_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats)); cl_git_pass(git_indexer_commit(idx, &stats));
...@@ -117,7 +122,12 @@ void test_pack_indexer__missing_trailer(void) ...@@ -117,7 +122,12 @@ void test_pack_indexer__missing_trailer(void)
git_indexer *idx = 0; git_indexer *idx = 0;
git_indexer_progress stats = { 0 }; git_indexer_progress stats = { 0 };
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, missing_trailer_pack, missing_trailer_pack_len, &stats)); idx, missing_trailer_pack, missing_trailer_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -133,7 +143,12 @@ void test_pack_indexer__leaky(void) ...@@ -133,7 +143,12 @@ void test_pack_indexer__leaky(void)
git_indexer *idx = 0; git_indexer *idx = 0;
git_indexer_progress stats = { 0 }; git_indexer_progress stats = { 0 };
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, leaky_pack, leaky_pack_len, &stats)); idx, leaky_pack, leaky_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -151,6 +166,7 @@ void test_pack_indexer__fix_thin(void) ...@@ -151,6 +166,7 @@ void test_pack_indexer__fix_thin(void)
git_repository *repo; git_repository *repo;
git_odb *odb; git_odb *odb;
git_oid id, should_id; git_oid id, should_id;
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "thin.git", true)); cl_git_pass(git_repository_init(&repo, "thin.git", true));
cl_git_pass(git_repository_odb(&odb, repo)); cl_git_pass(git_repository_odb(&odb, repo));
...@@ -160,7 +176,13 @@ void test_pack_indexer__fix_thin(void) ...@@ -160,7 +176,13 @@ void test_pack_indexer__fix_thin(void)
git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1); git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1);
cl_assert_equal_oid(&should_id, &id); cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL)); #ifdef GIT_EXPERIMENTAL_SHA256
opts.odb = odb;
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, &opts));
#endif
cl_git_pass(git_indexer_append(idx, thin_pack, thin_pack_len, &stats)); cl_git_pass(git_indexer_append(idx, thin_pack, thin_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats)); cl_git_pass(git_indexer_commit(idx, &stats));
...@@ -192,7 +214,12 @@ void test_pack_indexer__fix_thin(void) ...@@ -192,7 +214,12 @@ void test_pack_indexer__fix_thin(void)
cl_git_pass(p_stat(name, &st)); cl_git_pass(p_stat(name, &st));
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
read = p_read(fd, buffer, sizeof(buffer)); read = p_read(fd, buffer, sizeof(buffer));
cl_assert(read != -1); cl_assert(read != -1);
p_close(fd); p_close(fd);
...@@ -216,6 +243,7 @@ void test_pack_indexer__corrupt_length(void) ...@@ -216,6 +243,7 @@ void test_pack_indexer__corrupt_length(void)
git_repository *repo; git_repository *repo;
git_odb *odb; git_odb *odb;
git_oid id, should_id; git_oid id, should_id;
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "thin.git", true)); cl_git_pass(git_repository_init(&repo, "thin.git", true));
cl_git_pass(git_repository_odb(&odb, repo)); cl_git_pass(git_repository_odb(&odb, repo));
...@@ -225,7 +253,13 @@ void test_pack_indexer__corrupt_length(void) ...@@ -225,7 +253,13 @@ void test_pack_indexer__corrupt_length(void)
git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1); git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1);
cl_assert_equal_oid(&should_id, &id); cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL)); #ifdef GIT_EXPERIMENTAL_SHA256
opts.odb = odb;
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, &opts));
#endif
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats)); idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -246,7 +280,12 @@ void test_pack_indexer__incomplete_pack_fails_with_strict(void) ...@@ -246,7 +280,12 @@ void test_pack_indexer__incomplete_pack_fails_with_strict(void)
opts.verify = 1; opts.verify = 1;
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts));
#endif
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, incomplete_pack, incomplete_pack_len, &stats)); idx, incomplete_pack, incomplete_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -266,7 +305,12 @@ void test_pack_indexer__out_of_order_with_connectivity_checks(void) ...@@ -266,7 +305,12 @@ void test_pack_indexer__out_of_order_with_connectivity_checks(void)
opts.verify = 1; opts.verify = 1;
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts));
#endif
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, out_of_order_pack, out_of_order_pack_len, &stats)); idx, out_of_order_pack, out_of_order_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats)); cl_git_pass(git_indexer_commit(idx, &stats));
...@@ -309,7 +353,12 @@ void test_pack_indexer__no_tmp_files(void) ...@@ -309,7 +353,12 @@ void test_pack_indexer__no_tmp_files(void)
git_str_dispose(&path); git_str_dispose(&path);
cl_assert(git_str_len(&first_tmp_file) == 0); cl_assert(git_str_len(&first_tmp_file) == 0);
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
git_indexer_free(idx); git_indexer_free(idx);
cl_git_pass(git_str_sets(&path, clar_sandbox_path())); cl_git_pass(git_str_sets(&path, clar_sandbox_path()));
......
...@@ -104,7 +104,12 @@ void test_pack_packbuilder__create_pack(void) ...@@ -104,7 +104,12 @@ void test_pack_packbuilder__create_pack(void)
seed_packbuilder(); seed_packbuilder();
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&_indexer, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats)); cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats));
cl_git_pass(git_indexer_commit(_indexer, &stats)); cl_git_pass(git_indexer_commit(_indexer, &stats));
...@@ -244,7 +249,13 @@ void test_pack_packbuilder__foreach(void) ...@@ -244,7 +249,13 @@ void test_pack_packbuilder__foreach(void)
git_indexer *idx; git_indexer *idx;
seed_packbuilder(); seed_packbuilder();
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx)); cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx));
cl_git_pass(git_indexer_commit(idx, &_stats)); cl_git_pass(git_indexer_commit(idx, &_stats));
git_indexer_free(idx); git_indexer_free(idx);
...@@ -262,7 +273,13 @@ void test_pack_packbuilder__foreach_with_cancel(void) ...@@ -262,7 +273,13 @@ void test_pack_packbuilder__foreach_with_cancel(void)
git_indexer *idx; git_indexer *idx;
seed_packbuilder(); seed_packbuilder();
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_fail_with( cl_git_fail_with(
git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111); git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111);
git_indexer_free(idx); git_indexer_free(idx);
......
...@@ -142,27 +142,46 @@ void test_repo_init__reinit_bare_repo(void) ...@@ -142,27 +142,46 @@ void test_repo_init__reinit_bare_repo(void)
cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1)); cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
} }
void test_repo_init__reinit_too_recent_bare_repo(void) void test_repo_init__reinit_nondefault_version(void)
{ {
git_config *config; git_config *config;
cl_set_cleanup(&cleanup_repository, "reinit.git");
/* Initialize the repository */ /* Initialize the repository */
cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1)); cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
git_repository_config(&config, g_repo); git_repository_config(&config, g_repo);
/* Set the config to a supported but not default version */
cl_repo_set_string(g_repo, "core.repositoryformatversion", "1");
git_config_free(config);
git_repository_free(g_repo);
g_repo = NULL;
/* Try to reinitialize the repository */
cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
cl_assert_equal_i(1, cl_repo_get_int(g_repo, "core.repositoryformatversion"));
cl_fixture_cleanup("reinit.git");
}
void test_repo_init__reinit_unsupported_version(void)
{
cl_set_cleanup(&cleanup_repository, "reinit.git");
/* Initialize the repository */
cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
/* /*
* Hack the config of the repository to make it look like it has * Hack the config of the repository to make it look like it has
* been created by a recenter version of git/libgit2 * been created by a too new and unsupported version of git/libgit2
*/ */
cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 42)); cl_repo_set_string(g_repo, "core.repositoryformatversion", "42");
git_config_free(config);
git_repository_free(g_repo); git_repository_free(g_repo);
g_repo = NULL; g_repo = NULL;
/* Try to reinitialize the repository */ /* Try and fail to reinitialize the repository */
cl_git_fail(git_repository_init(&g_repo, "reinit.git", 1)); cl_git_fail(git_repository_init(&g_repo, "reinit.git", 1));
cl_fixture_cleanup("reinit.git"); cl_fixture_cleanup("reinit.git");
} }
...@@ -708,7 +727,7 @@ void test_repo_init__defaultbranch_config_empty(void) ...@@ -708,7 +727,7 @@ void test_repo_init__defaultbranch_config_empty(void)
void test_repo_init__longpath(void) void test_repo_init__longpath(void)
{ {
#ifdef GIT_WIN32 #ifdef GIT_WIN32
size_t padding = CONST_STRLEN("objects/pack/pack-.pack.lock") + GIT_OID_SHA1_HEXSIZE; size_t padding = CONST_STRLEN("objects/pack/pack-.pack.lock") + GIT_OID_MAX_HEXSIZE;
size_t max, i; size_t max, i;
git_str path = GIT_STR_INIT; git_str path = GIT_STR_INIT;
git_repository *one = NULL, *two = NULL; git_repository *one = NULL, *two = NULL;
......
#include "clar_libgit2.h"
#include "futils.h"
#include "sysdir.h"
#include "repository.h"
#include <ctype.h>
git_repository *repo;
git_config *config;
void test_repo_objectformat__initialize(void)
{
repo = cl_git_sandbox_init("empty_bare.git");
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
}
void test_repo_objectformat__cleanup(void)
{
git_config_free(config);
cl_git_sandbox_cleanup();
}
void test_repo_objectformat__unspecified(void)
{
git_repository *other;
cl_git_pass(git_repository_open(&other, "empty_bare.git"));
cl_assert_equal_i(GIT_OID_SHA1, git_repository_oid_type(other));
git_repository_free(other);
}
void test_repo_objectformat__sha1(void)
{
git_repository *other;
cl_git_pass(git_config_set_string(config, "extensions.objectformat", "sha1"));
cl_git_pass(git_repository_open(&other, "empty_bare.git"));
cl_assert_equal_i(GIT_OID_SHA1, git_repository_oid_type(other));
git_repository_free(other);
}
void test_repo_objectformat__sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
git_repository *other;
cl_git_pass(git_config_set_string(config, "extensions.objectformat", "sha256"));
cl_git_pass(git_repository_open(&other, "empty_bare.git"));
cl_assert_equal_i(GIT_OID_SHA256, git_repository_oid_type(other));
git_repository_free(other);
#endif
}
void test_repo_objectformat__invalid(void)
{
git_repository *other;
cl_git_pass(git_config_set_string(config, "extensions.objectformat", "bogus"));
cl_git_fail_with(GIT_EINVALID, git_repository_open(&other, "empty_bare.git"));
cl_assert_equal_s("unknown object format 'bogus'", git_error_last()->message);
git_repository_free(other);
}
...@@ -11,8 +11,9 @@ static void assert_flush_parses(const char *line) ...@@ -11,8 +11,9 @@ static void assert_flush_parses(const char *line)
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt *pkt; git_pkt *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_FLUSH); cl_assert_equal_i(pkt->type, GIT_PKT_FLUSH);
cl_assert_equal_strn(endptr, line + 4, linelen - 4); cl_assert_equal_strn(endptr, line + 4, linelen - 4);
...@@ -24,8 +25,9 @@ static void assert_data_pkt_parses(const char *line, const char *expected_data, ...@@ -24,8 +25,9 @@ static void assert_data_pkt_parses(const char *line, const char *expected_data,
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_data *pkt; git_pkt_data *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_DATA); cl_assert_equal_i(pkt->type, GIT_PKT_DATA);
cl_assert_equal_i(pkt->len, expected_len); cl_assert_equal_i(pkt->len, expected_len);
cl_assert_equal_strn(pkt->data, expected_data, expected_len); cl_assert_equal_strn(pkt->data, expected_data, expected_len);
...@@ -38,8 +40,9 @@ static void assert_sideband_progress_parses(const char *line, const char *expect ...@@ -38,8 +40,9 @@ static void assert_sideband_progress_parses(const char *line, const char *expect
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_progress *pkt; git_pkt_progress *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_PROGRESS); cl_assert_equal_i(pkt->type, GIT_PKT_PROGRESS);
cl_assert_equal_i(pkt->len, expected_len); cl_assert_equal_i(pkt->len, expected_len);
cl_assert_equal_strn(pkt->data, expected_data, expected_len); cl_assert_equal_strn(pkt->data, expected_data, expected_len);
...@@ -52,8 +55,9 @@ static void assert_error_parses(const char *line, const char *expected_error, si ...@@ -52,8 +55,9 @@ static void assert_error_parses(const char *line, const char *expected_error, si
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_err *pkt; git_pkt_err *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_ERR); cl_assert_equal_i(pkt->type, GIT_PKT_ERR);
cl_assert_equal_i(pkt->len, expected_len); cl_assert_equal_i(pkt->len, expected_len);
cl_assert_equal_strn(pkt->error, expected_error, expected_len); cl_assert_equal_strn(pkt->error, expected_error, expected_len);
...@@ -67,10 +71,11 @@ static void assert_ack_parses(const char *line, const char *expected_oid, enum g ...@@ -67,10 +71,11 @@ static void assert_ack_parses(const char *line, const char *expected_oid, enum g
const char *endptr; const char *endptr;
git_pkt_ack *pkt; git_pkt_ack *pkt;
git_oid oid; git_oid oid;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1));
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_ACK); cl_assert_equal_i(pkt->type, GIT_PKT_ACK);
cl_assert_equal_oid(&pkt->oid, &oid); cl_assert_equal_oid(&pkt->oid, &oid);
cl_assert_equal_i(pkt->status, expected_status); cl_assert_equal_i(pkt->status, expected_status);
...@@ -83,8 +88,9 @@ static void assert_nak_parses(const char *line) ...@@ -83,8 +88,9 @@ static void assert_nak_parses(const char *line)
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt *pkt; git_pkt *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_NAK); cl_assert_equal_i(pkt->type, GIT_PKT_NAK);
cl_assert_equal_strn(endptr, line + 7, linelen - 7); cl_assert_equal_strn(endptr, line + 7, linelen - 7);
...@@ -96,8 +102,9 @@ static void assert_comment_parses(const char *line, const char *expected_comment ...@@ -96,8 +102,9 @@ static void assert_comment_parses(const char *line, const char *expected_comment
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_comment *pkt; git_pkt_comment *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_COMMENT); cl_assert_equal_i(pkt->type, GIT_PKT_COMMENT);
cl_assert_equal_strn(pkt->comment, expected_comment, strlen(expected_comment)); cl_assert_equal_strn(pkt->comment, expected_comment, strlen(expected_comment));
...@@ -109,8 +116,9 @@ static void assert_ok_parses(const char *line, const char *expected_ref) ...@@ -109,8 +116,9 @@ static void assert_ok_parses(const char *line, const char *expected_ref)
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_ok *pkt; git_pkt_ok *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_OK); cl_assert_equal_i(pkt->type, GIT_PKT_OK);
cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref)); cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref));
...@@ -122,8 +130,9 @@ static void assert_unpack_parses(const char *line, bool ok) ...@@ -122,8 +130,9 @@ static void assert_unpack_parses(const char *line, bool ok)
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_unpack *pkt; git_pkt_unpack *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_UNPACK); cl_assert_equal_i(pkt->type, GIT_PKT_UNPACK);
cl_assert_equal_i(pkt->unpack_ok, ok); cl_assert_equal_i(pkt->unpack_ok, ok);
...@@ -135,8 +144,9 @@ static void assert_ng_parses(const char *line, const char *expected_ref, const c ...@@ -135,8 +144,9 @@ static void assert_ng_parses(const char *line, const char *expected_ref, const c
size_t linelen = strlen(line) + 1; size_t linelen = strlen(line) + 1;
const char *endptr; const char *endptr;
git_pkt_ng *pkt; git_pkt_ng *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_NG); cl_assert_equal_i(pkt->type, GIT_PKT_NG);
cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref)); cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref));
cl_assert_equal_strn(pkt->msg, expected_msg, strlen(expected_msg)); cl_assert_equal_strn(pkt->msg, expected_msg, strlen(expected_msg));
...@@ -153,10 +163,11 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp ...@@ -153,10 +163,11 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp
const char *endptr; const char *endptr;
git_pkt_ref *pkt; git_pkt_ref *pkt;
git_oid oid; git_oid oid;
git_pkt_parse_data pkt_parse_data = { 0 };
cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1));
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_REF); cl_assert_equal_i(pkt->type, GIT_PKT_REF);
cl_assert_equal_oid(&pkt->head.oid, &oid); cl_assert_equal_oid(&pkt->head.oid, &oid);
cl_assert_equal_strn(pkt->head.name, expected_ref, strlen(expected_ref)); cl_assert_equal_strn(pkt->head.name, expected_ref, strlen(expected_ref));
...@@ -171,8 +182,10 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp ...@@ -171,8 +182,10 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp
static void assert_pkt_fails(const char *line) static void assert_pkt_fails(const char *line)
{ {
const char *endptr; const char *endptr;
git_pkt_parse_data pkt_parse_data = { 0 };
git_pkt *pkt; git_pkt *pkt;
cl_git_fail(git_pkt_parse_line(&pkt, &endptr, line, strlen(line) + 1)); cl_git_fail(git_pkt_parse_line(&pkt, &endptr, line, strlen(line) + 1, &pkt_parse_data));
} }
void test_transports_smart_packet__parsing_garbage_fails(void) void test_transports_smart_packet__parsing_garbage_fails(void)
......
decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f branch 'master' of git://example.com/git/testrepo.git
7e9424c06052ca33bfc599bccadee60065d8664a9af7648a1455100c4f772e1c not-for-merge branch 'haacked' of git://example.com/git/testrepo.git
[core]
repositoryFormatVersion = 1
filemode = true
bare = true
ignorecase = true
precomposeunicode = true
[extensions]
objectFormat = sha256
Unnamed repository; edit this file 'description' to name the repository.
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 2) and last update token
# formatted as a string and outputs to stdout a new update token and
# all files that have been modified since the update token. Paths must
# be relative to the root of the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $last_update_token) = @ARGV;
# Uncomment for debugging
# print STDERR "$0 $version $last_update_token\n";
# Check the hook interface version
if ($version ne 2) {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree = get_working_dir();
my $retry = 1;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
launch_watchman();
sub launch_watchman {
my $o = watchman_query();
if (is_work_tree_watched($o)) {
output_result($o->{clock}, @{$o->{files}});
}
}
sub output_result {
my ($clockid, @files) = @_;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# binmode $fh, ":utf8";
# print $fh "$clockid\n@files\n";
# close $fh;
binmode STDOUT, ":utf8";
print $clockid;
print "\0";
local $, = "\0";
print @files;
}
sub watchman_clock {
my $response = qx/watchman clock "$git_work_tree"/;
die "Failed to get clock id on '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
return $json_pkg->new->utf8->decode($response);
}
sub watchman_query {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $last_update_token but not from the .git folder.
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only. Then we're using the "expression" term to
# further constrain the results.
if (substr($last_update_token, 0, 1) eq "c") {
$last_update_token = "\"$last_update_token\"";
}
my $query = <<" END";
["query", "$git_work_tree", {
"since": $last_update_token,
"fields": ["name"],
"expression": ["not", ["dirname", ".git"]]
}]
END
# Uncomment for debugging the watchman query
# open (my $fh, ">", ".git/watchman-query.json");
# print $fh $query;
# close $fh;
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
# Uncomment for debugging the watch response
# open ($fh, ">", ".git/watchman-response.json");
# print $fh $response;
# close $fh;
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
return $json_pkg->new->utf8->decode($response);
}
sub is_work_tree_watched {
my ($output) = @_;
my $error = $output->{error};
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
$retry--;
my $response = qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
$output = $json_pkg->new->utf8->decode($response);
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# close $fh;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
my $o = watchman_clock();
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
output_result($o->{clock}, ("/"));
$last_update_token = $o->{clock};
eval { launch_watchman() };
return 0;
}
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
return 1;
}
sub get_working_dir {
my $working_dir;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$working_dir = Win32::GetCwd();
$working_dir =~ tr/\\/\//;
} else {
require Cwd;
$working_dir = Cwd::cwd();
}
return $working_dir;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment