mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 12:57:05 +00:00
Merge branch 'development' into unmerged
This commit is contained in:
commit
050e8877dd
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.c eol=lf
|
||||
*.h eol=lf
|
@ -39,7 +39,7 @@ Under Unix-like systems, like Linux, *BSD and Mac OS X, libgit2 expects `pthread
|
||||
they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
|
||||
for threading.
|
||||
|
||||
Additionally, he following libraries may be used as replacement for built-in functionality:
|
||||
Additionally, the following libraries may be used as replacement for built-in functionality:
|
||||
|
||||
* LibSSL **(optional)** <http://www.openssl.org/>
|
||||
|
||||
@ -88,6 +88,9 @@ The waf build system for libgit2 accepts the following flags:
|
||||
--with-sqlite
|
||||
Enable sqlite support.
|
||||
|
||||
--with-redis
|
||||
Enable redis support.
|
||||
|
||||
You can run `./waf --help` to see a full list of install options and
|
||||
targets.
|
||||
|
||||
|
@ -26,9 +26,9 @@
|
||||
#ifndef INCLUDE_git_git_h__
|
||||
#define INCLUDE_git_git_h__
|
||||
|
||||
#define LIBGIT2_VERSION "0.11.0"
|
||||
#define LIBGIT2_VERSION "0.12.0"
|
||||
#define LIBGIT2_VER_MAJOR 0
|
||||
#define LIBGIT2_VER_MINOR 10
|
||||
#define LIBGIT2_VER_MINOR 12
|
||||
#define LIBGIT2_VER_REVISION 0
|
||||
|
||||
#include "git2/common.h"
|
||||
@ -52,5 +52,6 @@
|
||||
#include "git2/tree.h"
|
||||
|
||||
#include "git2/index.h"
|
||||
#include "git2/config.h"
|
||||
|
||||
#endif
|
||||
|
@ -84,92 +84,6 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Operation completed successfully. */
|
||||
#define GIT_SUCCESS 0
|
||||
|
||||
/**
|
||||
* Operation failed, with unspecified reason.
|
||||
* This value also serves as the base error code; all other
|
||||
* error codes are subtracted from it such that all errors
|
||||
* are < 0, in typical POSIX C tradition.
|
||||
*/
|
||||
#define GIT_ERROR -1
|
||||
|
||||
/** Input was not a properly formatted Git object id. */
|
||||
#define GIT_ENOTOID (GIT_ERROR - 1)
|
||||
|
||||
/** Input does not exist in the scope searched. */
|
||||
#define GIT_ENOTFOUND (GIT_ERROR - 2)
|
||||
|
||||
/** Not enough space available. */
|
||||
#define GIT_ENOMEM (GIT_ERROR - 3)
|
||||
|
||||
/** Consult the OS error information. */
|
||||
#define GIT_EOSERR (GIT_ERROR - 4)
|
||||
|
||||
/** The specified object is of invalid type */
|
||||
#define GIT_EOBJTYPE (GIT_ERROR - 5)
|
||||
|
||||
/** The specified object has its data corrupted */
|
||||
#define GIT_EOBJCORRUPTED (GIT_ERROR - 6)
|
||||
|
||||
/** The specified repository is invalid */
|
||||
#define GIT_ENOTAREPO (GIT_ERROR - 7)
|
||||
|
||||
/** The object type is invalid or doesn't match */
|
||||
#define GIT_EINVALIDTYPE (GIT_ERROR - 8)
|
||||
|
||||
/** The object cannot be written because it's missing internal data */
|
||||
#define GIT_EMISSINGOBJDATA (GIT_ERROR - 9)
|
||||
|
||||
/** The packfile for the ODB is corrupted */
|
||||
#define GIT_EPACKCORRUPTED (GIT_ERROR - 10)
|
||||
|
||||
/** Failed to acquire or release a file lock */
|
||||
#define GIT_EFLOCKFAIL (GIT_ERROR - 11)
|
||||
|
||||
/** The Z library failed to inflate/deflate an object's data */
|
||||
#define GIT_EZLIB (GIT_ERROR - 12)
|
||||
|
||||
/** The queried object is currently busy */
|
||||
#define GIT_EBUSY (GIT_ERROR - 13)
|
||||
|
||||
/** The index file is not backed up by an existing repository */
|
||||
#define GIT_EBAREINDEX (GIT_ERROR - 14)
|
||||
|
||||
/** The name of the reference is not valid */
|
||||
#define GIT_EINVALIDREFNAME (GIT_ERROR - 15)
|
||||
|
||||
/** The specified reference has its data corrupted */
|
||||
#define GIT_EREFCORRUPTED (GIT_ERROR - 16)
|
||||
|
||||
/** The specified symbolic reference is too deeply nested */
|
||||
#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17)
|
||||
|
||||
/** The pack-refs file is either corrupted or its format is not currently supported */
|
||||
#define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18)
|
||||
|
||||
/** The path is invalid */
|
||||
#define GIT_EINVALIDPATH (GIT_ERROR - 19)
|
||||
|
||||
/** The revision walker is empty; there are no more commits left to iterate */
|
||||
#define GIT_EREVWALKOVER (GIT_ERROR - 20)
|
||||
|
||||
/** The state of the reference is not valid */
|
||||
#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21)
|
||||
|
||||
/** This feature has not been implemented yet */
|
||||
#define GIT_ENOTIMPLEMENTED (GIT_ERROR - 22)
|
||||
|
||||
/** A reference with this name already exists */
|
||||
#define GIT_EEXISTS (GIT_ERROR - 23)
|
||||
|
||||
/** The given integer literal is too large to be parsed */
|
||||
#define GIT_EOVERFLOW (GIT_ERROR - 24)
|
||||
|
||||
/** The given literal is not a valid number */
|
||||
#define GIT_ENOTNUM (GIT_ERROR - 25)
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef struct {
|
||||
|
171
include/git2/config.h
Normal file
171
include/git2/config.h
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef INCLUDE_git_config_h__
|
||||
#define INCLUDE_git_config_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
* @file git2/config.h
|
||||
* @brief Git config management routines
|
||||
* @defgroup git_config Git config management routines
|
||||
* @ingroup Git
|
||||
* @{
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Allocate a new configuration
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_new(git_config **out);
|
||||
|
||||
/**
|
||||
* Open a configuration file
|
||||
*
|
||||
* @param cfg_out pointer to the configuration data
|
||||
* @param path where to load the confiration from
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_open_bare(git_config **cfg_out, const char *path);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_add_backend(git_config *cfg, git_config_backend *backend, int priority);
|
||||
|
||||
/**
|
||||
* Free the configuration and its associated memory
|
||||
*
|
||||
* @param cfg the configuration to free
|
||||
*/
|
||||
GIT_EXTERN(void) git_config_free(git_config *cfg);
|
||||
|
||||
/**
|
||||
* Get the value of an integer config variable.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_int(git_config *cfg, const char *name, int *out);
|
||||
|
||||
/**
|
||||
* Get the value of a long integer config variable.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_long(git_config *cfg, const char *name, long int *out);
|
||||
|
||||
/**
|
||||
* Get the value of a boolean config variable.
|
||||
*
|
||||
* This function uses the usual C convention of 0 being false and
|
||||
* anything else true.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_bool(git_config *cfg, const char *name, int *out);
|
||||
|
||||
/**
|
||||
* Get the value of a string config variable.
|
||||
*
|
||||
* The string is owned by the variable and should not be freed by the
|
||||
* user.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param out pointer to the variable's value
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_string(git_config *cfg, const char *name, const char **out);
|
||||
|
||||
/**
|
||||
* Set the value of an integer config variable.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_set_int(git_config *cfg, const char *name, int value);
|
||||
|
||||
/**
|
||||
* Set the value of a long integer config variable.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_set_long(git_config *cfg, const char *name, long int value);
|
||||
|
||||
/**
|
||||
* Set the value of a boolean config variable.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param value the value to store
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value);
|
||||
|
||||
/**
|
||||
* Set the value of a string config variable.
|
||||
*
|
||||
* A copy of the string is made and the user is free to use it
|
||||
* afterwards.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param value the string to store.
|
||||
* @return GIT_SUCCESS on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const char *value);
|
||||
|
||||
/**
|
||||
* Perform an operation on each config variable.
|
||||
*
|
||||
* The callback is passed a pointer to a config variable name and the
|
||||
* data pointer passed to this function. As soon as one of the
|
||||
* callback functions returns something other than 0, this function
|
||||
* returns that value.
|
||||
*
|
||||
* @param cfg where to get the variables from
|
||||
* @param callback the function to call on each variable
|
||||
* @param data the data to pass to the callback
|
||||
* @return GIT_SUCCESS or the return value of the callback which didn't return 0
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_foreach(git_config *cfg, int (*callback)(const char *, void *data), void *data);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
57
include/git2/config_backend.h
Normal file
57
include/git2/config_backend.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_git_config_backend_h__
|
||||
#define INCLUDE_git_config_backend_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "config.h"
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
struct git_config;
|
||||
|
||||
struct git_config_backend {
|
||||
struct git_config *cfg;
|
||||
/* Open means open the file/database and parse if necessary */
|
||||
int (*open)(struct git_config_backend *);
|
||||
int (* get)(struct git_config_backend *, const char *key, const char **value);
|
||||
int (* set)(struct git_config_backend *, const char *key, const char *value);
|
||||
int (*foreach)(struct git_config_backend *, int (*fn)(const char *, void *), void *data);
|
||||
void (*free)(struct git_config_backend *);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a file-backed configuration backend
|
||||
*
|
||||
* @param out the new backend
|
||||
* @path where the config file is located
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_backend_file(struct git_config_backend **out, const char *path);
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
#endif
|
@ -25,6 +25,8 @@
|
||||
#ifndef INCLUDE_git_errors_h__
|
||||
#define INCLUDE_git_errors_h__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* @file git2/errors.h
|
||||
* @brief Git error handling routines and variables
|
||||
@ -33,8 +35,106 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef enum {
|
||||
GIT_SUCCESS = 0,
|
||||
GIT_ERROR = -1,
|
||||
|
||||
/** Input was not a properly formatted Git object id. */
|
||||
GIT_ENOTOID = -2,
|
||||
|
||||
/** Input does not exist in the scope searched. */
|
||||
GIT_ENOTFOUND = -3,
|
||||
|
||||
/** Not enough space available. */
|
||||
GIT_ENOMEM = -4,
|
||||
|
||||
/** Consult the OS error information. */
|
||||
GIT_EOSERR = -5,
|
||||
|
||||
/** The specified object is of invalid type */
|
||||
GIT_EOBJTYPE = -6,
|
||||
|
||||
/** The specified repository is invalid */
|
||||
GIT_ENOTAREPO = -7,
|
||||
|
||||
/** The object type is invalid or doesn't match */
|
||||
GIT_EINVALIDTYPE = -8,
|
||||
|
||||
/** The object cannot be written because it's missing internal data */
|
||||
GIT_EMISSINGOBJDATA = -9,
|
||||
|
||||
/** The packfile for the ODB is corrupted */
|
||||
GIT_EPACKCORRUPTED = -10,
|
||||
|
||||
/** Failed to acquire or release a file lock */
|
||||
GIT_EFLOCKFAIL = -11,
|
||||
|
||||
/** The Z library failed to inflate/deflate an object's data */
|
||||
GIT_EZLIB = -12,
|
||||
|
||||
/** The queried object is currently busy */
|
||||
GIT_EBUSY = -13,
|
||||
|
||||
/** The index file is not backed up by an existing repository */
|
||||
GIT_EBAREINDEX = -14,
|
||||
|
||||
/** The name of the reference is not valid */
|
||||
GIT_EINVALIDREFNAME = -15,
|
||||
|
||||
/** The specified reference has its data corrupted */
|
||||
GIT_EREFCORRUPTED = -16,
|
||||
|
||||
/** The specified symbolic reference is too deeply nested */
|
||||
GIT_ETOONESTEDSYMREF = -17,
|
||||
|
||||
/** The pack-refs file is either corrupted or its format is not currently supported */
|
||||
GIT_EPACKEDREFSCORRUPTED = -18,
|
||||
|
||||
/** The path is invalid */
|
||||
GIT_EINVALIDPATH = -19,
|
||||
|
||||
/** The revision walker is empty; there are no more commits left to iterate */
|
||||
GIT_EREVWALKOVER = -20,
|
||||
|
||||
/** The state of the reference is not valid */
|
||||
GIT_EINVALIDREFSTATE = -21,
|
||||
|
||||
/** This feature has not been implemented yet */
|
||||
GIT_ENOTIMPLEMENTED = -22,
|
||||
|
||||
/** A reference with this name already exists */
|
||||
GIT_EEXISTS = -23,
|
||||
|
||||
/** The given integer literal is too large to be parsed */
|
||||
GIT_EOVERFLOW = -24,
|
||||
|
||||
/** The given literal is not a valid number */
|
||||
GIT_ENOTNUM = -25,
|
||||
|
||||
/** Streaming error */
|
||||
GIT_ESTREAM = -26,
|
||||
|
||||
/** invalid arguments to function */
|
||||
GIT_EINVALIDARGS = -27,
|
||||
|
||||
/** The specified object has its data corrupted */
|
||||
GIT_EOBJCORRUPTED = -28,
|
||||
} git_error;
|
||||
|
||||
/**
|
||||
* Return a detailed error string with the latest error
|
||||
* that occurred in the library.
|
||||
* @return a string explaining the error
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_lasterror(void);
|
||||
|
||||
/**
|
||||
* strerror() for the Git library
|
||||
*
|
||||
* Get a string description for a given error code.
|
||||
* NOTE: This method will be eventually deprecated in favor
|
||||
* of the new `git_lasterror`.
|
||||
*
|
||||
* @param num The error code to explain
|
||||
* @return a string explaining the error code
|
||||
*/
|
||||
|
@ -51,39 +51,29 @@ GIT_BEGIN_DECL
|
||||
*
|
||||
* In-memory only flags:
|
||||
*/
|
||||
#define GIT_IDXENTRY_UPDATE (1 << 16)
|
||||
#define GIT_IDXENTRY_REMOVE (1 << 17)
|
||||
#define GIT_IDXENTRY_UPTODATE (1 << 18)
|
||||
#define GIT_IDXENTRY_ADDED (1 << 19)
|
||||
#define GIT_IDXENTRY_UPDATE (1 << 0)
|
||||
#define GIT_IDXENTRY_REMOVE (1 << 1)
|
||||
#define GIT_IDXENTRY_UPTODATE (1 << 2)
|
||||
#define GIT_IDXENTRY_ADDED (1 << 3)
|
||||
|
||||
#define GIT_IDXENTRY_HASHED (1 << 20)
|
||||
#define GIT_IDXENTRY_UNHASHED (1 << 21)
|
||||
#define GIT_IDXENTRY_WT_REMOVE (1 << 22) /* remove in work directory */
|
||||
#define GIT_IDXENTRY_CONFLICTED (1 << 23)
|
||||
#define GIT_IDXENTRY_HASHED (1 << 4)
|
||||
#define GIT_IDXENTRY_UNHASHED (1 << 5)
|
||||
#define GIT_IDXENTRY_WT_REMOVE (1 << 6) /* remove in work directory */
|
||||
#define GIT_IDXENTRY_CONFLICTED (1 << 7)
|
||||
|
||||
#define GIT_IDXENTRY_UNPACKED (1 << 24)
|
||||
#define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 25)
|
||||
#define GIT_IDXENTRY_UNPACKED (1 << 8)
|
||||
#define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9)
|
||||
|
||||
/*
|
||||
* Extended on-disk flags:
|
||||
*/
|
||||
#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 29)
|
||||
#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 30)
|
||||
#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13)
|
||||
#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14)
|
||||
/* GIT_IDXENTRY_EXTENDED2 is for future extension */
|
||||
#define GIT_IDXENTRY_EXTENDED2 (1 << 31)
|
||||
#define GIT_IDXENTRY_EXTENDED2 (1 << 15)
|
||||
|
||||
#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE)
|
||||
|
||||
/*
|
||||
* Safeguard to avoid saving wrong flags:
|
||||
* - GIT_IDXENTRY_EXTENDED2 won't get saved until its semantic is known
|
||||
* - Bits in 0x0000FFFF have been saved in flags already
|
||||
* - Bits in 0x003F0000 are currently in-memory flags
|
||||
*/
|
||||
#if GIT_IDXENTRY_EXTENDED_FLAGS & 0x803FFFFF
|
||||
#error "GIT_IDXENTRY_EXTENDED_FLAGS out of range"
|
||||
#endif
|
||||
|
||||
/** Time used in a git index entry */
|
||||
typedef struct {
|
||||
git_time_t seconds;
|
||||
@ -188,7 +178,12 @@ GIT_EXTERN(int) git_index_write(git_index *index);
|
||||
GIT_EXTERN(int) git_index_find(git_index *index, const char *path);
|
||||
|
||||
/**
|
||||
* Add or update an index entry from a file in disk.
|
||||
* Add or update an index entry from a file in disk
|
||||
*
|
||||
* The file `path` must be relative to the repository's
|
||||
* working folder and must be readable.
|
||||
*
|
||||
* This method will fail in bare index instances.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param path filename to add
|
||||
@ -198,7 +193,55 @@ GIT_EXTERN(int) git_index_find(git_index *index, const char *path);
|
||||
GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage);
|
||||
|
||||
/**
|
||||
* Remove an entry from the index
|
||||
* Add or update an index entry from an in-memory struct
|
||||
*
|
||||
* A full copy (including the 'path' string) of the given
|
||||
* 'source_entry' will be inserted on the index.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param source_entry new entry object
|
||||
* @return 0 on success, otherwise an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_add2(git_index *index, const git_index_entry *source_entry);
|
||||
|
||||
/**
|
||||
* Add (append) an index entry from a file in disk
|
||||
*
|
||||
* A new entry will always be inserted into the index;
|
||||
* if the index already contains an entry for such
|
||||
* path, the old entry will **not** be replaced.
|
||||
*
|
||||
* The file `path` must be relative to the repository's
|
||||
* working folder and must be readable.
|
||||
*
|
||||
* This method will fail in bare index instances.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param path filename to add
|
||||
* @param stage stage for the entry
|
||||
* @return 0 on success, otherwise an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_append(git_index *index, const char *path, int stage);
|
||||
|
||||
/**
|
||||
* Add (append) an index entry from an in-memory struct
|
||||
*
|
||||
* A new entry will always be inserted into the index;
|
||||
* if the index already contains an entry for the path
|
||||
* in the `entry` struct, the old entry will **not** be
|
||||
* replaced.
|
||||
*
|
||||
* A full copy (including the 'path' string) of the given
|
||||
* 'source_entry' will be inserted on the index.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param source_entry new entry object
|
||||
* @return 0 on success, otherwise an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_append2(git_index *index, const git_index_entry *source_entry);
|
||||
|
||||
/**
|
||||
* Remove an entry from the index
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param position position of the entry to remove
|
||||
@ -206,18 +249,6 @@ GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage);
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_remove(git_index *index, int position);
|
||||
|
||||
/**
|
||||
* Insert an entry into the index.
|
||||
* A full copy (including the 'path' string) of the given
|
||||
* 'source_entry' will be inserted on the index; if the index
|
||||
* already contains an entry for the same path, the entry
|
||||
* will be updated.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param source_entry new entry object
|
||||
* @return 0 on success, otherwise an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_insert(git_index *index, const git_index_entry *source_entry);
|
||||
|
||||
/**
|
||||
* Get a pointer to one of the entries in the index
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
# undef GIT_TLS
|
||||
# define GIT_TLS
|
||||
|
||||
#elif defined(__GNUC__) || \
|
||||
defined(__SUNPRO_C) || \
|
||||
|
@ -130,6 +130,12 @@ typedef struct git_treebuilder git_treebuilder;
|
||||
/** Memory representation of an index file. */
|
||||
typedef struct git_index git_index;
|
||||
|
||||
/** Memory representation of a config file */
|
||||
typedef struct git_config git_config;
|
||||
|
||||
/** A specific implementation of a config backend */
|
||||
typedef struct git_config_backend git_config_backend;
|
||||
|
||||
/** Time in a signature */
|
||||
typedef struct git_time {
|
||||
git_time_t time; /** time in seconds from epoch */
|
||||
|
@ -53,7 +53,7 @@ int hiredis_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backe
|
||||
reply = redisCommand(backend->db, "HMGET %b %s %s", oid->id, GIT_OID_RAWSZ,
|
||||
"type", "size");
|
||||
|
||||
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||
if (reply && reply->type == REDIS_REPLY_ARRAY) {
|
||||
if (reply->element[0]->type != REDIS_REPLY_NIL &&
|
||||
reply->element[0]->type != REDIS_REPLY_NIL) {
|
||||
*type_p = (git_otype) atoi(reply->element[0]->str);
|
||||
@ -83,7 +83,7 @@ int hiredis_backend__read(void **data_p, size_t *len_p, git_otype *type_p, git_o
|
||||
reply = redisCommand(backend->db, "HMGET %b %s %s %s", oid->id, GIT_OID_RAWSZ,
|
||||
"type", "size", "data");
|
||||
|
||||
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||
if (reply && reply->type == REDIS_REPLY_ARRAY) {
|
||||
if (reply->element[0]->type != REDIS_REPLY_NIL &&
|
||||
reply->element[1]->type != REDIS_REPLY_NIL &&
|
||||
reply->element[2]->type != REDIS_REPLY_NIL) {
|
||||
@ -118,7 +118,7 @@ int hiredis_backend__exists(git_odb_backend *_backend, const git_oid *oid) {
|
||||
found = 0;
|
||||
|
||||
reply = redisCommand(backend->db, "exists %b", oid->id, GIT_OID_RAWSZ);
|
||||
if (reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR)
|
||||
if (reply && reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR)
|
||||
found = 1;
|
||||
|
||||
|
||||
@ -144,7 +144,8 @@ int hiredis_backend__write(git_oid *id, git_odb_backend *_backend, const void *d
|
||||
"size %d "
|
||||
"data %b ", id->id, GIT_OID_RAWSZ,
|
||||
(int) type, len, data, len);
|
||||
error = reply->type == REDIS_REPLY_ERROR ? GIT_ERROR : GIT_SUCCESS;
|
||||
|
||||
error = (reply == NULL || reply->type == REDIS_REPLY_ERROR) ? GIT_ERROR : GIT_SUCCESS;
|
||||
|
||||
freeReplyObject(reply);
|
||||
return error;
|
||||
|
@ -62,7 +62,7 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
|
||||
git_odb_stream *stream;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to create blob. Can't open write stream");
|
||||
|
||||
stream->write(stream, buffer, len);
|
||||
|
||||
@ -81,7 +81,7 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (repo->path_workdir == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to create blob. No workdir given");
|
||||
|
||||
git__joinpath(full_path, repo->path_workdir, path);
|
||||
|
||||
@ -106,7 +106,7 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
|
||||
if (read_len < 0) {
|
||||
gitfo_close(fd);
|
||||
stream->free(stream);
|
||||
return GIT_EOSERR;
|
||||
return git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
|
||||
}
|
||||
|
||||
stream->write(stream, buffer, read_len);
|
||||
|
84
src/cache.c
84
src/cache.c
@ -29,10 +29,7 @@
|
||||
#include "thread-utils.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define GIT_CACHE_OPENADR 3
|
||||
|
||||
|
||||
void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
|
||||
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@ -52,12 +49,15 @@ void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_p
|
||||
cache->free_obj = free_ptr;
|
||||
|
||||
cache->nodes = git__malloc((size + 1) * sizeof(cache_node));
|
||||
if (cache->nodes == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
for (i = 0; i < (size + 1); ++i) {
|
||||
git_mutex_init(&cache->nodes[i].lock);
|
||||
cache->nodes[i].ptr = NULL;
|
||||
cache->nodes[i].lru = 0;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_cache_free(git_cache *cache)
|
||||
@ -77,85 +77,53 @@ void git_cache_free(git_cache *cache)
|
||||
void *git_cache_get(git_cache *cache, const git_oid *oid)
|
||||
{
|
||||
const uint32_t *hash;
|
||||
size_t i, pos, found = 0;
|
||||
cache_node *node = NULL;
|
||||
void *result = NULL;
|
||||
|
||||
hash = (const uint32_t *)oid->id;
|
||||
node = &cache->nodes[hash[0] & cache->size_mask];
|
||||
|
||||
for (i = 0; !found && i < GIT_CACHE_OPENADR; ++i) {
|
||||
pos = hash[i] & cache->size_mask;
|
||||
node = &cache->nodes[pos];
|
||||
|
||||
git_mutex_lock(&node->lock);
|
||||
{
|
||||
if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
|
||||
git_cached_obj_incref(node->ptr);
|
||||
node->lru = ++cache->lru_count;
|
||||
found = 1;
|
||||
}
|
||||
git_mutex_lock(&node->lock);
|
||||
{
|
||||
if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
|
||||
git_cached_obj_incref(node->ptr);
|
||||
result = node->ptr;
|
||||
}
|
||||
git_mutex_unlock(&node->lock);
|
||||
}
|
||||
git_mutex_unlock(&node->lock);
|
||||
|
||||
|
||||
return found ? node->ptr : NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
void *git_cache_try_store(git_cache *cache, void *entry)
|
||||
{
|
||||
cache_node *nodes[GIT_CACHE_OPENADR], *lru_node;
|
||||
const uint32_t *hash;
|
||||
const git_oid *oid;
|
||||
size_t i;
|
||||
cache_node *node = NULL;
|
||||
|
||||
oid = &((git_cached_obj*)entry)->oid;
|
||||
hash = (const uint32_t *)oid->id;
|
||||
node = &cache->nodes[hash[0] & cache->size_mask];
|
||||
|
||||
/* increase the refcount on this object, because
|
||||
* the cache now owns it */
|
||||
git_cached_obj_incref(entry);
|
||||
git_mutex_lock(&node->lock);
|
||||
|
||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
|
||||
size_t pos = hash[i] & cache->size_mask;
|
||||
|
||||
nodes[i] = &cache->nodes[pos];
|
||||
git_mutex_lock(&nodes[i]->lock);
|
||||
}
|
||||
|
||||
lru_node = nodes[0];
|
||||
|
||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
|
||||
|
||||
if (nodes[i]->ptr == NULL) {
|
||||
nodes[i]->ptr = entry;
|
||||
nodes[i]->lru = ++cache->lru_count;
|
||||
break;
|
||||
} else if (git_cached_obj_compare(nodes[i]->ptr, oid) == 0) {
|
||||
git_cached_obj_decref(entry, cache->free_obj);
|
||||
entry = nodes[i]->ptr;
|
||||
nodes[i]->lru = ++cache->lru_count;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nodes[i]->lru < lru_node->lru)
|
||||
lru_node = nodes[i];
|
||||
}
|
||||
|
||||
if (i == GIT_CACHE_OPENADR) {
|
||||
void *old_entry = lru_node->ptr;
|
||||
assert(old_entry);
|
||||
|
||||
git_cached_obj_decref(old_entry, cache->free_obj);
|
||||
lru_node->ptr = entry;
|
||||
lru_node->lru = ++cache->lru_count;
|
||||
if (node->ptr == NULL) {
|
||||
node->ptr = entry;
|
||||
} else if (git_cached_obj_compare(node->ptr, oid) == 0) {
|
||||
git_cached_obj_decref(entry, cache->free_obj);
|
||||
entry = node->ptr;
|
||||
} else {
|
||||
git_cached_obj_decref(node->ptr, cache->free_obj);
|
||||
node->ptr = entry;
|
||||
}
|
||||
|
||||
/* increase the refcount again, because we are
|
||||
* returning it to the user */
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i)
|
||||
git_mutex_unlock(&nodes[i]->lock);
|
||||
git_mutex_unlock(&node->lock);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ typedef struct {
|
||||
typedef struct {
|
||||
git_cached_obj *ptr;
|
||||
git_mutex lock;
|
||||
unsigned int lru;
|
||||
} cache_node;
|
||||
|
||||
typedef struct {
|
||||
@ -31,7 +30,7 @@ typedef struct {
|
||||
} git_cache;
|
||||
|
||||
|
||||
void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr);
|
||||
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr);
|
||||
void git_cache_free(git_cache *cache);
|
||||
|
||||
void *git_cache_try_store(git_cache *cache, void *entry);
|
||||
|
15
src/commit.c
15
src/commit.c
@ -224,9 +224,18 @@ int git_commit_create(
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (git_reference_type(head) == GIT_REF_SYMBOLIC) {
|
||||
if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS)
|
||||
error = git_reference_resolve(&head, head);
|
||||
if (error < GIT_SUCCESS) {
|
||||
if (error != GIT_ENOTFOUND)
|
||||
return error;
|
||||
/*
|
||||
* The target of the reference was not found. This can happen
|
||||
* just after a repository has been initialized (the master
|
||||
* branch doesn't exist yet, as it doesn't have anything to
|
||||
* point to) or after an orphan checkout, so if the target
|
||||
* branch doesn't exist yet, create it and return.
|
||||
*/
|
||||
return git_reference_create_oid_f(&head, repo, git_reference_target(head), oid);
|
||||
}
|
||||
|
||||
error = git_reference_set_oid(head, oid);
|
||||
@ -277,7 +286,7 @@ int commit_parse_buffer(git_commit *commit, const void *data, size_t len)
|
||||
|
||||
if (buffer < buffer_end) {
|
||||
const char *line_end;
|
||||
size_t message_len = buffer_end - buffer;
|
||||
size_t message_len;
|
||||
|
||||
/* Long message */
|
||||
message_len = buffer_end - buffer;
|
||||
|
@ -50,10 +50,14 @@ typedef SSIZE_T ssize_t;
|
||||
|
||||
#include "git2/common.h"
|
||||
#include "git2/types.h"
|
||||
#include "util.h"
|
||||
#include "git2/errors.h"
|
||||
#include "thread-utils.h"
|
||||
#include "bswap.h"
|
||||
|
||||
#define GIT_PATH_MAX 4096
|
||||
extern int git__throw(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3);
|
||||
extern int git__rethrow(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3);
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#endif /* INCLUDE_common_h__ */
|
||||
|
323
src/config.c
Normal file
323
src/config.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "fileops.h"
|
||||
#include "hashtable.h"
|
||||
#include "config.h"
|
||||
#include "git2/config_backend.h"
|
||||
#include "vector.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
typedef struct {
|
||||
git_config_backend *backend;
|
||||
int priority;
|
||||
} backend_internal;
|
||||
|
||||
int git_config_open_bare(git_config **out, const char *path)
|
||||
{
|
||||
git_config_backend *backend = NULL;
|
||||
git_config *cfg = NULL;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
error = git_config_new(&cfg);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto error;
|
||||
|
||||
error = git_config_backend_file(&backend, path);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto error;
|
||||
|
||||
error = git_config_add_backend(cfg, backend, 1);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto error;
|
||||
|
||||
error = backend->open(backend);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto error;
|
||||
|
||||
*out = cfg;
|
||||
|
||||
return error;
|
||||
|
||||
error:
|
||||
if(backend)
|
||||
backend->free(backend);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void git_config_free(git_config *cfg)
|
||||
{
|
||||
unsigned int i;
|
||||
git_config_backend *backend;
|
||||
backend_internal *internal;
|
||||
|
||||
for(i = 0; i < cfg->backends.length; ++i){
|
||||
internal = git_vector_get(&cfg->backends, i);
|
||||
backend = internal->backend;
|
||||
backend->free(backend);
|
||||
free(internal);
|
||||
}
|
||||
|
||||
git_vector_free(&cfg->backends);
|
||||
free(cfg);
|
||||
}
|
||||
|
||||
static int config_backend_cmp(const void *a, const void *b)
|
||||
{
|
||||
const backend_internal *bk_a = *(const backend_internal **)(a);
|
||||
const backend_internal *bk_b = *(const backend_internal **)(b);
|
||||
|
||||
return bk_b->priority - bk_a->priority;
|
||||
}
|
||||
|
||||
int git_config_new(git_config **out)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
cfg = git__malloc(sizeof(git_config));
|
||||
if (cfg == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memset(cfg, 0x0, sizeof(git_config));
|
||||
|
||||
if (git_vector_init(&cfg->backends, 3, config_backend_cmp) < 0) {
|
||||
free(cfg);
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
*out = cfg;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_config_add_backend(git_config *cfg, git_config_backend *backend, int priority)
|
||||
{
|
||||
backend_internal *internal;
|
||||
|
||||
assert(cfg && backend);
|
||||
|
||||
internal = git__malloc(sizeof(backend_internal));
|
||||
if (internal == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
internal->backend = backend;
|
||||
internal->priority = priority;
|
||||
|
||||
if (git_vector_insert(&cfg->backends, internal) < 0) {
|
||||
free(internal);
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
git_vector_sort(&cfg->backends);
|
||||
internal->backend->cfg = cfg;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop over all the variables
|
||||
*/
|
||||
|
||||
int git_config_foreach(git_config *cfg, int (*fn)(const char *, void *), void *data)
|
||||
{
|
||||
int ret = GIT_SUCCESS;
|
||||
unsigned int i;
|
||||
backend_internal *internal;
|
||||
git_config_backend *backend;
|
||||
|
||||
for(i = 0; i < cfg->backends.length && ret == 0; ++i) {
|
||||
internal = git_vector_get(&cfg->backends, i);
|
||||
backend = internal->backend;
|
||||
ret = backend->foreach(backend, fn, data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**************
|
||||
* Setters
|
||||
**************/
|
||||
|
||||
/*
|
||||
* Internal function to actually set the string value of a variable
|
||||
*/
|
||||
|
||||
int git_config_set_long(git_config *cfg, const char *name, long int value)
|
||||
{
|
||||
char str_value[5]; /* Most numbers should fit in here */
|
||||
int buf_len = sizeof(str_value), ret;
|
||||
char *help_buf = NULL;
|
||||
|
||||
if ((ret = snprintf(str_value, buf_len, "%ld", value)) >= buf_len - 1){
|
||||
/* The number is too large, we need to allocate more memory */
|
||||
buf_len = ret + 1;
|
||||
help_buf = git__malloc(buf_len);
|
||||
snprintf(help_buf, buf_len, "%ld", value);
|
||||
ret = git_config_set_string(cfg, name, help_buf);
|
||||
free(help_buf);
|
||||
} else {
|
||||
ret = git_config_set_string(cfg, name, str_value);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_set_int(git_config *cfg, const char *name, int value)
|
||||
{
|
||||
return git_config_set_long(cfg, name, value);
|
||||
}
|
||||
|
||||
int git_config_set_bool(git_config *cfg, const char *name, int value)
|
||||
{
|
||||
const char *str_value;
|
||||
|
||||
if (value == 0)
|
||||
str_value = "false";
|
||||
else
|
||||
str_value = "true";
|
||||
|
||||
return git_config_set_string(cfg, name, str_value);
|
||||
}
|
||||
|
||||
int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
||||
{
|
||||
backend_internal *internal;
|
||||
git_config_backend *backend;
|
||||
|
||||
assert(cfg->backends.length > 0);
|
||||
|
||||
internal = git_vector_get(&cfg->backends, 0);
|
||||
backend = internal->backend;
|
||||
|
||||
return backend->set(backend, name, value);
|
||||
}
|
||||
|
||||
/***********
|
||||
* Getters
|
||||
***********/
|
||||
|
||||
int git_config_get_long(git_config *cfg, const char *name, long int *out)
|
||||
{
|
||||
const char *value, *num_end;
|
||||
int ret;
|
||||
long int num;
|
||||
|
||||
ret = git_config_get_string(cfg, name, &value);
|
||||
if (ret < GIT_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = git__strtol32(&num, value, &num_end, 0);
|
||||
if (ret < GIT_SUCCESS)
|
||||
return ret;
|
||||
|
||||
switch (*num_end) {
|
||||
case '\0':
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
num *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
num *= 1024 * 1024;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
num *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
|
||||
*out = num;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_config_get_int(git_config *cfg, const char *name, int *out)
|
||||
{
|
||||
long int tmp;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_long(cfg, name, &tmp);
|
||||
|
||||
*out = (int) tmp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_get_bool(git_config *cfg, const char *name, int *out)
|
||||
{
|
||||
const char *value;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
error = git_config_get_string(cfg, name, &value);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* A missing value means true */
|
||||
if (value == NULL) {
|
||||
*out = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!strcasecmp(value, "true") ||
|
||||
!strcasecmp(value, "yes") ||
|
||||
!strcasecmp(value, "on")) {
|
||||
*out = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
if (!strcasecmp(value, "false") ||
|
||||
!strcasecmp(value, "no") ||
|
||||
!strcasecmp(value, "off")) {
|
||||
*out = 0;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Try to parse it as an integer */
|
||||
error = git_config_get_int(cfg, name, out);
|
||||
if (error == GIT_SUCCESS)
|
||||
*out = !!(*out);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_config_get_string(git_config *cfg, const char *name, const char **out)
|
||||
{
|
||||
backend_internal *internal;
|
||||
git_config_backend *backend;
|
||||
|
||||
assert(cfg->backends.length > 0);
|
||||
|
||||
internal = git_vector_get(&cfg->backends, 0);
|
||||
backend = internal->backend;
|
||||
|
||||
return backend->get(backend, name, out);
|
||||
}
|
||||
|
12
src/config.h
Normal file
12
src/config.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef INCLUDE_config_h__
|
||||
#define INCLUDE_config_h__
|
||||
|
||||
#include "git2.h"
|
||||
#include "git2/config.h"
|
||||
#include "vector.h"
|
||||
|
||||
struct git_config {
|
||||
git_vector backends;
|
||||
};
|
||||
|
||||
#endif
|
1011
src/config_file.c
Normal file
1011
src/config_file.c
Normal file
File diff suppressed because it is too large
Load Diff
66
src/errors.c
66
src/errors.c
@ -1,6 +1,35 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "git2/thread-utils.h" /* for GIT_TLS */
|
||||
#include "thread-utils.h" /* for GIT_TLS */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static GIT_TLS char g_last_error[1024];
|
||||
|
||||
static struct {
|
||||
int num;
|
||||
const char *str;
|
||||
@ -13,7 +42,7 @@ static struct {
|
||||
{GIT_EOBJTYPE, "The specified object is of invalid type"},
|
||||
{GIT_EOBJCORRUPTED, "The specified object has its data corrupted"},
|
||||
{GIT_ENOTAREPO, "The specified repository is invalid"},
|
||||
{GIT_EINVALIDTYPE, "The object type is invalid or doesn't match"},
|
||||
{GIT_EINVALIDTYPE, "The object or config variable type is invalid or doesn't match"},
|
||||
{GIT_EMISSINGOBJDATA, "The object cannot be written that because it's missing internal data"},
|
||||
{GIT_EPACKCORRUPTED, "The packfile for the ODB is corrupted"},
|
||||
{GIT_EFLOCKFAIL, "Failed to adquire or release a file lock"},
|
||||
@ -46,3 +75,38 @@ const char *git_strerror(int num)
|
||||
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
int git__rethrow(int error, const char *msg, ...)
|
||||
{
|
||||
char new_error[1024];
|
||||
char *old_error = NULL;
|
||||
|
||||
va_list va;
|
||||
|
||||
va_start(va, msg);
|
||||
vsnprintf(new_error, sizeof(new_error), msg, va);
|
||||
va_end(va);
|
||||
|
||||
old_error = strdup(g_last_error);
|
||||
snprintf(g_last_error, sizeof(g_last_error), "%s \n - %s", new_error, old_error);
|
||||
free(old_error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git__throw(int error, const char *msg, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, msg);
|
||||
vsnprintf(g_last_error, sizeof(g_last_error), msg, va);
|
||||
va_end(va);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const char *git_lasterror(void)
|
||||
{
|
||||
return g_last_error;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ int gitfo_mkdir_2file(const char *file_path)
|
||||
|
||||
error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
return git__throw(GIT_EINVALIDPATH, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path);
|
||||
|
||||
/* Does the containing folder exist? */
|
||||
if (gitfo_isdir(target_folder_path)) {
|
||||
@ -19,7 +19,7 @@ int gitfo_mkdir_2file(const char *file_path)
|
||||
/* Let's create the tree structure */
|
||||
error = gitfo_mkdir_recurs(target_folder_path, mode);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
return error; /* The callee already takes care of setting the correct error message. */
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
@ -164,19 +164,19 @@ int gitfo_read_file(gitfo_buf *obj, const char *path)
|
||||
|
||||
if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) {
|
||||
gitfo_close(fd);
|
||||
return GIT_ERROR;
|
||||
return git__throw(GIT_ERROR, "Failed to read file `%s`. Either an error occured while calculating its size or the file is too large", path);
|
||||
}
|
||||
len = (size_t) size;
|
||||
|
||||
if ((buff = git__malloc(len + 1)) == NULL) {
|
||||
gitfo_close(fd);
|
||||
return GIT_ERROR;
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if (gitfo_read(fd, buff, len) < 0) {
|
||||
gitfo_close(fd);
|
||||
free(buff);
|
||||
return GIT_ERROR;
|
||||
return git__throw(GIT_ERROR, "Failed to read file `%s`", path);
|
||||
}
|
||||
buff[len] = '\0';
|
||||
|
||||
@ -197,13 +197,15 @@ void gitfo_free_buf(gitfo_buf *obj)
|
||||
|
||||
int gitfo_mv(const char *from, const char *to)
|
||||
{
|
||||
int error;
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
/*
|
||||
* Win32 POSIX compilance my ass. If the destination
|
||||
* file exists, the `rename` call fails. This is as
|
||||
* close as it gets with the Win32 API.
|
||||
*/
|
||||
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
|
||||
error = MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
|
||||
#else
|
||||
/* Don't even try this on Win32 */
|
||||
if (!link(from, to)) {
|
||||
@ -214,16 +216,21 @@ int gitfo_mv(const char *from, const char *to)
|
||||
if (!rename(from, to))
|
||||
return GIT_SUCCESS;
|
||||
|
||||
return GIT_EOSERR;
|
||||
error = GIT_EOSERR;
|
||||
#endif
|
||||
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__throw(error, "Failed to move file from `%s`to `%s`", from, to);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int gitfo_mv_force(const char *from, const char *to)
|
||||
{
|
||||
if (gitfo_mkdir_2file(to) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */
|
||||
|
||||
return gitfo_mv(from, to);
|
||||
return gitfo_mv(from, to); /* The callee already takes care of setting the correct error message. */
|
||||
}
|
||||
|
||||
int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
|
||||
@ -338,7 +345,7 @@ int gitfo_dirent(
|
||||
struct dirent *de;
|
||||
|
||||
if (!wd_len || path_sz < wd_len + 2)
|
||||
return GIT_ERROR;
|
||||
return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path);
|
||||
|
||||
while (path[wd_len - 1] == '/')
|
||||
wd_len--;
|
||||
@ -347,7 +354,7 @@ int gitfo_dirent(
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return GIT_EOSERR;
|
||||
return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path);
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
size_t de_len;
|
||||
@ -364,14 +371,14 @@ int gitfo_dirent(
|
||||
de_len = strlen(de->d_name);
|
||||
if (path_sz < wd_len + de_len + 1) {
|
||||
closedir(dir);
|
||||
return GIT_ERROR;
|
||||
return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path);
|
||||
}
|
||||
|
||||
strcpy(path + wd_len, de->d_name);
|
||||
result = fn(arg, path);
|
||||
if (result < GIT_SUCCESS) {
|
||||
closedir(dir);
|
||||
return result;
|
||||
return result; /* The callee is reponsible for setting the correct error message */
|
||||
}
|
||||
if (result > 0) {
|
||||
closedir(dir);
|
||||
@ -399,7 +406,7 @@ int retrieve_path_root_offset(const char *path)
|
||||
if (*(path + offset) == '/')
|
||||
return offset;
|
||||
|
||||
return GIT_ERROR;
|
||||
return -1; /* Not a real error. Rather a signal than the path is not rooted */
|
||||
}
|
||||
|
||||
|
||||
@ -438,7 +445,11 @@ int gitfo_mkdir_recurs(const char *path, int mode)
|
||||
error = gitfo_mkdir(path, mode);
|
||||
|
||||
free(path_copy);
|
||||
return error;
|
||||
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__throw(error, "Failed to recursively create `%s` tree structure", path);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int retrieve_previous_path_component_start(const char *path)
|
||||
@ -484,7 +495,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
||||
if (root_path_offset < 0) {
|
||||
error = gitfo_getcwd(buffer_out, size);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
return error; /* The callee already takes care of setting the correct error message. */
|
||||
|
||||
len = strlen(buffer_out);
|
||||
buffer_out += len;
|
||||
@ -529,7 +540,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
||||
|
||||
/* Are we escaping out of the root dir? */
|
||||
if (len < 0)
|
||||
return GIT_EINVALIDPATH;
|
||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize path `%s`. The path escapes out of the root directory", path);
|
||||
|
||||
buffer_out = (char *)buffer_out_start + len;
|
||||
continue;
|
||||
@ -537,7 +548,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
||||
|
||||
/* Guard against potential multiple dot path traversal (cf http://cwe.mitre.org/data/definitions/33.html) */
|
||||
if (only_dots && segment_len > 0)
|
||||
return GIT_EINVALIDPATH;
|
||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize path `%s`. The path contains a segment with three `.` or more", path);
|
||||
|
||||
*buffer_out++ = '/';
|
||||
len++;
|
||||
@ -557,21 +568,21 @@ int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path)
|
||||
|
||||
/* Let's make sure the filename isn't empty nor a dot */
|
||||
if (path_len == 0 || (path_len == 1 && *path == '.'))
|
||||
return GIT_EINVALIDPATH;
|
||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path is either empty or equals `.`", path);
|
||||
|
||||
/* Let's make sure the filename doesn't end with "/", "/." or "/.." */
|
||||
for (i = 1; path_len > i && i < 4; i++) {
|
||||
if (!strncmp(path + path_len - i, pattern, i))
|
||||
return GIT_EINVALIDPATH;
|
||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
|
||||
}
|
||||
|
||||
error = gitfo_prettify_dir_path(buffer_out, size, path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
return error; /* The callee already takes care of setting the correct error message. */
|
||||
|
||||
path_len = strlen(buffer_out);
|
||||
if (path_len < 2)
|
||||
return GIT_EINVALIDPATH;
|
||||
if (path_len < 2) /* TODO: Fixme. We should also take of detecting Windows rooted path (probably through usage of retrieve_path_root_offset) */
|
||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
|
||||
|
||||
/* Remove the trailing slash */
|
||||
buffer_out[path_len - 1] = '\0';
|
||||
@ -616,11 +627,11 @@ int gitfo_getcwd(char *buffer_out, size_t size)
|
||||
#ifdef GIT_WIN32
|
||||
cwd_buffer = _getcwd(buffer_out, size);
|
||||
#else
|
||||
cwd_buffer = getcwd(buffer_out, size); //TODO: Fixme. Ensure the required headers are correctly included
|
||||
cwd_buffer = getcwd(buffer_out, size);
|
||||
#endif
|
||||
|
||||
if (cwd_buffer == NULL)
|
||||
return GIT_EOSERR;
|
||||
return git__throw(GIT_EOSERR, "Failed to retrieve current working directory");
|
||||
|
||||
posixify_path(buffer_out);
|
||||
|
||||
|
156
src/index.c
156
src/index.c
@ -103,6 +103,7 @@ static git_index_tree *read_tree_internal(const char **, const char *, git_index
|
||||
static int read_unmerged_internal(git_index *, const char **, size_t buffer_size);
|
||||
|
||||
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
|
||||
static int is_index_extended(git_index *index);
|
||||
static void sort_index(git_index *index);
|
||||
static int write_index(git_index *index, git_filebuf *file);
|
||||
|
||||
@ -317,56 +318,12 @@ git_index_entry *git_index_get(git_index *index, int n)
|
||||
return git_vector_get(&index->entries, (unsigned int)n);
|
||||
}
|
||||
|
||||
int git_index_add(git_index *index, const char *rel_path, int stage)
|
||||
{
|
||||
git_index_entry entry;
|
||||
char full_path[GIT_PATH_MAX];
|
||||
struct stat st;
|
||||
int error;
|
||||
|
||||
if (index->repository == NULL)
|
||||
return GIT_EBAREINDEX;
|
||||
|
||||
git__joinpath(full_path, index->repository->path_workdir, rel_path);
|
||||
|
||||
if (gitfo_exists(full_path) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if (gitfo_stat(full_path, &st) < 0)
|
||||
return GIT_EOSERR;
|
||||
|
||||
if (stage < 0 || stage > 3)
|
||||
return GIT_ERROR;
|
||||
|
||||
memset(&entry, 0x0, sizeof(git_index_entry));
|
||||
|
||||
entry.ctime.seconds = (git_time_t)st.st_ctime;
|
||||
entry.mtime.seconds = (git_time_t)st.st_mtime;
|
||||
/* entry.mtime.nanoseconds = st.st_mtimensec; */
|
||||
/* entry.ctime.nanoseconds = st.st_ctimensec; */
|
||||
entry.dev= st.st_rdev;
|
||||
entry.ino = st.st_ino;
|
||||
entry.mode = st.st_mode;
|
||||
entry.uid = st.st_uid;
|
||||
entry.gid = st.st_gid;
|
||||
entry.file_size = st.st_size;
|
||||
|
||||
/* write the blob to disk and get the oid */
|
||||
if ((error = git_blob_create_fromfile(&entry.oid, index->repository, rel_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
|
||||
entry.path = (char *)rel_path; /* do not duplicate; index_insert already does this */
|
||||
|
||||
return git_index_insert(index, &entry);
|
||||
}
|
||||
|
||||
void sort_index(git_index *index)
|
||||
static void sort_index(git_index *index)
|
||||
{
|
||||
git_vector_sort(&index->entries);
|
||||
}
|
||||
|
||||
int git_index_insert(git_index *index, const git_index_entry *source_entry)
|
||||
static int index_insert(git_index *index, const git_index_entry *source_entry, int replace)
|
||||
{
|
||||
git_index_entry *entry;
|
||||
size_t path_length;
|
||||
@ -402,13 +359,15 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry)
|
||||
/* look if an entry with this path already exists */
|
||||
position = git_index_find(index, source_entry->path);
|
||||
|
||||
/* if no entry exists, add the entry at the end;
|
||||
/* if no entry exists and replace is not set,
|
||||
* add the entry at the end;
|
||||
* the index is no longer sorted */
|
||||
if (position == GIT_ENOTFOUND) {
|
||||
if (!replace || position == GIT_ENOTFOUND) {
|
||||
if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
/* if a previous entry exists, replace it */
|
||||
/* if a previous entry exists and replace is set,
|
||||
* replace it */
|
||||
} else {
|
||||
git_index_entry **entry_array = (git_index_entry **)index->entries.contents;
|
||||
|
||||
@ -421,6 +380,81 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int index_init_entry(git_index_entry *entry, git_index *index, const char *rel_path, int stage)
|
||||
{
|
||||
char full_path[GIT_PATH_MAX];
|
||||
struct stat st;
|
||||
int error;
|
||||
|
||||
if (index->repository == NULL)
|
||||
return GIT_EBAREINDEX;
|
||||
|
||||
git__joinpath(full_path, index->repository->path_workdir, rel_path);
|
||||
|
||||
if (gitfo_exists(full_path) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if (gitfo_stat(full_path, &st) < 0)
|
||||
return GIT_EOSERR;
|
||||
|
||||
if (stage < 0 || stage > 3)
|
||||
return GIT_ERROR;
|
||||
|
||||
memset(entry, 0x0, sizeof(git_index_entry));
|
||||
|
||||
entry->ctime.seconds = (git_time_t)st.st_ctime;
|
||||
entry->mtime.seconds = (git_time_t)st.st_mtime;
|
||||
/* entry.mtime.nanoseconds = st.st_mtimensec; */
|
||||
/* entry.ctime.nanoseconds = st.st_ctimensec; */
|
||||
entry->dev= st.st_rdev;
|
||||
entry->ino = st.st_ino;
|
||||
entry->mode = st.st_mode;
|
||||
entry->uid = st.st_uid;
|
||||
entry->gid = st.st_gid;
|
||||
entry->file_size = st.st_size;
|
||||
|
||||
/* write the blob to disk and get the oid */
|
||||
if ((error = git_blob_create_fromfile(&entry->oid, index->repository, rel_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
|
||||
entry->path = (char *)rel_path; /* do not duplicate; index_insert already does this */
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_index_add(git_index *index, const char *path, int stage)
|
||||
{
|
||||
int error;
|
||||
git_index_entry entry;
|
||||
|
||||
if ((error = index_init_entry(&entry, index, path, stage)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
return index_insert(index, &entry, 1);
|
||||
}
|
||||
|
||||
int git_index_append(git_index *index, const char *path, int stage)
|
||||
{
|
||||
int error;
|
||||
git_index_entry entry;
|
||||
|
||||
if ((error = index_init_entry(&entry, index, path, stage)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
return index_insert(index, &entry, 0);
|
||||
}
|
||||
|
||||
int git_index_add2(git_index *index, const git_index_entry *source_entry)
|
||||
{
|
||||
return index_insert(index, source_entry, 1);
|
||||
}
|
||||
|
||||
int git_index_append2(git_index *index, const git_index_entry *source_entry)
|
||||
{
|
||||
return index_insert(index, source_entry, 0);
|
||||
}
|
||||
|
||||
|
||||
int git_index_remove(git_index *index, int position)
|
||||
{
|
||||
assert(index);
|
||||
@ -798,6 +832,24 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int is_index_extended(git_index *index)
|
||||
{
|
||||
unsigned int i, extended;
|
||||
|
||||
extended = 0;
|
||||
|
||||
for (i = 0; i < index->entries.length; ++i) {
|
||||
git_index_entry *entry;
|
||||
entry = git_vector_get(&index->entries, i);
|
||||
entry->flags &= ~GIT_IDXENTRY_EXTENDED;
|
||||
if (entry->flags_extended & GIT_IDXENTRY_EXTENDED_FLAGS) {
|
||||
extended++;
|
||||
entry->flags |= GIT_IDXENTRY_EXTENDED;
|
||||
}
|
||||
}
|
||||
return extended;
|
||||
}
|
||||
|
||||
static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
|
||||
{
|
||||
struct entry_short *ondisk;
|
||||
@ -866,12 +918,14 @@ static int write_index(git_index *index, git_filebuf *file)
|
||||
|
||||
struct index_header header;
|
||||
|
||||
int is_extended = 1;
|
||||
int is_extended;
|
||||
|
||||
assert(index && file);
|
||||
|
||||
is_extended = is_index_extended(index);
|
||||
|
||||
header.signature = htonl(INDEX_HEADER_SIG);
|
||||
header.version = htonl(is_extended ? INDEX_VERSION_NUMBER : INDEX_VERSION_NUMBER_EXT);
|
||||
header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER);
|
||||
header.entry_count = htonl(index->entries.length);
|
||||
|
||||
git_filebuf_write(file, &header, sizeof(struct index_header));
|
||||
|
14
src/odb.c
14
src/odb.c
@ -221,7 +221,7 @@ static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend
|
||||
*
|
||||
***********************************************************/
|
||||
|
||||
int backend_sort_cmp(const void *a, const void *b)
|
||||
static int backend_sort_cmp(const void *a, const void *b)
|
||||
{
|
||||
const backend_internal *backend_a = *(const backend_internal **)(a);
|
||||
const backend_internal *backend_b = *(const backend_internal **)(b);
|
||||
@ -234,15 +234,19 @@ int backend_sort_cmp(const void *a, const void *b)
|
||||
|
||||
int git_odb_new(git_odb **out)
|
||||
{
|
||||
int error;
|
||||
|
||||
git_odb *db = git__calloc(1, sizeof(*db));
|
||||
if (!db)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
|
||||
error = git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
|
||||
if ((error = git_vector_init(&db->backends, 4, backend_sort_cmp)) < GIT_SUCCESS) {
|
||||
free(db);
|
||||
return GIT_ENOMEM;
|
||||
return error;
|
||||
}
|
||||
|
||||
*out = db;
|
||||
@ -444,7 +448,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
|
||||
return error;
|
||||
|
||||
*len_p = object->raw.len;
|
||||
*type_p = object->raw.len;
|
||||
*type_p = object->raw.type;
|
||||
git_odb_object_close(object);
|
||||
}
|
||||
|
||||
|
@ -336,7 +336,6 @@ static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj)
|
||||
{
|
||||
unsigned char head[64], *buf;
|
||||
z_stream zs;
|
||||
int z_status;
|
||||
obj_hdr hdr;
|
||||
size_t used;
|
||||
|
||||
@ -350,7 +349,7 @@ static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj)
|
||||
* inflate the initial part of the io buffer in order
|
||||
* to parse the object header (type and size).
|
||||
*/
|
||||
if ((z_status = start_inflate(&zs, obj, head, sizeof(head))) < Z_OK)
|
||||
if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
if ((used = get_object_header(&hdr, head)) == 0)
|
||||
@ -434,6 +433,9 @@ static int read_header_loose(git_rawobj *out, const char *loc)
|
||||
if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
|
||||
set_stream_input(&zs, raw_buffer, read_bytes);
|
||||
z_return = inflate(&zs, 0);
|
||||
} else {
|
||||
z_return = Z_STREAM_END;
|
||||
break;
|
||||
}
|
||||
} while (z_return == Z_OK);
|
||||
|
||||
|
@ -113,7 +113,7 @@ struct pack_backend {
|
||||
git_vector packs;
|
||||
struct pack_file *last_found;
|
||||
char *pack_folder;
|
||||
off_t pack_folder_size;
|
||||
time_t pack_folder_mtime;
|
||||
|
||||
size_t window_size; /* needs default value */
|
||||
|
||||
@ -874,7 +874,7 @@ static int packfile_refresh_all(struct pack_backend *backend)
|
||||
if (gitfo_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if (st.st_size != backend->pack_folder_size) {
|
||||
if (st.st_mtime != backend->pack_folder_mtime) {
|
||||
char path[GIT_PATH_MAX];
|
||||
strcpy(path, backend->pack_folder);
|
||||
|
||||
@ -884,7 +884,7 @@ static int packfile_refresh_all(struct pack_backend *backend)
|
||||
return error;
|
||||
|
||||
git_vector_sort(&backend->packs);
|
||||
backend->pack_folder_size = st.st_size;
|
||||
backend->pack_folder_mtime = st.st_mtime;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
@ -1385,6 +1385,7 @@ void pack_backend__free(git_odb_backend *_backend)
|
||||
}
|
||||
|
||||
git_vector_free(&backend->packs);
|
||||
free(backend->pack_folder);
|
||||
free(backend);
|
||||
}
|
||||
|
||||
@ -1408,7 +1409,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
|
||||
git__joinpath(path, objects_dir, "pack");
|
||||
if (gitfo_isdir(path) == GIT_SUCCESS) {
|
||||
backend->pack_folder = git__strdup(path);
|
||||
backend->pack_folder_size = -1;
|
||||
backend->pack_folder_mtime = 0;
|
||||
|
||||
if (backend->pack_folder == NULL) {
|
||||
free(backend);
|
||||
|
51
src/refs.c
51
src/refs.c
@ -122,7 +122,8 @@ static int reference_create(
|
||||
else if (type == GIT_REF_OID)
|
||||
size = sizeof(reference_oid);
|
||||
else
|
||||
return GIT_EINVALIDREFSTATE;
|
||||
return git__throw(GIT_EINVALIDARGS,
|
||||
"Invalid reference type. Use either GIT_REF_OID or GIT_REF_SYMBOLIC as type specifier");
|
||||
|
||||
reference = git__malloc(size);
|
||||
if (reference == NULL)
|
||||
@ -159,11 +160,9 @@ static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *re
|
||||
/* Determine the full path of the file */
|
||||
git__joinpath(path, repo_path, ref_name);
|
||||
|
||||
if (gitfo_stat(path, &st) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return GIT_EOBJCORRUPTED;
|
||||
if (gitfo_stat(path, &st) < 0 || S_ISDIR(st.st_mode))
|
||||
return git__throw(GIT_ENOTFOUND,
|
||||
"Cannot read reference file '%s'", ref_name);
|
||||
|
||||
if (mtime)
|
||||
*mtime = st.st_mtime;
|
||||
@ -205,7 +204,8 @@ static int loose_update(git_reference *ref)
|
||||
else if (ref->type == GIT_REF_OID)
|
||||
error = loose_parse_oid(ref, &ref_file);
|
||||
else
|
||||
error = GIT_EINVALIDREFSTATE;
|
||||
error = git__throw(GIT_EOBJCORRUPTED,
|
||||
"Invalid reference type (%d) for loose reference", ref->type);
|
||||
|
||||
gitfo_free_buf(&ref_file);
|
||||
|
||||
@ -229,7 +229,8 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content)
|
||||
ref_sym = (reference_symbolic *)ref;
|
||||
|
||||
if (file_content->len < (header_len + 1))
|
||||
return GIT_EREFCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED,
|
||||
"Failed to parse loose reference. Object too short");
|
||||
|
||||
/*
|
||||
* Assume we have already checked for the header
|
||||
@ -246,7 +247,8 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content)
|
||||
/* remove newline at the end of file */
|
||||
eol = strchr(ref_sym->target, '\n');
|
||||
if (eol == NULL)
|
||||
return GIT_EREFCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED,
|
||||
"Failed to parse loose reference. Missing EOL");
|
||||
|
||||
*eol = '\0';
|
||||
if (eol[-1] == '\r')
|
||||
@ -257,6 +259,7 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content)
|
||||
|
||||
static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content)
|
||||
{
|
||||
int error;
|
||||
reference_oid *ref_oid;
|
||||
char *buffer;
|
||||
|
||||
@ -265,17 +268,19 @@ static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content)
|
||||
|
||||
/* File format: 40 chars (OID) + newline */
|
||||
if (file_content->len < GIT_OID_HEXSZ + 1)
|
||||
return GIT_EREFCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED,
|
||||
"Failed to parse loose reference. Reference too short");
|
||||
|
||||
if (git_oid_mkstr(&ref_oid->oid, buffer) < GIT_SUCCESS)
|
||||
return GIT_EREFCORRUPTED;
|
||||
if ((error = git_oid_mkstr(&ref_oid->oid, buffer)) < GIT_SUCCESS)
|
||||
return git__rethrow(GIT_EOBJCORRUPTED, "Failed to parse loose reference.");
|
||||
|
||||
buffer = buffer + GIT_OID_HEXSZ;
|
||||
if (*buffer == '\r')
|
||||
buffer++;
|
||||
|
||||
if (*buffer != '\n')
|
||||
return GIT_EREFCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED,
|
||||
"Failed to parse loose reference. Missing EOL");
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
@ -387,7 +392,7 @@ static int loose_write(git_reference *ref)
|
||||
strcpy(ref_contents, GIT_SYMREF);
|
||||
strcat(ref_contents, ref_sym->target);
|
||||
} else {
|
||||
error = GIT_EINVALIDREFSTATE;
|
||||
error = git__throw(GIT_EOBJCORRUPTED, "Failed to write reference. Invalid reference type");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@ -684,7 +689,7 @@ static int packed_loadloose(git_repository *repository)
|
||||
|
||||
/* Remove any loose references from the cache */
|
||||
{
|
||||
const void *_unused;
|
||||
const void *GIT_UNUSED(_unused);
|
||||
git_reference *reference;
|
||||
|
||||
GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference,
|
||||
@ -787,6 +792,8 @@ static int packed_find_peel(reference_oid *ref)
|
||||
*/
|
||||
}
|
||||
|
||||
git_object_close(object);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -868,7 +875,7 @@ static int packed_write(git_repository *repo)
|
||||
/* Load all the packfile into a vector */
|
||||
{
|
||||
git_reference *reference;
|
||||
const void *_unused;
|
||||
const void *GIT_UNUSED(_unused);
|
||||
|
||||
GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference,
|
||||
git_vector_insert(&packing_list, reference); /* cannot fail: vector already has the right size */
|
||||
@ -1480,8 +1487,9 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)
|
||||
for (i = 0; i < MAX_NESTING_LEVEL; ++i) {
|
||||
reference_symbolic *ref_sym;
|
||||
|
||||
*resolved_ref = ref;
|
||||
|
||||
if (ref->type & GIT_REF_OID) {
|
||||
*resolved_ref = ref;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1518,7 +1526,7 @@ int git_reference_listcb(git_repository *repo, unsigned int list_flags, int (*ca
|
||||
/* list all the packed references first */
|
||||
if (list_flags & GIT_REF_PACKED) {
|
||||
const char *ref_name;
|
||||
void *_unused;
|
||||
void *GIT_UNUSED(_unused);
|
||||
|
||||
if ((error = packed_load(repo)) < GIT_SUCCESS)
|
||||
return error;
|
||||
@ -1597,7 +1605,7 @@ int git_repository__refcache_init(git_refcache *refs)
|
||||
void git_repository__refcache_free(git_refcache *refs)
|
||||
{
|
||||
git_reference *reference;
|
||||
const void *_unused;
|
||||
const void *GIT_UNUSED(_unused);
|
||||
|
||||
assert(refs);
|
||||
|
||||
@ -1692,8 +1700,9 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
|
||||
}
|
||||
|
||||
/* Object id refname have to contain at least one slash, except
|
||||
* for HEAD in a detached state */
|
||||
if (is_oid_ref && !contains_a_slash && strcmp(name, GIT_HEAD_FILE))
|
||||
* for HEAD in a detached state or MERGE_HEAD if we're in the
|
||||
* middle of a merge */
|
||||
if (is_oid_ref && !contains_a_slash && (strcmp(name, GIT_HEAD_FILE) && strcmp(name, GIT_MERGE_HEAD_FILE)))
|
||||
return GIT_EINVALIDREFNAME;
|
||||
|
||||
/* A refname can not end with ".lock" */
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH 100
|
||||
|
||||
#define GIT_HEAD_FILE "HEAD"
|
||||
#define GIT_MERGE_HEAD_FILE "MERGE_HEAD"
|
||||
#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
|
||||
|
||||
struct git_reference {
|
||||
|
@ -58,7 +58,6 @@ static int assign_repository_dirs(
|
||||
const char *git_work_tree)
|
||||
{
|
||||
char path_aux[GIT_PATH_MAX];
|
||||
size_t git_dir_path_len;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
assert(repo);
|
||||
@ -70,8 +69,6 @@ static int assign_repository_dirs(
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
git_dir_path_len = strlen(path_aux);
|
||||
|
||||
/* store GIT_DIR */
|
||||
repo->path_repository = git__strdup(path_aux);
|
||||
if (repo->path_repository == NULL)
|
||||
@ -127,16 +124,16 @@ static int check_repository_dirs(git_repository *repo)
|
||||
char path_aux[GIT_PATH_MAX];
|
||||
|
||||
if (gitfo_isdir(repo->path_repository) < GIT_SUCCESS)
|
||||
return GIT_ENOTAREPO;
|
||||
return git__throw(GIT_ENOTAREPO, "`%s` is not a folder", repo->path_repository);
|
||||
|
||||
/* Ensure GIT_OBJECT_DIRECTORY exists */
|
||||
if (gitfo_isdir(repo->path_odb) < GIT_SUCCESS)
|
||||
return GIT_ENOTAREPO;
|
||||
return git__throw(GIT_ENOTAREPO, "`%s` does not exist", repo->path_odb);
|
||||
|
||||
/* Ensure HEAD file exists */
|
||||
git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE);
|
||||
if (gitfo_exists(path_aux) < 0)
|
||||
return GIT_ENOTAREPO;
|
||||
return git__throw(GIT_ENOTAREPO, "HEAD file is missing");
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
@ -148,12 +145,12 @@ static int guess_repository_dirs(git_repository *repo, const char *repository_pa
|
||||
|
||||
/* Git directory name */
|
||||
if (git__basename_r(buffer, sizeof(buffer), repository_path) < 0)
|
||||
return GIT_EINVALIDPATH;
|
||||
return git__throw(GIT_EINVALIDPATH, "Unable to parse folder name from `%s`", repository_path);
|
||||
|
||||
if (strcmp(buffer, DOT_GIT) == 0) {
|
||||
/* Path to working dir */
|
||||
if (git__dirname_r(buffer, sizeof(buffer), repository_path) < 0)
|
||||
return GIT_EINVALIDPATH;
|
||||
return git__throw(GIT_EINVALIDPATH, "Unable to parse parent folder name from `%s`", repository_path);
|
||||
path_work_tree = buffer;
|
||||
}
|
||||
|
||||
@ -162,13 +159,19 @@ static int guess_repository_dirs(git_repository *repo, const char *repository_pa
|
||||
|
||||
static git_repository *repository_alloc()
|
||||
{
|
||||
int error;
|
||||
|
||||
git_repository *repo = git__malloc(sizeof(git_repository));
|
||||
if (!repo)
|
||||
return NULL;
|
||||
|
||||
memset(repo, 0x0, sizeof(git_repository));
|
||||
|
||||
git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
|
||||
error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
|
||||
if (error < GIT_SUCCESS) {
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
|
||||
free(repo);
|
||||
@ -180,7 +183,7 @@ static git_repository *repository_alloc()
|
||||
|
||||
static int init_odb(git_repository *repo)
|
||||
{
|
||||
return git_odb_open(&repo->db, repo->path_odb);
|
||||
return git_odb_open(&repo->db, repo->path_odb); /* TODO: Move odb.c to new error handling */
|
||||
}
|
||||
|
||||
int git_repository_open3(git_repository **repo_out,
|
||||
@ -195,7 +198,7 @@ int git_repository_open3(git_repository **repo_out,
|
||||
assert(repo_out);
|
||||
|
||||
if (object_database == NULL)
|
||||
return GIT_ERROR;
|
||||
return git__throw(GIT_EINVALIDARGS, "Failed to open repository. `object_database` can't be null");
|
||||
|
||||
repo = repository_alloc();
|
||||
if (repo == NULL)
|
||||
@ -221,7 +224,7 @@ int git_repository_open3(git_repository **repo_out,
|
||||
|
||||
cleanup:
|
||||
git_repository_free(repo);
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to open repository");
|
||||
}
|
||||
|
||||
|
||||
@ -262,7 +265,7 @@ int git_repository_open2(git_repository **repo_out,
|
||||
|
||||
cleanup:
|
||||
git_repository_free(repo);
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to open repository");
|
||||
}
|
||||
|
||||
int git_repository_open(git_repository **repo_out, const char *path)
|
||||
@ -293,7 +296,7 @@ int git_repository_open(git_repository **repo_out, const char *path)
|
||||
|
||||
cleanup:
|
||||
git_repository_free(repo);
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to open repository");
|
||||
}
|
||||
|
||||
void git_repository_free(git_repository *repo)
|
||||
@ -312,8 +315,10 @@ void git_repository_free(git_repository *repo)
|
||||
if (repo->db != NULL)
|
||||
git_odb_close(repo->db);
|
||||
|
||||
if (repo->index != NULL)
|
||||
if (repo->index != NULL) {
|
||||
repo->index->repository = NULL;
|
||||
git_index_free(repo->index);
|
||||
}
|
||||
|
||||
free(repo);
|
||||
}
|
||||
@ -325,7 +330,7 @@ int git_repository_index(git_index **index_out, git_repository *repo)
|
||||
assert(index_out && repo);
|
||||
|
||||
if (repo->index == NULL) {
|
||||
error = git_index_open_inrepo(&repo->index, repo);
|
||||
error = git_index_open_inrepo(&repo->index, repo); /* TODO: move index.c to new error handling */
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -352,7 +357,7 @@ static int repo_init_reinit(repo_init *results)
|
||||
static int repo_init_createhead(git_repository *repo)
|
||||
{
|
||||
git_reference *head_reference;
|
||||
return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE);
|
||||
return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE); /* TODO: finalize moving refs.c to new error handling */
|
||||
}
|
||||
|
||||
static int repo_init_check_head_existence(char * repository_path)
|
||||
@ -366,6 +371,7 @@ static int repo_init_check_head_existence(char * repository_path)
|
||||
static int repo_init_structure(repo_init *results)
|
||||
{
|
||||
const int mode = 0755; /* or 0777 ? */
|
||||
int error;
|
||||
|
||||
char temp_path[GIT_PATH_MAX];
|
||||
char *git_dir = results->path_repository;
|
||||
@ -375,23 +381,27 @@ static int repo_init_structure(repo_init *results)
|
||||
|
||||
/* Creates the '/objects/info/' directory */
|
||||
git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
|
||||
if (gitfo_mkdir_recurs(temp_path, mode) < GIT_SUCCESS)
|
||||
return GIT_ERROR;
|
||||
error = gitfo_mkdir_recurs(temp_path, mode);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Creates the '/objects/pack/' directory */
|
||||
git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
|
||||
if (gitfo_mkdir(temp_path, mode))
|
||||
return GIT_ERROR;
|
||||
error = gitfo_mkdir(temp_path, mode);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__throw(error, "Unable to create `%s` folder", temp_path);
|
||||
|
||||
/* Creates the '/refs/heads/' directory */
|
||||
git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);
|
||||
if (gitfo_mkdir_recurs(temp_path, mode))
|
||||
return GIT_ERROR;
|
||||
error = gitfo_mkdir_recurs(temp_path, mode);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Creates the '/refs/tags/' directory */
|
||||
git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);
|
||||
if (gitfo_mkdir(temp_path, mode))
|
||||
return GIT_ERROR;
|
||||
error = gitfo_mkdir(temp_path, mode);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__throw(error, "Unable to create `%s` folder", temp_path);
|
||||
|
||||
/* TODO: what's left? templates? */
|
||||
|
||||
@ -470,7 +480,7 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is
|
||||
cleanup:
|
||||
free(results.path_repository);
|
||||
git_repository_free(repo);
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
|
||||
}
|
||||
|
||||
int git_repository_is_empty(git_repository *repo)
|
||||
@ -480,10 +490,10 @@ int git_repository_is_empty(git_repository *repo)
|
||||
|
||||
error = git_reference_lookup(&head, repo, "HEAD");
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
return git__throw(error, "Failed to determine the emptiness of the repository. An error occured while retrieving the HEAD reference");
|
||||
|
||||
if (git_reference_type(head) != GIT_REF_SYMBOLIC)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to determine the emptiness of the repository. HEAD is probably in detached state");
|
||||
|
||||
return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1;
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
||||
git_oid oid;
|
||||
|
||||
if (git_oid_mkstr(&oid, (char *)buffer + STRLEN("parent ")) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Parent object is corrupted");
|
||||
|
||||
commit->parents[i] = commit_lookup(walk, &oid);
|
||||
if (commit->parents[i] == NULL)
|
||||
@ -222,14 +222,14 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
||||
commit->out_degree = (unsigned short)parents;
|
||||
|
||||
if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Object is corrupted");
|
||||
|
||||
buffer = memchr(buffer, '>', buffer_end - buffer);
|
||||
if (buffer == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't find author");
|
||||
|
||||
if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't parse commit time");
|
||||
|
||||
commit->time = (time_t)commit_time;
|
||||
commit->parsed = 1;
|
||||
@ -245,11 +245,11 @@ static int commit_parse(git_revwalk *walk, commit_object *commit)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to parse commit. Can't read object");
|
||||
|
||||
if (obj->raw.type != GIT_OBJ_COMMIT) {
|
||||
git_odb_object_close(obj);
|
||||
return GIT_EOBJTYPE;
|
||||
return git__throw(GIT_EOBJTYPE, "Failed to parse commit. Object is no commit object");
|
||||
}
|
||||
|
||||
error = commit_quick_parse(walk, commit, &obj->raw);
|
||||
@ -305,7 +305,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
|
||||
|
||||
commit = commit_lookup(walk, oid);
|
||||
if (commit == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to push commit. Object not found");
|
||||
|
||||
commit->uninteresting = uninteresting;
|
||||
|
||||
@ -483,7 +483,7 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
|
||||
void git_revwalk_free(git_revwalk *walk)
|
||||
{
|
||||
unsigned int i;
|
||||
const void *_unused;
|
||||
const void *GIT_UNUSED(_unused);
|
||||
commit_object *commit;
|
||||
|
||||
if (walk == NULL)
|
||||
@ -558,7 +558,7 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk)
|
||||
|
||||
void git_revwalk_reset(git_revwalk *walk)
|
||||
{
|
||||
const void *_unused;
|
||||
const void *GIT_UNUSED(_unused);
|
||||
commit_object *commit;
|
||||
|
||||
assert(walk);
|
||||
|
@ -115,22 +115,22 @@ static int parse_timezone_offset(const char *buffer, long *offset_out)
|
||||
}
|
||||
|
||||
if (offset_start[0] != '-' && offset_start[0] != '+')
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It doesn't start with '+' or '-'");
|
||||
|
||||
if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It isn't a number");
|
||||
|
||||
if (offset_end - offset_start != 5)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Invalid length");
|
||||
|
||||
hours = dec_offset / 100;
|
||||
mins = dec_offset % 100;
|
||||
|
||||
if (hours > 14) // see http://www.worldtimezone.com/faq.html
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Hour value too large");;
|
||||
|
||||
if (mins > 59)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Minute value too large");
|
||||
|
||||
offset = (hours * 60) + mins;
|
||||
|
||||
@ -157,19 +157,19 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
||||
|
||||
line_end = memchr(buffer, '\n', buffer_end - buffer);
|
||||
if (!line_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. No newline found");;
|
||||
|
||||
if (buffer + (header_len + 1) > line_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short");
|
||||
|
||||
if (memcmp(buffer, header, header_len) != 0)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header);
|
||||
|
||||
buffer += header_len;
|
||||
|
||||
/* Parse name */
|
||||
if ((name_end = memchr(buffer, '<', buffer_end - buffer)) == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail start");
|
||||
|
||||
name_length = name_end - buffer - 1;
|
||||
sig->name = git__malloc(name_length + 1);
|
||||
@ -181,11 +181,11 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
||||
buffer = name_end + 1;
|
||||
|
||||
if (buffer >= line_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly");
|
||||
|
||||
/* Parse email */
|
||||
if ((email_end = memchr(buffer, '>', buffer_end - buffer)) == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail end");
|
||||
|
||||
email_length = email_end - buffer;
|
||||
sig->email = git__malloc(email_length + 1);
|
||||
@ -197,10 +197,10 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
||||
buffer = email_end + 1;
|
||||
|
||||
if (buffer >= line_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly");
|
||||
|
||||
if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Timestamp isn't a number");
|
||||
|
||||
sig->when.time = (time_t)time;
|
||||
|
||||
|
19
src/tag.c
19
src/tag.c
@ -90,13 +90,13 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
|
||||
int error;
|
||||
|
||||
if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0)
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to parse tag. Object field invalid");
|
||||
|
||||
if (buffer + 5 >= buffer_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
|
||||
|
||||
if (memcmp(buffer, "type ", 5) != 0)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Type field not found");
|
||||
buffer += 5;
|
||||
|
||||
tag->type = GIT_OBJ_BAD;
|
||||
@ -105,7 +105,7 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
|
||||
size_t type_length = strlen(tag_types[i]);
|
||||
|
||||
if (buffer + type_length >= buffer_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
|
||||
|
||||
if (memcmp(buffer, tag_types[i], type_length) == 0) {
|
||||
tag->type = i;
|
||||
@ -115,18 +115,19 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
|
||||
}
|
||||
|
||||
if (tag->type == GIT_OBJ_BAD)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Invalid object type");
|
||||
|
||||
if (buffer + 4 >= buffer_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
|
||||
|
||||
if (memcmp(buffer, "tag ", 4) != 0)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Tag field not found");
|
||||
|
||||
buffer += 4;
|
||||
|
||||
search = memchr(buffer, '\n', buffer_end - buffer);
|
||||
if (search == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
|
||||
|
||||
text_len = search - buffer;
|
||||
|
||||
@ -218,7 +219,7 @@ static int tag_create(
|
||||
}
|
||||
|
||||
if (!git_odb_exists(repo->db, target))
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to create tag. Object to tag doesn't exist");
|
||||
|
||||
/* Try to find out what the type is */
|
||||
if (target_type == GIT_OBJ_ANY) {
|
||||
|
17
src/tree.c
17
src/tree.c
@ -151,15 +151,15 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf
|
||||
return GIT_ENOMEM;
|
||||
|
||||
if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Can't parse attributes");
|
||||
|
||||
if (*buffer++ != ' ') {
|
||||
error = GIT_EOBJCORRUPTED;
|
||||
error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted");
|
||||
break;
|
||||
}
|
||||
|
||||
if (memchr(buffer, 0, buffer_end - buffer) == NULL) {
|
||||
error = GIT_EOBJCORRUPTED;
|
||||
error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -274,7 +274,7 @@ int git_tree_create_fromindex(git_oid *oid, git_index *index)
|
||||
int error;
|
||||
|
||||
if (index->repository == NULL)
|
||||
return GIT_EBAREINDEX;
|
||||
return git__throw(GIT_EBAREINDEX, "Failed to create tree. The index file is not backed up by an existing repository");
|
||||
|
||||
error = write_index(oid, index, "", 0, 0, git_index_entrycount(index));
|
||||
return (error < GIT_SUCCESS) ? error : GIT_SUCCESS;
|
||||
@ -343,7 +343,7 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con
|
||||
assert(bld && id && filename);
|
||||
|
||||
if (!valid_attributes(attributes))
|
||||
return GIT_ERROR;
|
||||
return git__throw(GIT_ERROR, "Failed to insert entry. Invalid atrributes");
|
||||
|
||||
if ((pos = git_vector_bsearch2(&bld->entries, entry_search_cmp, filename)) != GIT_ENOTFOUND) {
|
||||
entry = git_vector_get(&bld->entries, pos);
|
||||
@ -400,7 +400,7 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
|
||||
git_tree_entry *remove_ptr = (git_tree_entry *)git_treebuilder_get(bld, filename);
|
||||
|
||||
if (remove_ptr == NULL || remove_ptr->removed)
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to remove entry. File isn't in the tree");
|
||||
|
||||
remove_ptr->removed = 1;
|
||||
bld->entry_count--;
|
||||
@ -424,13 +424,14 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
|
||||
if (entry->removed)
|
||||
continue;
|
||||
|
||||
size += (entry->attr > 0x7FF) ? 7 : 6;
|
||||
snprintf(filemode, sizeof(filemode), "%o ", entry->attr);
|
||||
size += strlen(filemode);
|
||||
size += entry->filename_len + 1;
|
||||
size += GIT_OID_RAWSZ;
|
||||
}
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, git_repository_database(repo), size, GIT_OBJ_TREE)) < GIT_SUCCESS)
|
||||
return error;
|
||||
return git__rethrow(error, "Failed to write tree. Can't open write stream");
|
||||
|
||||
for (i = 0; i < bld->entries.length; ++i) {
|
||||
git_tree_entry *entry = bld->entries.contents[i];
|
||||
|
14
src/util.c
14
src/util.c
@ -104,6 +104,20 @@ int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...)
|
||||
return r;
|
||||
}
|
||||
|
||||
void git__strntolower(char *str, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
str[i] = tolower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void git__strtolower(char *str)
|
||||
{
|
||||
git__strntolower(str, strlen(str));
|
||||
}
|
||||
|
||||
int git__prefixcmp(const char *str, const char *prefix)
|
||||
{
|
||||
for (;;) {
|
||||
|
65
src/util.h
65
src/util.h
@ -6,16 +6,60 @@
|
||||
#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))
|
||||
|
||||
/*
|
||||
* Don't wrap malloc/calloc.
|
||||
* Use the default versions in glibc, and make
|
||||
* sure that any methods that allocate memory
|
||||
* return a GIT_ENOMEM error when allocation
|
||||
* fails.
|
||||
* Custom memory allocation wrappers
|
||||
* that set error code and error message
|
||||
* on allocation failure
|
||||
*/
|
||||
#define git__malloc malloc
|
||||
#define git__calloc calloc
|
||||
#define git__realloc realloc
|
||||
#define git__strdup strdup
|
||||
GIT_INLINE(void *) git__malloc(size_t len)
|
||||
{
|
||||
void *ptr = malloc(len);
|
||||
if (!ptr)
|
||||
git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GIT_INLINE(void *) git__calloc(size_t nelem, size_t elsize)
|
||||
{
|
||||
void *ptr = calloc(nelem, elsize);
|
||||
if (!ptr)
|
||||
git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)elsize);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GIT_INLINE(char *) git__strdup(const char *str)
|
||||
{
|
||||
char *ptr = strdup(str);
|
||||
if (!ptr)
|
||||
git__throw(GIT_ENOMEM, "Out of memory. Failed to duplicate string");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GIT_INLINE(char *) git__strndup(const char *str, size_t n)
|
||||
{
|
||||
size_t length;
|
||||
char *ptr;
|
||||
|
||||
length = strlen(str);
|
||||
if (n < length)
|
||||
length = n;
|
||||
|
||||
ptr = malloc(length + 1);
|
||||
if (!ptr)
|
||||
git__throw(GIT_ENOMEM, "Out of memory. Failed to duplicate string");
|
||||
|
||||
memcpy(ptr, str, length);
|
||||
ptr[length] = 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GIT_INLINE(void *) git__realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *new_ptr = realloc(ptr, size);
|
||||
if (!new_ptr)
|
||||
git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)size);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
extern int git__fmt(char *, size_t, const char *, ...)
|
||||
GIT_FORMAT_PRINTF(3, 4);
|
||||
@ -98,6 +142,9 @@ GIT_INLINE(int) git__is_sizet(git_off_t p)
|
||||
extern char *git__strtok(char *output, char *src, char *delimit);
|
||||
extern char *git__strtok_keep(char *output, char *src, char *delimit);
|
||||
|
||||
extern void git__strntolower(char *str, int len);
|
||||
extern void git__strtolower(char *str);
|
||||
|
||||
#define STRLEN(str) (sizeof(str) - 1)
|
||||
|
||||
#define GIT_OID_LINE_LENGTH(header) (STRLEN(header) + 1 + GIT_OID_HEXSZ + 1)
|
||||
|
11
src/vector.c
11
src/vector.c
@ -106,7 +106,7 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke
|
||||
|
||||
/* need comparison function to sort the vector */
|
||||
if (v->_cmp == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Can't sort vector. No comparison function set");
|
||||
|
||||
git_vector_sort(v);
|
||||
|
||||
@ -114,7 +114,7 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke
|
||||
if (find != NULL)
|
||||
return (int)(find - v->contents);
|
||||
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Can't find element");
|
||||
}
|
||||
|
||||
int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key)
|
||||
@ -128,7 +128,7 @@ int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key
|
||||
return i;
|
||||
}
|
||||
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Can't find element");
|
||||
}
|
||||
|
||||
static int strict_comparison(const void *a, const void *b)
|
||||
@ -143,9 +143,6 @@ int git_vector_search(git_vector *v, const void *entry)
|
||||
|
||||
int git_vector_bsearch(git_vector *v, const void *key)
|
||||
{
|
||||
if (v->_cmp == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return git_vector_bsearch2(v, v->_cmp, key);
|
||||
}
|
||||
|
||||
@ -156,7 +153,7 @@ int git_vector_remove(git_vector *v, unsigned int idx)
|
||||
assert(v);
|
||||
|
||||
if (idx >= v->length || v->length == 0)
|
||||
return GIT_ENOTFOUND;
|
||||
return git__throw(GIT_ENOTFOUND, "Can't remove element. Index out of bounds");
|
||||
|
||||
for (i = idx; i < v->length - 1; ++i)
|
||||
v->contents[i] = v->contents[i + 1];
|
||||
|
@ -48,16 +48,15 @@ int pthread_join(pthread_t thread, void **value_ptr)
|
||||
int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex,
|
||||
const pthread_mutexattr_t *GIT_RESTRICT GIT_UNUSED(mutexattr))
|
||||
{
|
||||
GIT_UNUSED_ARG(mutexattr);
|
||||
GIT_UNUSED_ARG(mutexattr);
|
||||
InitializeCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
int ret;
|
||||
ret = CloseHandle(mutex);
|
||||
return -(!ret);
|
||||
DeleteCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
|
22
tests/NAMING
22
tests/NAMING
@ -23,14 +23,24 @@ Categories
|
||||
|
||||
04__: Parsing and loading commit data
|
||||
|
||||
05__: To be described
|
||||
05__: Revision walking
|
||||
|
||||
06__: To be described
|
||||
06__: Index reading, writing and searching
|
||||
|
||||
07__: To be described
|
||||
07__: Tests for the internal hashtable code
|
||||
|
||||
08__: To be described
|
||||
08__: Tag reading and writing
|
||||
|
||||
09__: To be described
|
||||
09__: Reading tree objects
|
||||
|
||||
10__: Symbolic, loose and packed references reading and writing.
|
||||
10__: Symbolic, loose and packed references reading and writing.
|
||||
|
||||
11__: SQLite backend
|
||||
|
||||
12__: Repository init and opening
|
||||
|
||||
13__: Threads, empty as of now
|
||||
|
||||
14__: Redis backend
|
||||
|
||||
15__: Configuration parsing
|
||||
|
BIN
tests/resources/config/config0
Normal file
BIN
tests/resources/config/config0
Normal file
Binary file not shown.
BIN
tests/resources/config/config1
Normal file
BIN
tests/resources/config/config1
Normal file
Binary file not shown.
BIN
tests/resources/config/config2
Normal file
BIN
tests/resources/config/config2
Normal file
Binary file not shown.
BIN
tests/resources/config/config3
Normal file
BIN
tests/resources/config/config3
Normal file
Binary file not shown.
BIN
tests/resources/config/config4
Normal file
BIN
tests/resources/config/config4
Normal file
Binary file not shown.
BIN
tests/resources/config/config5
Normal file
BIN
tests/resources/config/config5
Normal file
Binary file not shown.
@ -368,7 +368,7 @@ BEGIN_TEST(details0, "query the details on a parsed commit")
|
||||
const char *message, *message_short;
|
||||
git_time_t commit_time;
|
||||
unsigned int parents, p;
|
||||
git_commit *parent;
|
||||
git_commit *parent = NULL, *old_parent = NULL;
|
||||
|
||||
git_oid_mkstr(&id, commit_ids[i]);
|
||||
|
||||
@ -390,11 +390,19 @@ BEGIN_TEST(details0, "query the details on a parsed commit")
|
||||
must_be_true(commit_time > 0);
|
||||
must_be_true(parents <= 2);
|
||||
for (p = 0;p < parents;p++) {
|
||||
if (old_parent != NULL)
|
||||
git_commit_close(old_parent);
|
||||
|
||||
old_parent = parent;
|
||||
must_pass(git_commit_parent(&parent, commit, p));
|
||||
must_be_true(parent != NULL);
|
||||
must_be_true(git_commit_author(parent) != NULL); // is it really a commit?
|
||||
}
|
||||
git_commit_close(old_parent);
|
||||
git_commit_close(parent);
|
||||
|
||||
must_fail(git_commit_parent(&parent, commit, parents));
|
||||
git_commit_close(commit);
|
||||
}
|
||||
|
||||
git_repository_free(repo);
|
||||
@ -462,9 +470,76 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk")
|
||||
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
|
||||
|
||||
git_commit_close(commit);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
#define ROOT_COMMIT_MESSAGE "This is a root commit\n\
|
||||
This is a root commit and should be the only one in this branch\n"
|
||||
|
||||
BEGIN_TEST(root0, "create a root commit")
|
||||
git_repository *repo;
|
||||
git_commit *commit;
|
||||
git_oid tree_id, commit_id;
|
||||
const git_oid *branch_oid;
|
||||
const git_signature *author, *committer;
|
||||
const char *branch_name = "refs/heads/root-commit-branch";
|
||||
git_reference *head, *branch;
|
||||
char *head_old;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git_oid_mkstr(&tree_id, tree_oid);
|
||||
|
||||
/* create signatures */
|
||||
committer = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 123456789, 60);
|
||||
must_be_true(committer != NULL);
|
||||
|
||||
author = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 987654321, 90);
|
||||
must_be_true(author != NULL);
|
||||
|
||||
/* First we need to update HEAD so it points to our non-existant branch */
|
||||
must_pass(git_reference_lookup(&head, repo, "HEAD"));
|
||||
must_be_true(git_reference_type(head) == GIT_REF_SYMBOLIC);
|
||||
head_old = git__strdup(git_reference_target(head));
|
||||
must_be_true(head_old != NULL);
|
||||
|
||||
must_pass(git_reference_set_target(head, branch_name));
|
||||
|
||||
must_pass(git_commit_create_v(
|
||||
&commit_id, /* out id */
|
||||
repo,
|
||||
"HEAD",
|
||||
author,
|
||||
committer,
|
||||
ROOT_COMMIT_MESSAGE,
|
||||
&tree_id,
|
||||
0));
|
||||
|
||||
git_signature_free((git_signature *)committer);
|
||||
git_signature_free((git_signature *)author);
|
||||
|
||||
/*
|
||||
* The fact that creating a commit works has already been
|
||||
* tested. Here we just make sure it's our commit and that it was
|
||||
* written as a root commit.
|
||||
*/
|
||||
must_pass(git_commit_lookup(&commit, repo, &commit_id));
|
||||
must_be_true(git_commit_parentcount(commit) == 0);
|
||||
must_pass(git_reference_lookup(&branch, repo, branch_name));
|
||||
branch_oid = git_reference_oid(branch);
|
||||
must_pass(git_oid_cmp(branch_oid, &commit_id));
|
||||
must_be_true(!strcmp(git_commit_message(commit), ROOT_COMMIT_MESSAGE));
|
||||
|
||||
/* Remove the data we just added to the repo */
|
||||
must_pass(git_reference_lookup(&head, repo, "HEAD"));
|
||||
must_pass(git_reference_set_target(head, head_old));
|
||||
must_pass(git_reference_delete(branch));
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
|
||||
free(head_old);
|
||||
git_commit_close(commit);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_SUITE(commit)
|
||||
ADD_TEST(parse0);
|
||||
@ -474,4 +549,6 @@ BEGIN_SUITE(commit)
|
||||
|
||||
ADD_TEST(write0);
|
||||
//ADD_TEST(write1);
|
||||
|
||||
ADD_TEST(root0);
|
||||
END_SUITE
|
||||
|
@ -155,7 +155,7 @@ BEGIN_TEST(tableit0, "iterate through all the contents of the table")
|
||||
const int objects_n = 32;
|
||||
int i;
|
||||
table_item *objects, *ob;
|
||||
const void *_unused;
|
||||
const void *GIT_UNUSED(_unused);
|
||||
|
||||
git_hashtable *table = NULL;
|
||||
|
||||
|
@ -32,6 +32,7 @@ static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
|
||||
static const char *blob_oid = "fa49b077972391ad58037050f2a75f74e3671e92";
|
||||
static const char *first_tree = "181037049a54a1eb5fab404658a3a250b44335d7";
|
||||
static const char *second_tree = "f60079018b664e4e79329a7ef9559c8d9e0378d1";
|
||||
static const char *third_tree = "eb86d8b81d6adbd5290a935d6c9976882de98488";
|
||||
|
||||
#if 0
|
||||
static int print_tree(git_repository *repo, const git_oid *tree_oid, int depth)
|
||||
@ -82,6 +83,7 @@ BEGIN_TEST(read0, "acces randomly the entries on a loaded tree")
|
||||
must_be_true(git_tree_entry_byindex(tree, 3) == NULL);
|
||||
must_be_true(git_tree_entry_byindex(tree, -1) == NULL);
|
||||
|
||||
git_tree_close(tree);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
@ -102,7 +104,9 @@ BEGIN_TEST(read1, "read a tree from the repository")
|
||||
|
||||
/* GH-86: git_object_lookup() should also check the type if the object comes from the cache */
|
||||
must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_TREE) == 0);
|
||||
git_object_close(obj);
|
||||
must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_BLOB) == GIT_EINVALIDTYPE);
|
||||
git_object_close(obj);
|
||||
|
||||
entry = git_tree_entry_byname(tree, "README");
|
||||
must_be_true(entry != NULL);
|
||||
@ -111,6 +115,8 @@ BEGIN_TEST(read1, "read a tree from the repository")
|
||||
|
||||
must_pass(git_tree_entry_2object(&obj, repo, entry));
|
||||
|
||||
git_object_close(obj);
|
||||
git_tree_close(tree);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
@ -148,9 +154,50 @@ BEGIN_TEST(write2, "write a tree from a memory")
|
||||
must_pass(git_treebuilder_write(&rid,repo,builder));
|
||||
|
||||
must_be_true(git_oid_cmp(&rid, &id2) == 0);
|
||||
|
||||
git_treebuilder_free(builder);
|
||||
git_tree_close(tree);
|
||||
close_temp_repo(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write3, "write a hierarchical tree from a memory")
|
||||
git_repository *repo;
|
||||
git_treebuilder *builder;
|
||||
git_tree *tree;
|
||||
git_oid id, bid, subtree_id, id2, id3;
|
||||
git_oid id_hiearar;
|
||||
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
git_oid_mkstr(&id, first_tree);
|
||||
git_oid_mkstr(&id2, second_tree);
|
||||
git_oid_mkstr(&id3, third_tree);
|
||||
git_oid_mkstr(&bid, blob_oid);
|
||||
|
||||
//create subtree
|
||||
must_pass(git_treebuilder_create(&builder, NULL));
|
||||
must_pass(git_treebuilder_insert(NULL,builder,"new.txt",&bid,0100644));
|
||||
must_pass(git_treebuilder_write(&subtree_id,repo,builder));
|
||||
git_treebuilder_free(builder);
|
||||
|
||||
// create parent tree
|
||||
must_pass(git_tree_lookup(&tree, repo, &id));
|
||||
must_pass(git_treebuilder_create(&builder, tree));
|
||||
must_pass(git_treebuilder_insert(NULL,builder,"new",&subtree_id,040000));
|
||||
must_pass(git_treebuilder_write(&id_hiearar,repo,builder));
|
||||
git_treebuilder_free(builder);
|
||||
git_tree_close(tree);
|
||||
|
||||
must_be_true(git_oid_cmp(&id_hiearar, &id3) == 0);
|
||||
|
||||
// check data is correct
|
||||
must_pass(git_tree_lookup(&tree, repo, &id_hiearar));
|
||||
must_be_true(2 == git_tree_entrycount(tree));
|
||||
git_tree_close(tree);
|
||||
|
||||
close_temp_repo(repo);
|
||||
|
||||
END_TEST
|
||||
|
||||
BEGIN_SUITE(tree)
|
||||
//ADD_TEST(print0);
|
||||
ADD_TEST(read0);
|
||||
@ -158,5 +205,6 @@ BEGIN_SUITE(tree)
|
||||
//ADD_TEST(write0);
|
||||
//ADD_TEST(write1);
|
||||
ADD_TEST(write2);
|
||||
ADD_TEST(write3);
|
||||
END_SUITE
|
||||
|
||||
|
@ -51,6 +51,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference")
|
||||
git__joinpath(ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object));
|
||||
must_be_true(strcmp(ref_name_from_tag_name, loose_tag_ref_name) == 0);
|
||||
|
||||
git_object_close(object);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
@ -91,6 +92,7 @@ BEGIN_TEST(readsym0, "lookup a symbolic reference")
|
||||
git_oid_mkstr(&id, current_master_tip);
|
||||
must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0);
|
||||
|
||||
git_object_close(object);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
@ -117,6 +119,7 @@ BEGIN_TEST(readsym1, "lookup a nested symbolic reference")
|
||||
git_oid_mkstr(&id, current_master_tip);
|
||||
must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0);
|
||||
|
||||
git_object_close(object);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
@ -175,6 +178,7 @@ BEGIN_TEST(readpacked0, "lookup a packed reference")
|
||||
must_be_true(object != NULL);
|
||||
must_be_true(git_object_type(object) == GIT_OBJ_COMMIT);
|
||||
|
||||
git_object_close(object);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
@ -194,7 +198,7 @@ END_TEST
|
||||
|
||||
BEGIN_TEST(create0, "create a new symbolic reference")
|
||||
git_reference *new_reference, *looked_up_ref, *resolved_ref;
|
||||
git_repository *repo;
|
||||
git_repository *repo, *repo2;
|
||||
git_oid id;
|
||||
char ref_path[GIT_PATH_MAX];
|
||||
|
||||
@ -202,7 +206,7 @@ BEGIN_TEST(create0, "create a new symbolic reference")
|
||||
|
||||
git_oid_mkstr(&id, current_master_tip);
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
/* Retrieve the physical path to the symbolic ref for further cleaning */
|
||||
git__joinpath(ref_path, repo->path_repository, new_head_tracker);
|
||||
@ -226,14 +230,13 @@ BEGIN_TEST(create0, "create a new symbolic reference")
|
||||
git_repository_free(repo);
|
||||
|
||||
/* Similar test with a fresh new repository */
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(git_repository_open(&repo2, TEMP_REPO_FOLDER));
|
||||
|
||||
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker));
|
||||
must_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker));
|
||||
must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
|
||||
must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
|
||||
|
||||
git_reference_delete(looked_up_ref);
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo2);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(create1, "create a deep symbolic reference")
|
||||
@ -246,7 +249,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
|
||||
|
||||
git_oid_mkstr(&id, current_master_tip);
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git__joinpath(ref_path, repo->path_repository, new_head_tracker);
|
||||
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target));
|
||||
@ -254,13 +257,12 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
|
||||
must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
|
||||
must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
|
||||
|
||||
git_reference_delete(looked_up_ref);
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(create2, "create a new OID reference")
|
||||
git_reference *new_reference, *looked_up_ref;
|
||||
git_repository *repo;
|
||||
git_repository *repo, *repo2;
|
||||
git_oid id;
|
||||
char ref_path[GIT_PATH_MAX];
|
||||
|
||||
@ -268,7 +270,7 @@ BEGIN_TEST(create2, "create a new OID reference")
|
||||
|
||||
git_oid_mkstr(&id, current_master_tip);
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
/* Retrieve the physical path to the symbolic ref for further cleaning */
|
||||
git__joinpath(ref_path, repo->path_repository, new_head);
|
||||
@ -288,13 +290,12 @@ BEGIN_TEST(create2, "create a new OID reference")
|
||||
git_repository_free(repo);
|
||||
|
||||
/* Similar test with a fresh new repository */
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(git_repository_open(&repo2, TEMP_REPO_FOLDER));
|
||||
|
||||
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head));
|
||||
must_pass(git_reference_lookup(&looked_up_ref, repo2, new_head));
|
||||
must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0);
|
||||
|
||||
git_reference_delete(looked_up_ref);
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo2);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id")
|
||||
@ -325,7 +326,7 @@ BEGIN_TEST(overwrite0, "Overwrite an existing symbolic reference")
|
||||
git_reference *ref, *branch_ref;
|
||||
git_repository *repo;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
/* The target needds to exist and we need to check the name has changed */
|
||||
must_pass(git_reference_create_symbolic(&branch_ref, repo, ref_branch_name, ref_master_name));
|
||||
@ -344,9 +345,7 @@ BEGIN_TEST(overwrite0, "Overwrite an existing symbolic reference")
|
||||
must_be_true(git_reference_type(ref) & GIT_REF_SYMBOLIC);
|
||||
must_be_true(!strcmp(git_reference_target(ref), ref_master_name));
|
||||
|
||||
must_pass(git_reference_delete(ref));
|
||||
must_pass(git_reference_delete(branch_ref));
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(overwrite1, "Overwrite an existing object id reference")
|
||||
@ -354,7 +353,7 @@ BEGIN_TEST(overwrite1, "Overwrite an existing object id reference")
|
||||
git_repository *repo;
|
||||
git_oid id;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
must_pass(git_reference_lookup(&ref, repo, ref_master_name));
|
||||
must_be_true(ref->type & GIT_REF_OID);
|
||||
@ -375,8 +374,7 @@ BEGIN_TEST(overwrite1, "Overwrite an existing object id reference")
|
||||
must_pass(git_reference_lookup(&ref, repo, ref_name));
|
||||
must_be_true(!git_oid_cmp(&id, git_reference_oid(ref)));
|
||||
|
||||
git_reference_delete(ref);
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symbolic one")
|
||||
@ -384,7 +382,7 @@ BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symboli
|
||||
git_repository *repo;
|
||||
git_oid id;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
must_pass(git_reference_lookup(&ref, repo, ref_master_name));
|
||||
must_be_true(ref->type & GIT_REF_OID);
|
||||
@ -399,8 +397,7 @@ BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symboli
|
||||
must_be_true(git_reference_type(ref) & GIT_REF_SYMBOLIC);
|
||||
must_be_true(!strcmp(git_reference_target(ref), ref_master_name));
|
||||
|
||||
git_reference_delete(ref);
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object id one")
|
||||
@ -408,7 +405,7 @@ BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object
|
||||
git_repository *repo;
|
||||
git_oid id;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
must_pass(git_reference_lookup(&ref, repo, ref_master_name));
|
||||
must_be_true(ref->type & GIT_REF_OID);
|
||||
@ -425,8 +422,7 @@ BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object
|
||||
must_be_true(git_reference_type(ref) & GIT_REF_OID);
|
||||
must_be_true(!git_oid_cmp(git_reference_oid(ref), &id));
|
||||
|
||||
git_reference_delete(ref);
|
||||
git_repository_free(repo);
|
||||
close_temp_repo(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(pack0, "create a packfile for an empty folder")
|
||||
|
170
tests/t15-config.c
Normal file
170
tests/t15-config.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
#include "test_helpers.h"
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
#define CONFIG_BASE TEST_RESOURCES "/config"
|
||||
|
||||
/*
|
||||
* This one is so we know the code isn't completely broken
|
||||
*/
|
||||
BEGIN_TEST(config0, "read a simple configuration")
|
||||
git_config *cfg;
|
||||
int i;
|
||||
|
||||
must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config0"));
|
||||
must_pass(git_config_get_int(cfg, "core.repositoryformatversion", &i));
|
||||
must_be_true(i == 0);
|
||||
must_pass(git_config_get_bool(cfg, "core.filemode", &i));
|
||||
must_be_true(i == 1);
|
||||
must_pass(git_config_get_bool(cfg, "core.bare", &i));
|
||||
must_be_true(i == 0);
|
||||
must_pass(git_config_get_bool(cfg, "core.logallrefupdates", &i));
|
||||
must_be_true(i == 1);
|
||||
|
||||
git_config_free(cfg);
|
||||
END_TEST
|
||||
|
||||
/*
|
||||
* [this "that"] and [this "That] are different namespaces. Make sure
|
||||
* each returns the correct one.
|
||||
*/
|
||||
BEGIN_TEST(config1, "case sensitivity")
|
||||
git_config *cfg;
|
||||
int i;
|
||||
const char *str;
|
||||
|
||||
must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config1"));
|
||||
|
||||
must_pass(git_config_get_string(cfg, "this.that.other", &str));
|
||||
must_be_true(!strcmp(str, "true"));
|
||||
must_pass(git_config_get_string(cfg, "this.That.other", &str));
|
||||
must_be_true(!strcmp(str, "yes"));
|
||||
|
||||
must_pass(git_config_get_bool(cfg, "this.that.other", &i));
|
||||
must_be_true(i == 1);
|
||||
must_pass(git_config_get_bool(cfg, "this.That.other", &i));
|
||||
must_be_true(i == 1);
|
||||
|
||||
/* This one doesn't exist */
|
||||
must_fail(git_config_get_bool(cfg, "this.thaT.other", &i));
|
||||
|
||||
git_config_free(cfg);
|
||||
END_TEST
|
||||
|
||||
/*
|
||||
* If \ is the last non-space character on the line, we read the next
|
||||
* one, separating each line with SP.
|
||||
*/
|
||||
BEGIN_TEST(config2, "parse a multiline value")
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
|
||||
must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config2"));
|
||||
|
||||
must_pass(git_config_get_string(cfg, "this.That.and", &str));
|
||||
must_be_true(!strcmp(str, "one one one two two three three"));
|
||||
|
||||
git_config_free(cfg);
|
||||
END_TEST
|
||||
|
||||
/*
|
||||
* This kind of subsection declaration is case-insensitive
|
||||
*/
|
||||
BEGIN_TEST(config3, "parse a [section.subsection] header")
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
|
||||
must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config3"));
|
||||
|
||||
must_pass(git_config_get_string(cfg, "section.subsection.var", &str));
|
||||
must_be_true(!strcmp(str, "hello"));
|
||||
|
||||
/* Avoid a false positive */
|
||||
str = "nohello";
|
||||
must_pass(git_config_get_string(cfg, "section.subSectIon.var", &str));
|
||||
must_be_true(!strcmp(str, "hello"));
|
||||
|
||||
git_config_free(cfg);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(config4, "a variable name on its own is valid")
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
int i;
|
||||
|
||||
must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config4"));
|
||||
|
||||
must_pass(git_config_get_string(cfg, "some.section.variable", &str));
|
||||
must_be_true(str == NULL);
|
||||
|
||||
must_pass(git_config_get_bool(cfg, "some.section.variable", &i));
|
||||
must_be_true(i == 1);
|
||||
|
||||
|
||||
git_config_free(cfg);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(config5, "test number suffixes")
|
||||
git_config *cfg;
|
||||
long int i;
|
||||
|
||||
must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config5"));
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.simple", &i));
|
||||
must_be_true(i == 1);
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.k", &i));
|
||||
must_be_true(i == 1 * 1024);
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.kk", &i));
|
||||
must_be_true(i == 1 * 1024);
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.m", &i));
|
||||
must_be_true(i == 1 * 1024 * 1024);
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.mm", &i));
|
||||
must_be_true(i == 1 * 1024 * 1024);
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.g", &i));
|
||||
must_be_true(i == 1 * 1024 * 1024 * 1024);
|
||||
|
||||
must_pass(git_config_get_long(cfg, "number.gg", &i));
|
||||
must_be_true(i == 1 * 1024 * 1024 * 1024);
|
||||
|
||||
git_config_free(cfg);
|
||||
END_TEST
|
||||
|
||||
|
||||
BEGIN_SUITE(config)
|
||||
ADD_TEST(config0);
|
||||
ADD_TEST(config1);
|
||||
ADD_TEST(config2);
|
||||
ADD_TEST(config3);
|
||||
ADD_TEST(config4);
|
||||
ADD_TEST(config5);
|
||||
END_SUITE
|
@ -130,6 +130,7 @@ static void free_suite(git_testsuite *ts)
|
||||
if (ts->list[n])
|
||||
test_free(ts->list[n]);
|
||||
|
||||
free(ts->name);
|
||||
free(ts);
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ DECLARE_SUITE(sqlite);
|
||||
DECLARE_SUITE(hiredis);
|
||||
DECLARE_SUITE(repository);
|
||||
DECLARE_SUITE(threads);
|
||||
DECLARE_SUITE(config);
|
||||
|
||||
static libgit2_suite suite_methods[]= {
|
||||
SUITE_NAME(core),
|
||||
@ -60,7 +61,8 @@ static libgit2_suite suite_methods[]= {
|
||||
SUITE_NAME(sqlite),
|
||||
SUITE_NAME(repository),
|
||||
SUITE_NAME(threads),
|
||||
SUITE_NAME(hiredis)
|
||||
SUITE_NAME(hiredis),
|
||||
SUITE_NAME(config),
|
||||
};
|
||||
|
||||
#define GIT_SUITE_COUNT (ARRAY_SIZE(suite_methods))
|
||||
|
Loading…
Reference in New Issue
Block a user