Unverified Commit deb1ce4c by Edward Thomson Committed by GitHub

Merge pull request #5921 from libgit2/ethomson/1.1.1

Bug fixes for v1.1.1
parents ebe771b3 0cb432ae
......@@ -16,6 +16,7 @@ ELSEIF(USE_HTTPS STREQUAL "OpenSSL")
SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c")
ELSEIF(USE_HTTPS STREQUAL "mbedTLS")
ADD_DEFINITIONS(-DCRYPT_MBEDTLS)
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
SET(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c")
ELSE()
MESSAGE(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${USE_HTTPS}) for NTLM crypto")
......
......@@ -21,40 +21,6 @@
# include <stdbool.h>
#endif
#if defined(_WIN32) || defined(__APPLE__)
/* winsock and macOS > 10.9 have htonll already */
#elif defined(__linux__)
/* See man page endian(3) */
# include <endian.h>
# define htonll htobe64
#elif defined(__NetBSD__) || defined(__OpenBSD__)
/* See man page htobe64(3) */
# include <endian.h>
# define htonll htobe64
#elif defined(__FreeBSD__)
/* See man page bwaps64(9) */
# include <sys/endian.h>
# define htonll htobe64
#elif defined(sun) || defined(__sun)
/* See man page byteorder(3SOCKET) */
# include <sys/types.h>
# include <netinet/in.h>
# include <inttypes.h>
# if !defined(htonll)
# if defined(_BIG_ENDIAN)
# define htonll(x) (x)
# else
# define htonll(x) ((((uint64_t)htonl(x)) << 32) + htonl((uint64_t)(x) >> 32))
# endif
# endif
#elif defined(__HAIKU__)
# include <ByteOrder.h>
# define htonll B_HOST_TO_BENDIAN_INT64
#else
# error "Please implement htonll for your platform"
#endif
#ifndef MIN
# define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
......
......@@ -71,7 +71,7 @@ static inline void HMAC_CTX_free(HMAC_CTX *ctx)
static inline int HMAC_CTX_reset(HMAC_CTX *ctx)
{
HMAC_CTX_cleanup(ctx);
memzero(ctx, sizeof(HMAC_CTX));
ntlm_memzero(ctx, sizeof(HMAC_CTX));
return 1;
}
......
......@@ -132,10 +132,10 @@ int ntlm_client_set_hostname(
static void free_credentials(ntlm_client *ntlm)
{
if (ntlm->password)
memzero(ntlm->password, strlen(ntlm->password));
ntlm_memzero(ntlm->password, strlen(ntlm->password));
if (ntlm->password_utf16)
memzero(ntlm->password_utf16, ntlm->password_utf16_len);
ntlm_memzero(ntlm->password_utf16, ntlm->password_utf16_len);
free(ntlm->username);
free(ntlm->username_upper);
......@@ -1125,7 +1125,7 @@ static bool generate_lm2_response(ntlm_client *ntlm,
size_t lm2_len = 16;
uint64_t local_nonce;
local_nonce = htonll(ntlm->nonce);
local_nonce = ntlm_htonll(ntlm->nonce);
if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) ||
!ntlm_hmac_md5_init(ntlm->hmac_ctx,
......@@ -1197,8 +1197,8 @@ static bool generate_ntlm2_response(ntlm_client *ntlm)
/* the blob's integer values are in network byte order */
signature = htonl(0x01010000);
timestamp = htonll(ntlm->timestamp);
nonce = htonll(ntlm->nonce);
timestamp = ntlm_htonll(ntlm->timestamp);
nonce = ntlm_htonll(ntlm->nonce);
/* construct the blob */
memcpy(&blob[0], &signature, 4);
......
......@@ -8,14 +8,28 @@
#include <stdlib.h>
#include <stdint.h>
#include <arpa/inet.h>
#include "compat.h"
#include "util.h"
void memzero(void *data, size_t size)
void ntlm_memzero(void *data, size_t size)
{
volatile uint8_t *scan = (volatile uint8_t *)data;
while (size--)
*scan++ = 0x0;
}
uint64_t ntlm_htonll(uint64_t value)
{
static union {
uint32_t i;
char c[8];
} test = { 0x01020304 };
if (test.c[0] == 0x01)
return value;
else
return ((uint64_t)htonl(value) << 32) | htonl((uint64_t)value >> 32);
}
......@@ -9,6 +9,7 @@
#ifndef PRIVATE_UTIL_H__
#define PRIVATE_UTIL_H__
extern void memzero(void *data, size_t size);
extern void ntlm_memzero(void *data, size_t size);
extern uint64_t ntlm_htonll(uint64_t value);
#endif /* PRIVATE_UTIL_H__ */
......@@ -100,6 +100,7 @@ GIT_EXTERN(int) git_apply_options_init(git_apply_options *opts, unsigned int ver
* @param preimage the tree to apply the diff to
* @param diff the diff to apply
* @param options the options for the apply (or null for defaults)
* @return 0 or an error code
*/
GIT_EXTERN(int) git_apply_to_tree(
git_index **out,
......@@ -137,6 +138,7 @@ typedef enum {
* @param diff the diff to apply
* @param location the location to apply (workdir, index or both)
* @param options the options for the apply (or null for defaults)
* @return 0 or an error code
*/
GIT_EXTERN(int) git_apply(
git_repository *repo,
......
......@@ -118,6 +118,10 @@ typedef enum {
/**
* The options used when applying filter options to a file.
*
* Initialize with `GIT_BLOB_FILTER_OPTIONS_INIT`. Alternatively, you can
* use `git_blob_filter_options_init`.
*
*/
typedef struct {
int version;
......@@ -130,6 +134,18 @@ typedef struct {
#define GIT_BLOB_FILTER_OPTIONS_INIT {GIT_BLOB_FILTER_OPTIONS_VERSION, GIT_BLOB_FILTER_CHECK_FOR_BINARY}
/**
* Initialize git_blob_filter_options structure
*
* Initializes a `git_blob_filter_options` with default values. Equivalent
* to creating an instance with `GIT_BLOB_FILTER_OPTIONS_INIT`.
*
* @param opts The `git_blob_filter_options` struct to initialize.
* @param version The struct version; pass `GIT_BLOB_FILTER_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_blob_filter_options_init(git_blob_filter_options *opts, unsigned int version);
/**
* Get a buffer with the filtered content of a blob.
*
* This applies filters as if the blob was being checked out to the
......@@ -229,7 +245,7 @@ GIT_EXTERN(int) git_blob_create_from_stream_commit(
* Write an in-memory buffer to the ODB as a blob
*
* @param id return the id of the written blob
* @param repo repository where to blob will be written
* @param repo repository where the blob will be written
* @param buffer data to be written into the blob
* @param len length of the data
* @return 0 or an error code
......
......@@ -356,6 +356,11 @@ typedef enum {
* >
* > - `ciphers` is the list of ciphers that are eanbled.
*
* * opts(GIT_OPT_GET_USER_AGENT, git_buf *out)
*
* > Get the value of the User-Agent header.
* > The User-Agent is written to the `out` buffer.
*
* * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled)
*
* > Enable or disable the use of "offset deltas" when creating packfiles,
......
......@@ -263,7 +263,7 @@ GIT_EXTERN(int) git_config_open_level(
*
* Git allows you to store your global configuration at
* `$HOME/.gitconfig` or `$XDG_CONFIG_HOME/git/config`. For backwards
* compatability, the XDG file shouldn't be used unless the use has
* compatibility, the XDG file shouldn't be used unless the use has
* created it explicitly. With this function you'll open the correct
* one to write to.
*
......
......@@ -998,7 +998,7 @@ GIT_EXTERN(size_t) git_diff_num_deltas(const git_diff *diff);
/**
* Query how many diff deltas are there in a diff filtered by type.
*
* This works just like `git_diff_entrycount()` with an extra parameter
* This works just like `git_diff_num_deltas()` with an extra parameter
* that is a `git_delta_t` and returns just the count of how many deltas
* match that particular type.
*
......
......@@ -349,7 +349,7 @@ GIT_EXTERN(int) git_index_write_tree(git_oid *out, git_index *index);
*
* The index must not contain any file in conflict.
*
* @param out Pointer where to store OID of the the written tree
* @param out Pointer where to store OID of the written tree
* @param index Index to write
* @param repo Repository where to write the tree
* @return 0 on success, GIT_EUNMERGED when the index is not clean
......@@ -702,7 +702,7 @@ GIT_EXTERN(int) git_index_update_all(
* @param at_pos the address to which the position of the index entry is written (optional)
* @param index an existing index object
* @param path path to search
* @return a zero-based position in the index if found; GIT_ENOTFOUND otherwise
* @return 0 with valid value in at_pos; an error code otherwise
*/
GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path);
......
......@@ -51,7 +51,7 @@ typedef struct git_indexer_progress {
* Type for progress callbacks during indexing. Return a value less
* than zero to cancel the indexing or download.
*
* @param stats Structure containing information about the state of the tran sfer
* @param stats Structure containing information about the state of the transfer
* @param payload Payload provided by caller
*/
typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *stats, void *payload);
......@@ -64,6 +64,7 @@ typedef struct git_indexer_options {
/** progress_cb function to call with progress information */
git_indexer_progress_cb progress_cb;
/** progress_cb_payload payload for the progress callback */
void *progress_cb_payload;
......
......@@ -70,7 +70,7 @@ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir);
*
* @param odb database to add the backend to
* @param path path to the objects folder for the alternate
* @return 0 on success; error code otherwise
* @return 0 on success, error code otherwise
*/
GIT_EXTERN(int) git_odb_add_disk_alternate(git_odb *odb, const char *path);
......@@ -94,9 +94,8 @@ GIT_EXTERN(void) git_odb_free(git_odb *db);
* @param out pointer where to store the read object
* @param db database to search for the object in.
* @param id identity of the object to read.
* @return
* - 0 if the object was read;
* - GIT_ENOTFOUND if the object is not in the database.
* @return 0 if the object was read, GIT_ENOTFOUND if the object is
* not in the database.
*/
GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id);
......@@ -122,10 +121,9 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i
* @param db database to search for the object in.
* @param short_id a prefix of the id of the object to read.
* @param len the length of the prefix
* @return
* - 0 if the object was read;
* - GIT_ENOTFOUND if the object is not in the database.
* - GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix)
* @return 0 if the object was read, GIT_ENOTFOUND if the object is not in the
* database. GIT_EAMBIGUOUS if the prefix is ambiguous
* (several objects match the prefix)
*/
GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len);
......@@ -143,9 +141,8 @@ GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git
* @param type_out pointer where to store the type
* @param db database to search for the object in.
* @param id identity of the object to read.
* @return
* - 0 if the object was read;
* - GIT_ENOTFOUND if the object is not in the database.
* @return 0 if the object was read, GIT_ENOTFOUND if the object is not
* in the database.
*/
GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_object_t *type_out, git_odb *db, const git_oid *id);
......@@ -154,9 +151,7 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_object_t *type_out, git
*
* @param db database to be searched for the given object.
* @param id the object to search for.
* @return
* - 1, if the object was found
* - 0, otherwise
* @return 1 if the object was found, 0 otherwise
*/
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
......@@ -305,7 +300,7 @@ GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **out, git_odb *db, git_obje
* @param stream the stream
* @param buffer the data to write
* @param len the buffer's length
* @return 0 if the write succeeded; error code otherwise
* @return 0 if the write succeeded, error code otherwise
*/
GIT_EXTERN(int) git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len);
......@@ -320,7 +315,7 @@ GIT_EXTERN(int) git_odb_stream_write(git_odb_stream *stream, const char *buffer,
*
* @param out pointer to store the resulting object's id
* @param stream the stream
* @return 0 on success; an error code otherwise
* @return 0 on success, an error code otherwise
*/
GIT_EXTERN(int) git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream);
......@@ -362,7 +357,7 @@ GIT_EXTERN(void) git_odb_stream_free(git_odb_stream *stream);
* @param type pointer where to store the type of the object
* @param db object database where the stream will read from
* @param oid oid of the object the stream will read from
* @return 0 if the stream was created; error code otherwise
* @return 0 if the stream was created, error code otherwise
*/
GIT_EXTERN(int) git_odb_open_rstream(
git_odb_stream **out,
......@@ -501,7 +496,7 @@ GIT_EXTERN(git_object_t) git_odb_object_type(git_odb_object *object);
* @param odb database to add the backend to
* @param backend pointer to a git_odb_backend instance
* @param priority Value for ordering the backends queue
* @return 0 on success; error code otherwise
* @return 0 on success, error code otherwise
*/
GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority);
......@@ -522,7 +517,7 @@ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int
* @param odb database to add the backend to
* @param backend pointer to a git_odb_backend instance
* @param priority Value for ordering the backends queue
* @return 0 on success; error code otherwise
* @return 0 on success, error code otherwise
*/
GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority);
......@@ -540,7 +535,7 @@ GIT_EXTERN(size_t) git_odb_num_backends(git_odb *odb);
* @param out output pointer to ODB backend at pos
* @param odb object database
* @param pos index into object database backend list
* @return 0 on success; GIT_ENOTFOUND if pos is invalid; other errors < 0
* @return 0 on success, GIT_ENOTFOUND if pos is invalid, other errors < 0
*/
GIT_EXTERN(int) git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos);
......
......@@ -169,7 +169,7 @@ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repositor
*
* The message for the reflog will be ignored if the reference does
* not belong in the standard set (HEAD, branches and remote-tracking
* branches) and and it does not have a reflog.
* branches) and it does not have a reflog.
*
* @param out Pointer to the newly created reference
* @param repo Repository where that reference will live
......@@ -206,7 +206,7 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo,
*
* The message for the reflog will be ignored if the reference does
* not belong in the standard set (HEAD, branches and remote-tracking
* branches) and and it does not have a reflog.
* branches) and it does not have a reflog.
*
* It will return GIT_EMODIFIED if the reference's value at the time
* of updating does not match the one passed through `current_id`
......@@ -318,7 +318,7 @@ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref);
*
* The message for the reflog will be ignored if the reference does
* not belong in the standard set (HEAD, branches and remote-tracking
* branches) and and it does not have a reflog.
* branches) and it does not have a reflog.
*
* @param out Pointer to the newly created reference
* @param ref The reference
......
......@@ -219,36 +219,54 @@ GIT_EXTERN(int) git_repository_init(
*
* These flags configure extra behaviors to `git_repository_init_ext`.
* In every case, the default behavior is the zero value (i.e. flag is
* not set). Just OR the flag values together for the `flags` parameter
* when initializing a new repo. Details of individual values are:
*
* * BARE - Create a bare repository with no working directory.
* * NO_REINIT - Return an GIT_EEXISTS error if the repo_path appears to
* already be an git repository.
* * NO_DOTGIT_DIR - Normally a "/.git/" will be appended to the repo
* path for non-bare repos (if it is not already there), but
* passing this flag prevents that behavior.
* * MKDIR - Make the repo_path (and workdir_path) as needed. Init is
* always willing to create the ".git" directory even without this
* flag. This flag tells init to create the trailing component of
* the repo and workdir paths as needed.
* * MKPATH - Recursively make all components of the repo and workdir
* paths as necessary.
* * EXTERNAL_TEMPLATE - libgit2 normally uses internal templates to
* initialize a new repo. This flags enables external templates,
* looking the "template_path" from the options if set, or the
* `init.templatedir` global config if not, or falling back on
* "/usr/share/git-core/templates" if it exists.
* * GIT_REPOSITORY_INIT_RELATIVE_GITLINK - If an alternate workdir is
* specified, use relative paths for the gitdir and core.worktree.
* not set). Just OR the flag values together for the `flags` parameter
* when initializing a new repo.
*/
typedef enum {
/**
* Create a bare repository with no working directory.
*/
GIT_REPOSITORY_INIT_BARE = (1u << 0),
/**
* Return an GIT_EEXISTS error if the repo_path appears to already be
* an git repository.
*/
GIT_REPOSITORY_INIT_NO_REINIT = (1u << 1),
/**
* Normally a "/.git/" will be appended to the repo path for
* non-bare repos (if it is not already there), but passing this flag
* prevents that behavior.
*/
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = (1u << 2),
/**
* Make the repo_path (and workdir_path) as needed. Init is always willing
* to create the ".git" directory even without this flag. This flag tells
* init to create the trailing component of the repo and workdir paths
* as needed.
*/
GIT_REPOSITORY_INIT_MKDIR = (1u << 3),
/**
* Recursively make all components of the repo and workdir paths as
* necessary.
*/
GIT_REPOSITORY_INIT_MKPATH = (1u << 4),
/**
* libgit2 normally uses internal templates to initialize a new repo.
* This flags enables external templates, looking the "template_path" from
* the options if set, or the `init.templatedir` global config if not,
* or falling back on "/usr/share/git-core/templates" if it exists.
*/
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = (1u << 5),
/**
* If an alternate workdir is specified, use relative paths for the gitdir
* and core.worktree.
*/
GIT_REPOSITORY_INIT_RELATIVE_GITLINK = (1u << 6),
} git_repository_init_flag_t;
......@@ -257,17 +275,23 @@ typedef enum {
*
* Set the mode field of the `git_repository_init_options` structure
* either to the custom mode that you would like, or to one of the
* following modes:
*
* * SHARED_UMASK - Use permissions configured by umask - the default.
* * SHARED_GROUP - Use "--shared=group" behavior, chmod'ing the new repo
* to be group writable and "g+sx" for sticky group assignment.
* * SHARED_ALL - Use "--shared=all" behavior, adding world readability.
* * Anything else - Set to custom value.
* defined modes.
*/
typedef enum {
/**
* Use permissions configured by umask - the default.
*/
GIT_REPOSITORY_INIT_SHARED_UMASK = 0,
/**
* Use "--shared=group" behavior, chmod'ing the new repo to be group
* writable and "g+sx" for sticky group assignment.
*/
GIT_REPOSITORY_INIT_SHARED_GROUP = 0002775,
/**
* Use "--shared=all" behavior, adding world readability.
*/
GIT_REPOSITORY_INIT_SHARED_ALL = 0002777,
} git_repository_init_mode_t;
......@@ -275,38 +299,57 @@ typedef enum {
* Extended options structure for `git_repository_init_ext`.
*
* This contains extra options for `git_repository_init_ext` that enable
* additional initialization features. The fields are:
*
* * flags - Combination of GIT_REPOSITORY_INIT flags above.
* * mode - Set to one of the standard GIT_REPOSITORY_INIT_SHARED_...
* constants above, or to a custom value that you would like.
* * workdir_path - The path to the working dir or NULL for default (i.e.
* repo_path parent on non-bare repos). IF THIS IS RELATIVE PATH,
* IT WILL BE EVALUATED RELATIVE TO THE REPO_PATH. If this is not
* the "natural" working directory, a .git gitlink file will be
* created here linking to the repo_path.
* * description - If set, this will be used to initialize the "description"
* file in the repository, instead of using the template content.
* * template_path - When GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE is set,
* this contains the path to use for the template directory. If
* this is NULL, the config or default directory options will be
* used instead.
* * initial_head - The name of the head to point HEAD at. If NULL, then
* this will be treated as "master" and the HEAD ref will be set
* to "refs/heads/master". If this begins with "refs/" it will be
* used verbatim; otherwise "refs/heads/" will be prefixed.
* * origin_url - If this is non-NULL, then after the rest of the
* repository initialization is completed, an "origin" remote
* will be added pointing to this URL.
* additional initialization features.
*/
typedef struct {
unsigned int version;
/**
* Combination of GIT_REPOSITORY_INIT flags above.
*/
uint32_t flags;
/**
* Set to one of the standard GIT_REPOSITORY_INIT_SHARED_... constants
* above, or to a custom value that you would like.
*/
uint32_t mode;
/**
* The path to the working dir or NULL for default (i.e. repo_path parent
* on non-bare repos). IF THIS IS RELATIVE PATH, IT WILL BE EVALUATED
* RELATIVE TO THE REPO_PATH. If this is not the "natural" working
* directory, a .git gitlink file will be created here linking to the
* repo_path.
*/
const char *workdir_path;
/**
* If set, this will be used to initialize the "description" file in the
* repository, instead of using the template content.
*/
const char *description;
/**
* When GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE is set, this contains
* the path to use for the template directory. If this is NULL, the config
* or default directory options will be used instead.
*/
const char *template_path;
/**
* The name of the head to point HEAD at. If NULL, then this will be
* treated as "master" and the HEAD ref will be set to "refs/heads/master".
* If this begins with "refs/" it will be used verbatim;
* otherwise "refs/heads/" will be prefixed.
*/
const char *initial_head;
/**
* If this is non-NULL, then after the rest of the repository
* initialization is completed, an "origin" remote will be added
* pointing to this URL.
*/
const char *origin_url;
} git_repository_init_options;
......
......@@ -23,7 +23,7 @@
GIT_BEGIN_DECL
/**
* Callback for messages recieved by the transport.
* Callback for messages received by the transport.
*
* Return a negative value to cancel the network operation.
*
......
......@@ -334,6 +334,7 @@ GIT_EXTERN(int) git_treebuilder_insert(
*
* @param bld Tree builder
* @param filename Filename of the entry to remove
* @return 0 or an error code
*/
GIT_EXTERN(int) git_treebuilder_remove(
git_treebuilder *bld, const char *filename);
......@@ -477,6 +478,7 @@ typedef struct {
* @param baseline the tree to base these changes on
* @param nupdates the number of elements in the update list
* @param updates the list of updates to perform
* @return 0 or an error code
*/
GIT_EXTERN(int) git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates);
......
......@@ -76,6 +76,14 @@ static git_blame_hunk* new_hunk(
return hunk;
}
static void free_hunk(git_blame_hunk *hunk)
{
git__free((void*)hunk->orig_path);
git_signature_free(hunk->final_signature);
git_signature_free(hunk->orig_signature);
git__free(hunk);
}
static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
{
git_blame_hunk *newhunk = new_hunk(
......@@ -90,17 +98,14 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id);
git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id);
newhunk->boundary = hunk->boundary;
git_signature_dup(&newhunk->final_signature, hunk->final_signature);
git_signature_dup(&newhunk->orig_signature, hunk->orig_signature);
return newhunk;
}
static void free_hunk(git_blame_hunk *hunk)
{
git__free((void*)hunk->orig_path);
git_signature_free(hunk->final_signature);
git_signature_free(hunk->orig_signature);
git__free(hunk);
if (git_signature_dup(&newhunk->final_signature, hunk->final_signature) < 0 ||
git_signature_dup(&newhunk->orig_signature, hunk->orig_signature) < 0) {
free_hunk(newhunk);
return NULL;
}
return newhunk;
}
/* Starting with the hunk that includes start_line, shift all following hunks'
......
......@@ -400,6 +400,15 @@ int git_blob_is_binary(const git_blob *blob)
return git_buf_text_is_binary(&content);
}
int git_blob_filter_options_init(
git_blob_filter_options *opts,
unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
git_blob_filter_options, GIT_BLOB_FILTER_OPTIONS_INIT);
return 0;
}
int git_blob_filter(
git_buf *out,
git_blob *blob,
......
......@@ -162,6 +162,37 @@ done:
return error;
}
static int update_remote_head_byname(
git_repository *repo,
const char *remote_name,
const char *tracking_branch_name,
const char *reflog_message)
{
git_buf tracking_head_name = GIT_BUF_INIT;
git_reference *remote_head = NULL;
int error;
if ((error = git_buf_printf(&tracking_head_name,
"%s%s/%s",
GIT_REFS_REMOTES_DIR,
remote_name,
GIT_HEAD_FILE)) < 0)
goto cleanup;
error = git_reference_symbolic_create(
&remote_head,
repo,
git_buf_cstr(&tracking_head_name),
tracking_branch_name,
true,
reflog_message);
cleanup:
git_reference_free(remote_head);
git_buf_dispose(&tracking_head_name);
return error;
}
static int update_remote_head(
git_repository *repo,
git_remote *remote,
......@@ -169,9 +200,7 @@ static int update_remote_head(
const char *reflog_message)
{
git_refspec *refspec;
git_reference *remote_head = NULL;
git_buf remote_head_name = GIT_BUF_INIT;
git_buf remote_branch_name = GIT_BUF_INIT;
git_buf tracking_branch_name = GIT_BUF_INIT;
int error;
/* Determine the remote tracking ref name from the local branch */
......@@ -184,30 +213,19 @@ static int update_remote_head(
}
if ((error = git_refspec_transform(
&remote_branch_name,
&tracking_branch_name,
refspec,
git_buf_cstr(target))) < 0)
goto cleanup;
if ((error = git_buf_printf(&remote_head_name,
"%s%s/%s",
GIT_REFS_REMOTES_DIR,
git_remote_name(remote),
GIT_HEAD_FILE)) < 0)
goto cleanup;
error = git_reference_symbolic_create(
&remote_head,
error = update_remote_head_byname(
repo,
git_buf_cstr(&remote_head_name),
git_buf_cstr(&remote_branch_name),
true,
git_remote_name(remote),
git_buf_cstr(&tracking_branch_name),
reflog_message);
cleanup:
git_reference_free(remote_head);
git_buf_dispose(&remote_branch_name);
git_buf_dispose(&remote_head_name);
git_buf_dispose(&tracking_branch_name);
return error;
}
......@@ -276,8 +294,11 @@ static int update_head_to_branch(
if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
goto cleanup;
retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), branch,
reflog_message);
if ((retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), branch,
reflog_message)) < 0)
goto cleanup;
retcode = update_remote_head_byname(repo, remote_name, remote_branch_name.ptr, reflog_message);
cleanup:
git_reference_free(remote_ref);
......
......@@ -111,9 +111,11 @@ int git_config__configmap_lookup(int *out, git_config *config, git_configmap_ite
int git_repository__configmap_lookup(int *out, git_repository *repo, git_configmap_item item)
{
*out = repo->configmap_cache[(int)item];
intptr_t value = repo->configmap_cache[(int)item];
if (*out == GIT_CONFIGMAP_NOT_CACHED) {
*out = (int)value;
if (value == GIT_CONFIGMAP_NOT_CACHED) {
int error;
git_config *config;
......@@ -121,7 +123,8 @@ int git_repository__configmap_lookup(int *out, git_repository *repo, git_configm
(error = git_config__configmap_lookup(out, config, item)) < 0)
return error;
repo->configmap_cache[(int)item] = *out;
value = *out;
repo->configmap_cache[(int)item] = value;
}
return 0;
......
......@@ -1038,7 +1038,7 @@ find_best_matches:
memcpy(&src->old_file, &swap, sizeof(src->old_file));
/* if we've just swapped the new element into the correct
* place, clear the SPLIT flag
* place, clear the SPLIT and RENAME_TARGET flags
*/
if (tgt2src[s].idx == t &&
tgt2src[s].similarity >
......@@ -1046,7 +1046,7 @@ find_best_matches:
src->status = GIT_DELTA_RENAMED;
src->similarity = tgt2src[s].similarity;
tgt2src[s].similarity = 0;
src->flags &= ~GIT_DIFF_FLAG__TO_SPLIT;
src->flags &= ~(GIT_DIFF_FLAG__TO_SPLIT | GIT_DIFF_FLAG__IS_RENAME_TARGET);
num_rewrites--;
}
/* otherwise, if we just overwrote a source, update mapping */
......
......@@ -2826,14 +2826,16 @@ static int write_entries(git_index *index, git_filebuf *file)
{
int error = 0;
size_t i;
git_vector case_sorted, *entries;
git_vector case_sorted = GIT_VECTOR_INIT, *entries = NULL;
git_index_entry *entry;
const char *last = NULL;
/* If index->entries is sorted case-insensitively, then we need
* to re-sort it case-sensitively before writing */
if (index->ignore_case) {
git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp);
if ((error = git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp)) < 0)
goto done;
git_vector_sort(&case_sorted);
entries = &case_sorted;
} else {
......@@ -2850,9 +2852,8 @@ static int write_entries(git_index *index, git_filebuf *file)
last = entry->path;
}
if (index->ignore_case)
git_vector_free(&case_sorted);
done:
git_vector_free(&case_sorted);
return error;
}
......
......@@ -604,6 +604,23 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
{
#ifdef NO_MMAP
size_t remaining_size = size;
const char *ptr = (const char *)data;
/* Handle data size larger that ssize_t */
while (remaining_size > 0) {
ssize_t nb;
HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr,
remaining_size, offset));
if (nb <= 0)
return -1;
ptr += nb;
offset += nb;
remaining_size -= nb;
}
#else
git_file fd = idx->pack->mwf.fd;
size_t mmap_alignment;
size_t page_offset;
......@@ -627,6 +644,7 @@ static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t s
map_data = (unsigned char *)map.data;
memcpy(map_data + page_offset, data, size);
p_munmap(&map);
#endif
return 0;
}
......@@ -638,7 +656,6 @@ static int append_to_pack(git_indexer *idx, const void *data, size_t size)
size_t page_offset;
off64_t page_start;
off64_t current_size = idx->pack->mwf.size;
int fd = idx->pack->mwf.fd;
int error;
if (!size)
......@@ -655,8 +672,7 @@ static int append_to_pack(git_indexer *idx, const void *data, size_t size)
page_offset = new_size % mmap_alignment;
page_start = new_size - page_offset;
if (p_lseek(fd, page_start + mmap_alignment - 1, SEEK_SET) < 0 ||
p_write(idx->pack->mwf.fd, data, 1) < 0) {
if (p_pwrite(idx->pack->mwf.fd, data, 1, page_start + mmap_alignment - 1) < 0) {
git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name);
return -1;
}
......
......@@ -77,6 +77,9 @@ GIT_INLINE(int) git__is_int(long long p)
# define git__sub_int_overflow(out, one, two) \
__builtin_ssub_overflow(one, two, out)
# define git__add_int64_overflow(out, one, two) \
__builtin_add_overflow(one, two, out)
/* Use Microsoft's safe integer handling functions where available */
#elif defined(_MSC_VER)
......@@ -92,6 +95,9 @@ GIT_INLINE(int) git__is_int(long long p)
#define git__sub_int_overflow(out, one, two) \
(IntSub(one, two, out) != S_OK)
#define git__add_int64_overflow(out, one, two) \
(LongLongAdd(one, two, out) != S_OK)
#else
/**
......@@ -136,6 +142,15 @@ GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two)
return false;
}
GIT_INLINE(bool) git__add_int64_overflow(int64_t *out, int64_t one, int64_t two)
{
if ((two > 0 && one > (INT64_MAX - two)) ||
(two < 0 && one < (INT64_MIN - two)))
return true;
*out = one + two;
return false;
}
#endif
#endif
......@@ -2258,8 +2258,11 @@ static int create_virtual_base(
result->type = GIT_ANNOTATED_COMMIT_VIRTUAL;
result->index = index;
insert_head_ids(&result->parents, one);
insert_head_ids(&result->parents, two);
if (insert_head_ids(&result->parents, one) < 0 ||
insert_head_ids(&result->parents, two) < 0) {
git_annotated_commit_free(result);
return -1;
}
*out = result;
return 0;
......
......@@ -295,8 +295,10 @@ static int git_mwindow_close_lru_file(void)
current_file, &mru_window, NULL, true, GIT_MWINDOW__MRU)) {
continue;
}
if (!lru_window || lru_window->last_used > mru_window->last_used)
if (!lru_window || lru_window->last_used > mru_window->last_used) {
lru_window = mru_window;
lru_file = current_file;
}
}
if (!lru_file) {
......
......@@ -298,14 +298,15 @@ int git_odb__hashlink(git_oid *out, const char *path)
GIT_ERROR_CHECK_ALLOC(link_data);
read_len = p_readlink(path, link_data, size);
link_data[size] = '\0';
if (read_len != size) {
if (read_len == -1) {
git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path);
git__free(link_data);
return -1;
}
GIT_ASSERT(read_len <= size);
link_data[read_len] = '\0';
result = git_odb_hash(out, link_data, size, GIT_OBJECT_BLOB);
result = git_odb_hash(out, link_data, read_len, GIT_OBJECT_BLOB);
git__free(link_data);
} else {
int fd = git_futils_open_ro(path);
......
......@@ -841,7 +841,7 @@ static int packfile_unpack_compressed(
do {
size_t bytes = buffer_len - total;
unsigned int window_len;
unsigned int window_len, consumed;
unsigned char *in;
if ((in = pack_window_open(p, mwindow, *position, &window_len)) == NULL) {
......@@ -857,10 +857,15 @@ static int packfile_unpack_compressed(
git_mwindow_close(mwindow);
if (!bytes)
break;
consumed = window_len - (unsigned int)zstream.in_len;
if (!bytes && !consumed) {
git_error_set(GIT_ERROR_ZLIB, "error inflating zlib stream");
error = -1;
goto out;
}
*position += window_len - zstream.in_len;
*position += consumed;
total += bytes;
} while (!git_zstream_eos(&zstream));
......@@ -1058,8 +1063,7 @@ static int packfile_open(struct git_pack_file *p)
/* Verify the pack matches its index. */
if (p->num_objects != ntohl(hdr.hdr_entries) ||
p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1 ||
p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < 0)
p_pread(p->mwf.fd, sha1.id, GIT_OID_RAWSZ, p->mwf.size - GIT_OID_RAWSZ) < 0)
goto cleanup;
idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
......
......@@ -237,24 +237,43 @@ int git__mmap_alignment(size_t *alignment)
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
{
const char *ptr;
size_t remaining_len;
GIT_MMAP_VALIDATE(out, len, prot, flags);
out->data = NULL;
out->len = 0;
/* writes cannot be emulated without handling pagefaults since write happens by
* writing to mapped memory */
if (prot & GIT_PROT_WRITE) {
git_error_set(GIT_ERROR_OS, "trying to map %s-writeable",
((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) ? "shared": "private");
return -1;
}
if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) {
git_error_set(GIT_ERROR_OS, "trying to map shared-writeable");
if (!git__is_ssizet(len)) {
errno = EINVAL;
return -1;
}
out->len = 0;
out->data = git__malloc(len);
GIT_ERROR_CHECK_ALLOC(out->data);
if (!git__is_ssizet(len) ||
(p_lseek(fd, offset, SEEK_SET) < 0) ||
(p_read(fd, out->data, len) != (ssize_t)len)) {
git_error_set(GIT_ERROR_OS, "mmap emulation failed");
return -1;
remaining_len = len;
ptr = (const char *)out->data;
while (remaining_len > 0) {
ssize_t nb;
HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset));
if (nb <= 0) {
git_error_set(GIT_ERROR_OS, "mmap emulation failed");
git__free(out->data);
out->data = NULL;
return -1;
}
ptr += nb;
offset += nb;
remaining_len -= nb;
}
out->len = len;
......@@ -266,6 +285,10 @@ int p_munmap(git_map *map)
assert(map != NULL);
git__free(map->data);
/* Initializing will help debug use-after-free */
map->len = 0;
map->data = NULL;
return 0;
}
......
......@@ -89,6 +89,12 @@
#define EAFNOSUPPORT (INT_MAX-1)
#endif
/* Compiler independent macro to handle signal interrpted system calls */
#define HANDLE_EINTR(result, x) do { \
result = (x); \
} while (result == -1 && errno == EINTR);
/* Provide a 64-bit size for offsets. */
#if defined(_MSC_VER)
......@@ -119,6 +125,9 @@ typedef int git_file;
extern ssize_t p_read(git_file fd, void *buf, size_t cnt);
extern int p_write(git_file fd, const void *buf, size_t cnt);
extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset);
extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset);
#define p_close(fd) close(fd)
#define p_umask(m) umask(m)
......
......@@ -254,7 +254,8 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0)
goto done;
git_sortedcache_wlock(backend->refcache);
if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
goto done;
if (!(error = git_sortedcache_upsert(
(void **)&ref, backend->refcache, name))) {
......@@ -760,7 +761,8 @@ static int reference_path_available(
}
}
git_sortedcache_rlock(backend->refcache);
if ((error = git_sortedcache_rlock(backend->refcache)) < 0)
return error;
for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
struct packref *ref = git_sortedcache_entry(backend->refcache, i);
......
......@@ -1287,19 +1287,32 @@ cleanup:
return error;
}
int git_reference__is_valid_name(const char *refname, unsigned int flags)
int git_reference__name_is_valid(
int *valid,
const char *refname,
unsigned int flags)
{
if (git_reference__normalize_name(NULL, refname, flags) < 0) {
git_error_clear();
return false;
}
int error;
return true;
*valid = 0;
error = git_reference__normalize_name(NULL, refname, flags);
if (!error)
*valid = 1;
else if (error == GIT_EINVALIDSPEC)
error = 0;
return error;
}
int git_reference_is_valid_name(const char *refname)
{
return git_reference__is_valid_name(refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
int valid = 0;
git_reference__name_is_valid(&valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
return valid;
}
const char *git_reference__shorthand(const char *name)
......
......@@ -85,7 +85,7 @@ git_reference *git_reference__realloc(git_reference **ptr_to_ref, const char *na
int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags);
int git_reference__update_terminal(git_repository *repo, const char *ref_name, const git_oid *oid, const git_signature *sig, const char *log_message);
int git_reference__is_valid_name(const char *refname, unsigned int flags);
int git_reference__name_is_valid(int *valid, const char *name, unsigned int flags);
int git_reference__is_branch(const char *ref_name);
int git_reference__is_remote(const char *ref_name);
int git_reference__is_tag(const char *ref_name);
......
......@@ -21,7 +21,8 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
size_t llen;
int is_glob = 0;
const char *lhs, *rhs;
int flags;
int valid = 0;
unsigned int flags;
assert(refspec && input);
......@@ -75,57 +76,69 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
if (is_fetch) {
/*
* LHS
* - empty is allowed; it means HEAD.
* - otherwise it must be a valid looking ref.
*/
* LHS
* - empty is allowed; it means HEAD.
* - otherwise it must be a valid looking ref.
*/
if (!*refspec->src)
; /* empty is ok */
else if (!git_reference__is_valid_name(refspec->src, flags))
else if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
goto on_error;
else if (!valid)
goto invalid;
/*
* RHS
* - missing is ok, and is same as empty.
* - empty is ok; it means not to store.
* - otherwise it must be a valid looking ref.
*/
* RHS
* - missing is ok, and is same as empty.
* - empty is ok; it means not to store.
* - otherwise it must be a valid looking ref.
*/
if (!refspec->dst)
; /* ok */
else if (!*refspec->dst)
; /* ok */
else if (!git_reference__is_valid_name(refspec->dst, flags))
else if (git_reference__name_is_valid(&valid, refspec->dst, flags) < 0)
goto on_error;
else if (!valid)
goto invalid;
} else {
/*
* LHS
* - empty is allowed; it means delete.
* - when wildcarded, it must be a valid looking ref.
* - otherwise, it must be an extended SHA-1, but
* there is no existing way to validate this.
*/
* LHS
* - empty is allowed; it means delete.
* - when wildcarded, it must be a valid looking ref.
* - otherwise, it must be an extended SHA-1, but
* there is no existing way to validate this.
*/
if (!*refspec->src)
; /* empty is ok */
else if (is_glob) {
if (!git_reference__is_valid_name(refspec->src, flags))
if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
goto on_error;
else if (!valid)
goto invalid;
}
else {
; /* anything goes, for now */
}
/*
* RHS
* - missing is allowed, but LHS then must be a
* valid looking ref.
* - empty is not allowed.
* - otherwise it must be a valid looking ref.
*/
* RHS
* - missing is allowed, but LHS then must be a
* valid looking ref.
* - empty is not allowed.
* - otherwise it must be a valid looking ref.
*/
if (!refspec->dst) {
if (!git_reference__is_valid_name(refspec->src, flags))
if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
goto on_error;
else if (!valid)
goto invalid;
} else if (!*refspec->dst) {
goto invalid;
} else {
if (!git_reference__is_valid_name(refspec->dst, flags))
if (git_reference__name_is_valid(&valid, refspec->dst, flags) < 0)
goto on_error;
else if (!valid)
goto invalid;
}
......@@ -141,11 +154,14 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
return 0;
invalid:
git_error_set(
GIT_ERROR_INVALID,
"'%s' is not a valid refspec.", input);
git_refspec__dispose(refspec);
invalid:
git_error_set(GIT_ERROR_INVALID,
"'%s' is not a valid refspec.", input);
git_refspec__dispose(refspec);
return GIT_EINVALIDSPEC;
on_error:
git_refspec__dispose(refspec);
return -1;
}
......
......@@ -110,12 +110,8 @@ static int write_add_refspec(git_repository *repo, const char *name, const char
if ((error = ensure_remote_name_is_valid(name)) < 0)
return error;
if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
error = GIT_EINVALIDSPEC;
if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0)
return error;
}
git_refspec__dispose(&spec);
......@@ -1116,7 +1112,7 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_re
git_reference *resolved_ref = NULL;
git_buf remote_name = GIT_BUF_INIT;
git_config *config = NULL;
const char *ref_name;
const char *ref_name = NULL;
int error = 0, update;
assert(out && spec && ref);
......@@ -1129,10 +1125,20 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_re
if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
ref_name = git_reference_symbolic_target(ref);
error = 0;
} else {
} else if (resolved_ref) {
ref_name = git_reference_name(resolved_ref);
}
/*
* The ref name may be unresolvable - perhaps it's pointing to
* something invalid. In this case, there is no remote head for
* this ref.
*/
if (!ref_name) {
error = 0;
goto cleanup;
}
if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
goto cleanup;
......
......@@ -2078,7 +2078,8 @@ static int repo_init_head(const char *repo_dir, const char *given)
if (given) {
initial_head = given;
} else if ((error = git_config_open_default(&cfg)) >= 0 &&
(error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0) {
(error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0 &&
*cfg_branch.ptr) {
initial_head = cfg_branch.ptr;
}
......@@ -2334,21 +2335,19 @@ int git_repository_head_unborn(git_repository *repo)
return 0;
}
static int at_least_one_cb(const char *refname, void *payload)
{
GIT_UNUSED(refname);
GIT_UNUSED(payload);
return GIT_PASSTHROUGH;
}
static int repo_contains_no_reference(git_repository *repo)
{
int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
git_reference_iterator *iter;
const char *refname;
int error;
if (error == GIT_PASSTHROUGH)
return 0;
if ((error = git_reference_iterator_new(&iter, repo)) < 0)
return error;
if (!error)
error = git_reference_next_name(&refname, iter);
git_reference_iterator_free(iter);
if (error == GIT_ITEROVER)
return 1;
return error;
......@@ -2364,10 +2363,11 @@ int git_repository_initialbranch(git_buf *out, git_repository *repo)
if ((error = git_repository_config__weakptr(&config, repo)) < 0)
return error;
if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0) {
if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0 &&
*entry->value) {
branch = entry->value;
}
else if (error == GIT_ENOTFOUND) {
else if (!error || error == GIT_ENOTFOUND) {
branch = GIT_BRANCH_DEFAULT;
}
else {
......@@ -2379,7 +2379,7 @@ int git_repository_initialbranch(git_buf *out, git_repository *repo)
goto done;
if (!git_reference_is_valid_name(out->ptr)) {
git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid reference name");
git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid branch name");
error = -1;
}
......
......@@ -154,7 +154,7 @@ struct git_repository {
git_atomic attr_session_key;
git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
git_strmap *submodule_cache;
};
......
......@@ -235,35 +235,35 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
#else
GIT_INLINE(int) git___noop(void) { return 0; }
#define git_thread unsigned int
#define git_thread_create(thread, start_routine, arg) 0
#define git_thread_join(id, status) (void)0
#define git_thread_create(thread, start_routine, arg) git___noop()
#define git_thread_join(id, status) git___noop()
/* Pthreads Mutex */
#define git_mutex unsigned int
GIT_INLINE(int) git_mutex_init(git_mutex *mutex) \
{ GIT_UNUSED(mutex); return 0; }
GIT_INLINE(int) git_mutex_lock(git_mutex *mutex) \
{ GIT_UNUSED(mutex); return 0; }
#define git_mutex_unlock(a) (void)0
#define git_mutex_free(a) (void)0
#define git_mutex_init(a) git___noop()
#define git_mutex_lock(a) git___noop()
#define git_mutex_unlock(a) git___noop()
#define git_mutex_free(a) git___noop()
/* Pthreads condition vars */
#define git_cond unsigned int
#define git_cond_init(c, a) (void)0
#define git_cond_free(c) (void)0
#define git_cond_wait(c, l) (void)0
#define git_cond_signal(c) (void)0
#define git_cond_broadcast(c) (void)0
#define git_cond_init(c, a) git___noop()
#define git_cond_free(c) git___noop()
#define git_cond_wait(c, l) git___noop()
#define git_cond_signal(c) git___noop()
#define git_cond_broadcast(c) git___noop()
/* Pthreads rwlock */
#define git_rwlock unsigned int
#define git_rwlock_init(a) 0
#define git_rwlock_rdlock(a) 0
#define git_rwlock_rdunlock(a) (void)0
#define git_rwlock_wrlock(a) 0
#define git_rwlock_wrunlock(a) (void)0
#define git_rwlock_free(a) (void)0
#define git_rwlock_init(a) git___noop()
#define git_rwlock_rdlock(a) git___noop()
#define git_rwlock_rdunlock(a) git___noop()
#define git_rwlock_wrlock(a) git___noop()
#define git_rwlock_wrunlock(a) git___noop()
#define git_rwlock_free(a) git___noop()
#define GIT_RWLOCK_STATIC_INIT 0
......@@ -311,6 +311,11 @@ GIT_INLINE(volatile void *) git___swap(
return old;
}
GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
{
return *ptr;
}
#ifdef GIT_ARCH_64
GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
......
......@@ -658,6 +658,11 @@ static int generate_connect_request(
return git_buf_oom(buf) ? -1 : 0;
}
static bool use_connect_proxy(git_http_client *client)
{
return client->proxy.url.host && !strcmp(client->server.url.scheme, "https");
}
static int generate_request(
git_http_client *client,
git_http_request *request)
......@@ -713,7 +718,8 @@ static int generate_request(
git_buf_printf(buf, "Expect: 100-continue\r\n");
if ((error = apply_server_credentials(buf, client, request)) < 0 ||
(error = apply_proxy_credentials(buf, client, request)) < 0)
(!use_connect_proxy(client) &&
(error = apply_proxy_credentials(buf, client, request)) < 0))
return error;
if (request->custom_headers) {
......@@ -1003,8 +1009,7 @@ static int http_client_connect(
reset_parser(client);
/* Reconnect to the proxy if necessary. */
use_proxy = client->proxy.url.host &&
!strcmp(client->server.url.scheme, "https");
use_proxy = use_connect_proxy(client);
if (use_proxy) {
if (!client->proxy_connected || !client->keepalive ||
......@@ -1476,7 +1481,7 @@ int git_http_client_skip_body(git_http_client *client)
"unexpected data handled in callback");
error = -1;
}
} while (!error);
} while (error >= 0 && client->state != DONE);
if (error < 0)
client->connected = 0;
......
......@@ -53,6 +53,10 @@
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3 0x00002000
#endif
#ifndef WINHTTP_NO_CLIENT_CERT_CONTEXT
# define WINHTTP_NO_CLIENT_CERT_CONTEXT NULL
#endif
#ifndef HTTP_STATUS_PERMANENT_REDIRECT
# define HTTP_STATUS_PERMANENT_REDIRECT 308
#endif
......@@ -112,7 +116,8 @@ typedef struct {
DWORD post_body_len;
unsigned sent_request : 1,
received_response : 1,
chunked : 1;
chunked : 1,
status_sending_request_reached: 1;
} winhttp_stream;
typedef struct {
......@@ -708,30 +713,36 @@ static void CALLBACK winhttp_status(
DWORD status;
GIT_UNUSED(connection);
GIT_UNUSED(ctx);
GIT_UNUSED(info_len);
if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
return;
status = *((DWORD *)info);
if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
else
git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
switch (code) {
case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
status = *((DWORD *)info);
if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
else
git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
break;
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
((winhttp_stream *) ctx)->status_sending_request_reached = 1;
break;
}
}
static int winhttp_connect(
......@@ -826,7 +837,12 @@ static int winhttp_connect(
goto on_error;
}
if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
if (WinHttpSetStatusCallback(
t->connection,
winhttp_status,
WINHTTP_CALLBACK_FLAG_SECURE_FAILURE | WINHTTP_CALLBACK_FLAG_SEND_REQUEST,
0
) == WINHTTP_INVALID_STATUS_CALLBACK) {
git_error_set(GIT_ERROR_OS, "failed to set status callback");
goto on_error;
}
......@@ -858,12 +874,12 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
success = WinHttpSendRequest(s->request,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0);
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, (DWORD_PTR)s);
} else {
success = WinHttpSendRequest(s->request,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
(DWORD)len, 0);
(DWORD)len, (DWORD_PTR)s);
}
if (success || GetLastError() != (DWORD)SEC_E_BUFFER_TOO_SMALL)
......@@ -875,42 +891,73 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
static int send_request(winhttp_stream *s, size_t len, bool chunked)
{
int request_failed = 0, cert_valid = 1, error = 0;
DWORD ignore_flags;
int request_failed = 1, error, attempts = 0;
DWORD ignore_flags, send_request_error;
git_error_clear();
if ((error = do_send_request(s, len, chunked)) < 0) {
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
git_error_set(GIT_ERROR_OS, "failed to send request");
return -1;
}
request_failed = 1;
cert_valid = 0;
}
while (request_failed && attempts++ < 3) {
int cert_valid = 1;
int client_cert_requested = 0;
request_failed = 0;
if ((error = do_send_request(s, len, chunked)) < 0) {
send_request_error = GetLastError();
request_failed = 1;
switch (send_request_error) {
case ERROR_WINHTTP_SECURE_FAILURE:
cert_valid = 0;
break;
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
client_cert_requested = 1;
break;
default:
git_error_set(GIT_ERROR_OS, "failed to send request");
return -1;
}
}
git_error_clear();
if ((error = certificate_check(s, cert_valid)) < 0) {
if (!git_error_last())
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
/*
* Only check the certificate if we were able to reach the sending request phase, or
* received a secure failure error. Otherwise, the server certificate won't be available
* since the request wasn't able to complete (e.g. proxy auth required)
*/
if (!cert_valid ||
(!request_failed && s->status_sending_request_reached)) {
git_error_clear();
if ((error = certificate_check(s, cert_valid)) < 0) {
if (!git_error_last())
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
return error;
}
return error;
}
}
/* if neither the request nor the certificate check returned errors, we're done */
if (!request_failed)
return 0;
/* if neither the request nor the certificate check returned errors, we're done */
if (!request_failed)
return 0;
ignore_flags = no_check_cert_flags;
if (!cert_valid) {
ignore_flags = no_check_cert_flags;
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
git_error_set(GIT_ERROR_OS, "failed to set security options");
return -1;
}
}
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
git_error_set(GIT_ERROR_OS, "failed to set security options");
return -1;
if (client_cert_requested) {
/*
* Client certificates are not supported, explicitly tell the server that
* (it's possible a client certificate was requested but is not required)
*/
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) {
git_error_set(GIT_ERROR_OS, "failed to set client cert context");
return -1;
}
}
}
if ((error = do_send_request(s, len, chunked)) < 0)
git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
return error;
}
......
......@@ -101,4 +101,7 @@ GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
# define p_futimes futimes
#endif
#define p_pread(f, d, s, o) pread(f, d, s, o)
#define p_pwrite(f, d, s, o) pwrite(f, d, s, o)
#endif
......@@ -982,3 +982,73 @@ int p_inet_pton(int af, const char *src, void *dst)
errno = EINVAL;
return -1;
}
ssize_t p_pread(int fd, void *data, size_t size, off64_t offset)
{
HANDLE fh;
DWORD rsize = 0;
OVERLAPPED ov = {0};
LARGE_INTEGER pos = {0};
off64_t final_offset = 0;
/* Fail if the final offset would have overflowed to match POSIX semantics. */
if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
errno = EINVAL;
return -1;
}
/*
* Truncate large writes to the maximum allowable size: the caller
* needs to always call this in a loop anyways.
*/
if (size > INT32_MAX) {
size = INT32_MAX;
}
pos.QuadPart = offset;
ov.Offset = pos.LowPart;
ov.OffsetHigh = pos.HighPart;
fh = (HANDLE)_get_osfhandle(fd);
if (ReadFile(fh, data, (DWORD)size, &rsize, &ov)) {
return (ssize_t)rsize;
}
set_errno();
return -1;
}
ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset)
{
HANDLE fh;
DWORD wsize = 0;
OVERLAPPED ov = {0};
LARGE_INTEGER pos = {0};
off64_t final_offset = 0;
/* Fail if the final offset would have overflowed to match POSIX semantics. */
if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
errno = EINVAL;
return -1;
}
/*
* Truncate large writes to the maximum allowable size: the caller
* needs to always call this in a loop anyways.
*/
if (size > INT32_MAX) {
size = INT32_MAX;
}
pos.QuadPart = offset;
ov.Offset = pos.LowPart;
ov.OffsetHigh = pos.HighPart;
fh = (HANDLE)_get_osfhandle(fd);
if (WriteFile(fh, data, (DWORD)size, &wsize, &ov)) {
return (ssize_t)wsize;
}
set_errno();
return -1;
}
......@@ -259,7 +259,14 @@ int git_worktree_validate(const git_worktree *wt)
wt->commondir_path);
return GIT_ERROR;
}
if (!git_path_exists(wt->worktree_path)) {
git_error_set(GIT_ERROR_WORKTREE,
"worktree directory '%s' does not exist",
wt->worktree_path);
return GIT_ERROR;
}
return 0;
}
......
......@@ -158,6 +158,8 @@ void test_clone_nonetwork__can_prevent_the_checkout_of_a_standard_repo(void)
void test_clone_nonetwork__can_checkout_given_branch(void)
{
git_reference *remote_head;
g_options.checkout_branch = "test";
cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
......@@ -167,6 +169,12 @@ void test_clone_nonetwork__can_checkout_given_branch(void)
cl_assert_equal_s(git_reference_name(g_ref), "refs/heads/test");
cl_assert(git_path_exists("foo/readme.txt"));
cl_git_pass(git_reference_lookup(&remote_head, g_repo, "refs/remotes/origin/HEAD"));
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(remote_head));
cl_assert_equal_s("refs/remotes/origin/test", git_reference_symbolic_target(remote_head));
git_reference_free(remote_head);
}
static int clone_cancel_fetch_transfer_progress_cb(
......
......@@ -82,6 +82,11 @@ void test_core_structinit__compare(void)
git_blame_options, GIT_BLAME_OPTIONS_VERSION, \
GIT_BLAME_OPTIONS_INIT, git_blame_options_init);
/* blob_filter_options */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_blob_filter_options, GIT_BLOB_FILTER_OPTIONS_VERSION, \
GIT_BLOB_FILTER_OPTIONS_INIT, git_blob_filter_options_init);
/* checkout */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, \
......
......@@ -22,6 +22,8 @@ void test_diff_rename__cleanup(void)
#define RENAME_MODIFICATION_COMMIT "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13"
#define REWRITE_DELETE_COMMIT "84d8efa38af7ace2b302de0adbda16b1f1cd2e1b"
#define DELETE_RENAME_COMMIT "be053a189b0bbde545e0a3f59ce00b46ad29ce0d"
#define BREAK_REWRITE_BASE_COMMIT "db98035f715427eef1f5e17f03e1801c05301e9e"
#define BREAK_REWRITE_COMMIT "7e7bfb88ba9bc65fd700fee1819cf1c317aafa56"
/*
* Renames repo has:
......@@ -1978,3 +1980,56 @@ void test_diff_rename__delete_and_rename(void)
git_tree_free(old_tree);
git_tree_free(new_tree);
}
/*
* The break_rewrite branch contains a testcase reduced from
* a real-world scenario, rather than being "constructed" like
* the above tests seem to be. There are two commits layered
* on top of the repo's initial commit; the base commit which
* clears out the files from the initial commit and installs
* four files. And then there's the modification commit which
* mutates the files in such a way as to trigger the bug in
* libgit2.
* commit db98035f715427eef1f5e17f03e1801c05301e9e
* serving.txt (deleted)
* sevencities.txt (deleted)
* AAA (313 lines)
* BBB (314 lines)
* CCC (704 lines)
* DDD (314 lines, identical to BBB)
* commit 7e7bfb88ba9bc65fd700fee1819cf1c317aafa56
* This deletes CCC and makes slight modifications
* to AAA, BBB, and DDD. The find_best_matches loop
* for git_diff_find_similar computes the following:
* CCC moved to AAA (similarity 91)
* CCC copied to AAA (similarity 91)
* DDD moved to BBB (similarity 52)
* CCC copied to BBB (similarity 90)
* BBB moved to DDD (similarity 52)
* CCC copied to DDD (similarity 90)
* The code to rewrite the diffs by resolving these
* copies/renames would resolve the BBB <-> DDD moves
* but then still leave BBB as a rename target for
* the deleted file CCC. Since the split flag on BBB
* was cleared, this would trigger an error.
*/
void test_diff_rename__break_rewrite(void)
{
const char *old_sha = BREAK_REWRITE_BASE_COMMIT;
const char *new_sha = BREAK_REWRITE_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_find_options find_opts = GIT_DIFF_FIND_OPTIONS_INIT;
old_tree = resolve_commit_oid_to_tree(g_repo, old_sha);
new_tree = resolve_commit_oid_to_tree(g_repo, new_sha);
find_opts.flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES | GIT_DIFF_BREAK_REWRITES | GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY;
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, old_tree, new_tree, NULL));
cl_git_pass(git_diff_find_similar(diff, &find_opts));
git_diff_free(diff);
git_tree_free(old_tree);
git_tree_free(new_tree);
}
......@@ -319,6 +319,16 @@ static int assert_master_for_merge(const char *ref, const char *url, const git_o
return 0;
}
static int assert_none_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data)
{
GIT_UNUSED(ref);
GIT_UNUSED(url);
GIT_UNUSED(id);
GIT_UNUSED(data);
return is_merge ? -1 : 0;
}
void test_fetchhead_nonetwork__unborn_with_upstream(void)
{
git_repository *repo;
......@@ -366,6 +376,25 @@ void test_fetchhead_nonetwork__fetch_into_repo_with_symrefs(void)
cl_git_sandbox_cleanup();
}
void test_fetchhead_nonetwork__fetch_into_repo_with_invalid_head(void)
{
git_remote *remote;
char *strings[] = { "refs/heads/*:refs/remotes/origin/*" };
git_strarray refspecs = { strings, 1 };
cl_set_cleanup(&cleanup_repository, "./test1");
cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
/* HEAD pointing to nonexistent branch */
cl_git_rewritefile("./test1/.git/HEAD", "ref: refs/heads/\n");
cl_git_pass(git_remote_create_anonymous(&remote, g_repo, cl_fixture("testrepo.git")));
cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, NULL));
cl_git_pass(git_repository_fetchhead_foreach(g_repo, assert_none_for_merge, NULL));
git_remote_free(remote);
}
void test_fetchhead_nonetwork__quote_in_branch_name(void)
{
cl_set_cleanup(&cleanup_repository, "./test1");
......
......@@ -13,7 +13,7 @@ static void assert_refspec(unsigned int direction, const char *input, bool is_ex
if (is_expected_to_be_valid)
cl_assert_equal_i(0, error);
else
cl_assert_equal_i(GIT_ERROR, error);
cl_assert_equal_i(GIT_EINVALIDSPEC, error);
}
void test_network_refspecs__parsing(void)
......
......@@ -869,6 +869,28 @@ void test_online_clone__proxy_credentials_in_environment(void)
git_buf_dispose(&url);
}
void test_online_clone__proxy_credentials_in_url_https(void)
{
git_buf url = GIT_BUF_INIT;
if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
cl_skip();
cl_git_pass(git_buf_printf(&url, "%s://%s:%s@%s/",
_remote_proxy_scheme ? _remote_proxy_scheme : "http",
_remote_proxy_user, _remote_proxy_pass, _remote_proxy_host));
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
g_options.fetch_opts.proxy_opts.url = url.ptr;
g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
g_options.fetch_opts.callbacks.certificate_check = ssl_cert;
called_proxy_creds = 0;
cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options));
cl_assert(called_proxy_creds == 0);
git_buf_dispose(&url);
}
void test_online_clone__proxy_auto_not_detected(void)
{
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
......
#include "clar_libgit2.h"
#include "repo/repo_helpers.h"
void test_repo_getters__is_empty_correctly_deals_with_pristine_looking_repos(void)
{
......@@ -23,6 +24,18 @@ void test_repo_getters__is_empty_can_detect_used_repositories(void)
git_repository_free(repo);
}
void test_repo_getters__is_empty_can_detect_repositories_with_defaultbranch_config_empty(void)
{
git_repository *repo;
create_tmp_global_config("tmp_global_path", "init.defaultBranch", "");
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
cl_assert_equal_i(false, git_repository_is_empty(repo));
git_repository_free(repo);
}
void test_repo_getters__retrieving_the_odb_honors_the_refcount(void)
{
git_odb *odb;
......
......@@ -262,6 +262,7 @@ void test_repo_init__symlinks_win32_enabled_by_global_config(void)
* Create a new repository (can't use `assert_config_on_init` since we
* want to examine configuration levels with more granularity.)
*/
cl_set_cleanup(&cleanup_repository, "config_entry/test.non.bare.git");
cl_git_pass(git_repository_init(&_repo, "config_entry/test.non.bare.git", false));
/* Ensure that core.symlinks remains set (via the global config). */
......@@ -681,3 +682,19 @@ void test_repo_init__defaultbranch_config(void)
git_reference_free(head);
}
void test_repo_init__defaultbranch_config_empty(void)
{
git_reference *head;
cl_set_cleanup(&cleanup_repository, "repo");
create_tmp_global_config("tmp_global_path", "init.defaultbranch", "");
cl_git_pass(git_repository_init(&_repo, "repo", 0));
cl_git_pass(git_reference_lookup(&head, _repo, "HEAD"));
cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
git_reference_free(head);
}
19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13
......@@ -2,3 +2,8 @@
31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 2bc7f351d20b53f1c72c16c4b036e491c478c49a Russell Belfer <rb@github.com> 1351024817 -0700 commit: copy and rename with no change
2bc7f351d20b53f1c72c16c4b036e491c478c49a 1c068dee5790ef1580cfc4cd670915b48d790084 Russell Belfer <rb@github.com> 1361485758 -0800 commit: rewrites, copies with changes, etc.
1c068dee5790ef1580cfc4cd670915b48d790084 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Russell Belfer <rb@github.com> 1361486360 -0800 commit: more renames and smallish modifications
19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 Kartikaya Gupta <kats@pancake.staktrace.com> 1618486966 -0400 checkout: moving from master to break_rewrite
31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 db98035f715427eef1f5e17f03e1801c05301e9e Kartikaya Gupta <kats@pancake.staktrace.com> 1618487039 -0400 commit: This test needs to start with a minimum of four files
db98035f715427eef1f5e17f03e1801c05301e9e 7e7bfb88ba9bc65fd700fee1819cf1c317aafa56 Kartikaya Gupta <kats@pancake.staktrace.com> 1618487097 -0400 commit: Copy/modify files around
7e7bfb88ba9bc65fd700fee1819cf1c317aafa56 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Kartikaya Gupta <kats@pancake.staktrace.com> 1618487105 -0400 checkout: moving from break_rewrite to master
19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Kartikaya Gupta <kats@pancake.staktrace.com> 1618487271 -0400 reset: moving to HEAD
7e7bfb88ba9bc65fd700fee1819cf1c317aafa56
......@@ -58,47 +58,47 @@ void test_trace_windows_stacktrace__leaks(void)
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1");
cl_assert((leaks == 1));
cl_assert_equal_i(1, leaks);
p2 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1,p2");
cl_assert((leaks == 2));
cl_assert_equal_i(2, leaks);
p3 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1,p2,p3");
cl_assert((leaks == 3));
cl_assert_equal_i(3, leaks);
git__free(p2);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1,p3");
cl_assert((leaks == 2));
cl_assert_equal_i(2, leaks);
/* move the mark. only new leaks should appear afterwards */
error = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
NULL);
cl_assert((error == 0));
cl_assert_equal_i(0, error);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"not_p1,not_p3");
cl_assert((leaks == 0));
cl_assert_equal_i(0, leaks);
p4 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p4,not_p1,not_p3");
cl_assert((leaks == 1));
cl_assert_equal_i(1, leaks);
git__free(p1);
git__free(p3);
......@@ -106,21 +106,21 @@ void test_trace_windows_stacktrace__leaks(void)
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p4");
cl_assert((leaks == 1));
cl_assert_equal_i(1, leaks);
git__free(p4);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"end");
cl_assert((leaks == 0));
cl_assert_equal_i(0, leaks);
/* confirm current absolute leaks count matches beginning value. */
after = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL,
"total");
cl_assert((before == after));
cl_assert_equal_i(before, after);
#endif
}
......
......@@ -610,3 +610,15 @@ void test_worktree_worktree__foreach_worktree_lists_all_worktrees(void)
int counter = 0;
cl_git_pass(git_repository_foreach_worktree(fixture.repo, foreach_worktree_cb, &counter));
}
void test_worktree_worktree__validate_invalid_worktreedir(void)
{
git_worktree *wt;
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
p_rename("testrepo-worktree", "testrepo-worktree-tmp");
cl_git_fail(git_worktree_validate(wt));
p_rename("testrepo-worktree-tmp", "testrepo-worktree");
git_worktree_free(wt);
}
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