mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-11 04:28:26 +00:00
Merge upstream/development
Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
This commit is contained in:
commit
f026f2b9ee
@ -22,8 +22,7 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1"
|
||||
SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}")
|
||||
|
||||
# Find required dependencies
|
||||
FIND_PACKAGE(ZLIB REQUIRED)
|
||||
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} src)
|
||||
INCLUDE_DIRECTORIES(deps/zlib src include)
|
||||
|
||||
# Try finding openssl
|
||||
FIND_PACKAGE(OpenSSL)
|
||||
@ -63,25 +62,32 @@ SET(INSTALL_INC include CACHE PATH "Where to install headers to.")
|
||||
# Build options
|
||||
OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
|
||||
OPTION (BUILD_TESTS "Build Tests" ON)
|
||||
OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF)
|
||||
|
||||
# Build Release by default
|
||||
IF (NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
ENDIF ()
|
||||
|
||||
IF (THREADSAFE)
|
||||
IF (NOT WIN32)
|
||||
find_package(Threads REQUIRED)
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DGIT_THREADS)
|
||||
ENDIF()
|
||||
|
||||
# Collect sourcefiles
|
||||
FILE(GLOB SRC src/*.c src/backends/*.c)
|
||||
FILE(GLOB SRC_ZLIB deps/zlib/*.c)
|
||||
FILE(GLOB SRC_SHA1 src/block-sha1/*.c)
|
||||
FILE(GLOB SRC_PLAT src/unix/*.c)
|
||||
FILE(GLOB SRC_H include/git2/*.h)
|
||||
|
||||
# On Windows use specific platform sources
|
||||
IF (WIN32 AND NOT CYGWIN)
|
||||
ADD_DEFINITIONS(-DWIN32 -D_DEBUG -D_LIB -DZLIB_WINAPI)
|
||||
ADD_DEFINITIONS(-DWIN32 -D_DEBUG -D_LIB)
|
||||
FILE(GLOB SRC_PLAT src/win32/*.c)
|
||||
IF (MINGW)
|
||||
SET(PTHREAD_LIBRARY pthread)
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
# Specify sha1 implementation
|
||||
@ -96,9 +102,8 @@ ELSEIF (SHA1_TYPE STREQUAL "openssl")
|
||||
ENDIF ()
|
||||
|
||||
# Compile and link libgit2
|
||||
INCLUDE_DIRECTORIES(src include)
|
||||
ADD_LIBRARY(git2 ${SRC} ${SRC_PLAT} ${SRC_SHA1})
|
||||
TARGET_LINK_LIBRARIES(git2 ${ZLIB_LIBRARY} ${LIB_SHA1} ${PTHREAD_LIBRARY} ${SQLITE3_LIBRARIES})
|
||||
ADD_LIBRARY(git2 ${SRC} ${SRC_PLAT} ${SRC_SHA1} ${SRC_ZLIB})
|
||||
TARGET_LINK_LIBRARIES(git2 ${LIB_SHA1} ${CMAKE_THREAD_LIBS_INIT} ${SQLITE3_LIBRARIES})
|
||||
SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
|
||||
SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR})
|
||||
|
||||
@ -121,8 +126,8 @@ IF (BUILD_TESTS)
|
||||
|
||||
FILE(GLOB SRC_TEST tests/t??-*.c)
|
||||
|
||||
ADD_EXECUTABLE(libgit2_test tests/test_main.c tests/test_lib.c tests/test_helpers.c ${SRC} ${SRC_PLAT} ${SRC_SHA1} ${SRC_TEST})
|
||||
TARGET_LINK_LIBRARIES(libgit2_test ${ZLIB_LIBRARY} ${LIB_SHA1} ${PTHREAD_LIBRARY} ${SQLITE3_LIBRARIES})
|
||||
ADD_EXECUTABLE(libgit2_test tests/test_main.c tests/test_lib.c tests/test_helpers.c ${SRC} ${SRC_PLAT} ${SRC_SHA1} ${SRC_TEST} ${SRC_ZLIB})
|
||||
TARGET_LINK_LIBRARIES(libgit2_test ${LIB_SHA1} ${CMAKE_THREAD_LIBS_INIT} ${SQLITE3_LIBRARIES})
|
||||
|
||||
ADD_TEST(libgit2_test libgit2_test)
|
||||
ENDIF ()
|
||||
|
47
README.md
47
README.md
@ -5,6 +5,11 @@ libgit2 is a portable, pure C implementation of the Git core methods provided as
|
||||
re-entrant linkable library with a solid API, allowing you to write native
|
||||
speed custom Git applications in any language with bindings.
|
||||
|
||||
libgit2 is licensed under a **very permissive license** (GPLv2 with a special Linking Exception).
|
||||
This basically means that you can link it (unmodified) with any kind of software without having to
|
||||
release its source code.
|
||||
|
||||
* Mailing list: <libgit2@librelist.org>
|
||||
* Website: <http://libgit2.github.com>
|
||||
* API documentation: <http://libgit2.github.com/libgit2/modules.html>
|
||||
* Usage guide: <http://libgit2.github.com/api.html>
|
||||
@ -14,30 +19,32 @@ What It Can Do
|
||||
|
||||
libgit2 is already very usable.
|
||||
|
||||
* raw <-> hex SHA conversions
|
||||
* raw object reading (loose and packed)
|
||||
* raw object writing (loose)
|
||||
* revlist walker
|
||||
* commit, tag and tree object parsing and write-back
|
||||
* SHA conversions, formatting and shortening
|
||||
* object reading (loose and packed)
|
||||
* object writing (loose)
|
||||
* commit, tag, tree and blob parsing and write-back
|
||||
* tree traversal
|
||||
* basic index file (staging area) operations
|
||||
* revision walking
|
||||
* index file (staging area) manipulation
|
||||
* custom ODB backends
|
||||
* reference management (including packed references)
|
||||
* ...and more
|
||||
|
||||
|
||||
Building libgit2 - External dependencies
|
||||
========================================
|
||||
|
||||
The following libraries are required to manually build the libgit2 library:
|
||||
libgit2 builds cleanly on most platforms without any external dependencies.
|
||||
Under Unix-like systems, like Linux, *BSD and Mac OS X, libgit2 expects `pthreads` to be available;
|
||||
they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
|
||||
for threading.
|
||||
|
||||
* zlib 1.2+ <http://www.zlib.net/>
|
||||
|
||||
When building in Windows using MSVC, make sure you compile ZLib using the MSVC solution that ships in its source distribution.
|
||||
Alternatively, you may download precompiled binaries from: <http://www.winimage.com/zLibDll/>
|
||||
Additionally, he following libraries may be used as replacement for built-in functionality:
|
||||
|
||||
* LibSSL **(optional)** <http://www.openssl.org/>
|
||||
|
||||
libgit2 can be built using the SHA1 implementation of LibSSL-Crypto, instead of the built-in custom implementations. Performance wise, they are quite similar.
|
||||
|
||||
* pthreads-w32 **(required on MinGW)** <http://sourceware.org/pthreads-win32/>
|
||||
|
||||
Building libgit2 - Using waf
|
||||
======================
|
||||
|
||||
@ -112,11 +119,17 @@ Language Bindings
|
||||
Here are the bindings to libgit2 that are currently available:
|
||||
|
||||
* Rugged (Ruby bindings) <https://github.com/libgit2/rugged>
|
||||
* objective-git (Objective-C bindings) <https://github.com/libgit2/objective-git>
|
||||
* pygit2 (Python bindings) <https://github.com/libgit2/pygit2>
|
||||
* libgit2sharp (.NET bindings) <https://github.com/nulltoken/libgit2sharp>
|
||||
* php-git (PHP bindings) <https://github.com/chobie/php-git>
|
||||
* luagit2 (Lua bindings) <https://github.com/Neopallium/luagit2>
|
||||
* GitForDelphi (Delphi bindings) <https://github.com/jasonpenny/GitForDelphi>
|
||||
* libgit2sharp (.NET bindings) <https://github.com/libgit2/libgit2sharp>
|
||||
* php-git (PHP bindings) <https://github.com/libgit2/php-git>
|
||||
* luagit2 (Lua bindings) <https://github.com/libgit2/luagit2>
|
||||
* GitForDelphi (Delphi bindings) <https://github.com/libgit2/GitForDelphi>
|
||||
* node-gitteh (Node.js bindings) <https://github.com/libgit2/node-gitteh>
|
||||
* nodegit (Node.js bindings) <https://github.com/tbranyen/nodegit>
|
||||
* go-git (Go bindings) <https://github.com/str1ngs/go-git>
|
||||
* libqgit2 (C++ QT bindings) <https://projects.kde.org/projects/playground/libs/libqgit2/>
|
||||
* libgit2-ocaml (ocaml bindings) <https://github.com/burdges/libgit2-ocaml>
|
||||
* Geef (Erlang bindings) <https://github.com/schacon/geef>
|
||||
|
||||
If you start another language binding to libgit2, please let us know so
|
||||
|
@ -1,6 +1,6 @@
|
||||
PROJECT_NAME = libgit2
|
||||
|
||||
INPUT = src/git2
|
||||
INPUT = include/git2
|
||||
QUIET = YES
|
||||
RECURSIVE = YES
|
||||
FILE_PATTERNS = *.h
|
||||
|
169
deps/zlib/adler32.c
vendored
Normal file
169
deps/zlib/adler32.c
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
/* adler32.c -- compute the Adler-32 checksum of a data stream
|
||||
* Copyright (C) 1995-2007 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#include "zutil.h"
|
||||
|
||||
#define local static
|
||||
|
||||
local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
|
||||
|
||||
#define BASE 65521UL /* largest prime smaller than 65536 */
|
||||
#define NMAX 5552
|
||||
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||||
|
||||
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
|
||||
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
|
||||
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
|
||||
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
|
||||
#define DO16(buf) DO8(buf,0); DO8(buf,8);
|
||||
|
||||
/* use NO_DIVIDE if your processor does not do division in hardware */
|
||||
#ifdef NO_DIVIDE
|
||||
# define MOD(a) \
|
||||
do { \
|
||||
if (a >= (BASE << 16)) a -= (BASE << 16); \
|
||||
if (a >= (BASE << 15)) a -= (BASE << 15); \
|
||||
if (a >= (BASE << 14)) a -= (BASE << 14); \
|
||||
if (a >= (BASE << 13)) a -= (BASE << 13); \
|
||||
if (a >= (BASE << 12)) a -= (BASE << 12); \
|
||||
if (a >= (BASE << 11)) a -= (BASE << 11); \
|
||||
if (a >= (BASE << 10)) a -= (BASE << 10); \
|
||||
if (a >= (BASE << 9)) a -= (BASE << 9); \
|
||||
if (a >= (BASE << 8)) a -= (BASE << 8); \
|
||||
if (a >= (BASE << 7)) a -= (BASE << 7); \
|
||||
if (a >= (BASE << 6)) a -= (BASE << 6); \
|
||||
if (a >= (BASE << 5)) a -= (BASE << 5); \
|
||||
if (a >= (BASE << 4)) a -= (BASE << 4); \
|
||||
if (a >= (BASE << 3)) a -= (BASE << 3); \
|
||||
if (a >= (BASE << 2)) a -= (BASE << 2); \
|
||||
if (a >= (BASE << 1)) a -= (BASE << 1); \
|
||||
if (a >= BASE) a -= BASE; \
|
||||
} while (0)
|
||||
# define MOD4(a) \
|
||||
do { \
|
||||
if (a >= (BASE << 4)) a -= (BASE << 4); \
|
||||
if (a >= (BASE << 3)) a -= (BASE << 3); \
|
||||
if (a >= (BASE << 2)) a -= (BASE << 2); \
|
||||
if (a >= (BASE << 1)) a -= (BASE << 1); \
|
||||
if (a >= BASE) a -= BASE; \
|
||||
} while (0)
|
||||
#else
|
||||
# define MOD(a) a %= BASE
|
||||
# define MOD4(a) a %= BASE
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT adler32(adler, buf, len)
|
||||
uLong adler;
|
||||
const Bytef *buf;
|
||||
uInt len;
|
||||
{
|
||||
unsigned long sum2;
|
||||
unsigned n;
|
||||
|
||||
/* split Adler-32 into component sums */
|
||||
sum2 = (adler >> 16) & 0xffff;
|
||||
adler &= 0xffff;
|
||||
|
||||
/* in case user likes doing a byte at a time, keep it fast */
|
||||
if (len == 1) {
|
||||
adler += buf[0];
|
||||
if (adler >= BASE)
|
||||
adler -= BASE;
|
||||
sum2 += adler;
|
||||
if (sum2 >= BASE)
|
||||
sum2 -= BASE;
|
||||
return adler | (sum2 << 16);
|
||||
}
|
||||
|
||||
/* initial Adler-32 value (deferred check for len == 1 speed) */
|
||||
if (buf == Z_NULL)
|
||||
return 1L;
|
||||
|
||||
/* in case short lengths are provided, keep it somewhat fast */
|
||||
if (len < 16) {
|
||||
while (len--) {
|
||||
adler += *buf++;
|
||||
sum2 += adler;
|
||||
}
|
||||
if (adler >= BASE)
|
||||
adler -= BASE;
|
||||
MOD4(sum2); /* only added so many BASE's */
|
||||
return adler | (sum2 << 16);
|
||||
}
|
||||
|
||||
/* do length NMAX blocks -- requires just one modulo operation */
|
||||
while (len >= NMAX) {
|
||||
len -= NMAX;
|
||||
n = NMAX / 16; /* NMAX is divisible by 16 */
|
||||
do {
|
||||
DO16(buf); /* 16 sums unrolled */
|
||||
buf += 16;
|
||||
} while (--n);
|
||||
MOD(adler);
|
||||
MOD(sum2);
|
||||
}
|
||||
|
||||
/* do remaining bytes (less than NMAX, still just one modulo) */
|
||||
if (len) { /* avoid modulos if none remaining */
|
||||
while (len >= 16) {
|
||||
len -= 16;
|
||||
DO16(buf);
|
||||
buf += 16;
|
||||
}
|
||||
while (len--) {
|
||||
adler += *buf++;
|
||||
sum2 += adler;
|
||||
}
|
||||
MOD(adler);
|
||||
MOD(sum2);
|
||||
}
|
||||
|
||||
/* return recombined sums */
|
||||
return adler | (sum2 << 16);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
local uLong adler32_combine_(adler1, adler2, len2)
|
||||
uLong adler1;
|
||||
uLong adler2;
|
||||
z_off64_t len2;
|
||||
{
|
||||
unsigned long sum1;
|
||||
unsigned long sum2;
|
||||
unsigned rem;
|
||||
|
||||
/* the derivation of this formula is left as an exercise for the reader */
|
||||
rem = (unsigned)(len2 % BASE);
|
||||
sum1 = adler1 & 0xffff;
|
||||
sum2 = rem * sum1;
|
||||
MOD(sum2);
|
||||
sum1 += (adler2 & 0xffff) + BASE - 1;
|
||||
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
|
||||
if (sum1 >= BASE) sum1 -= BASE;
|
||||
if (sum1 >= BASE) sum1 -= BASE;
|
||||
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
|
||||
if (sum2 >= BASE) sum2 -= BASE;
|
||||
return sum1 | (sum2 << 16);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
|
||||
uLong adler1;
|
||||
uLong adler2;
|
||||
z_off_t len2;
|
||||
{
|
||||
return adler32_combine_(adler1, adler2, len2);
|
||||
}
|
||||
|
||||
uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
|
||||
uLong adler1;
|
||||
uLong adler2;
|
||||
z_off64_t len2;
|
||||
{
|
||||
return adler32_combine_(adler1, adler2, len2);
|
||||
}
|
1834
deps/zlib/deflate.c
vendored
Normal file
1834
deps/zlib/deflate.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
342
deps/zlib/deflate.h
vendored
Normal file
342
deps/zlib/deflate.h
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
/* deflate.h -- internal compression state
|
||||
* Copyright (C) 1995-2010 Jean-loup Gailly
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef DEFLATE_H
|
||||
#define DEFLATE_H
|
||||
|
||||
#include "zutil.h"
|
||||
|
||||
/* define NO_GZIP when compiling if you want to disable gzip header and
|
||||
trailer creation by deflate(). NO_GZIP would be used to avoid linking in
|
||||
the crc code when it is not needed. For shared libraries, gzip encoding
|
||||
should be left enabled. */
|
||||
#ifndef NO_GZIP
|
||||
# define GZIP
|
||||
#endif
|
||||
|
||||
/* ===========================================================================
|
||||
* Internal compression state.
|
||||
*/
|
||||
|
||||
#define LENGTH_CODES 29
|
||||
/* number of length codes, not counting the special END_BLOCK code */
|
||||
|
||||
#define LITERALS 256
|
||||
/* number of literal bytes 0..255 */
|
||||
|
||||
#define L_CODES (LITERALS+1+LENGTH_CODES)
|
||||
/* number of Literal or Length codes, including the END_BLOCK code */
|
||||
|
||||
#define D_CODES 30
|
||||
/* number of distance codes */
|
||||
|
||||
#define BL_CODES 19
|
||||
/* number of codes used to transfer the bit lengths */
|
||||
|
||||
#define HEAP_SIZE (2*L_CODES+1)
|
||||
/* maximum heap size */
|
||||
|
||||
#define MAX_BITS 15
|
||||
/* All codes must not exceed MAX_BITS bits */
|
||||
|
||||
#define INIT_STATE 42
|
||||
#define EXTRA_STATE 69
|
||||
#define NAME_STATE 73
|
||||
#define COMMENT_STATE 91
|
||||
#define HCRC_STATE 103
|
||||
#define BUSY_STATE 113
|
||||
#define FINISH_STATE 666
|
||||
/* Stream status */
|
||||
|
||||
|
||||
/* Data structure describing a single value and its code string. */
|
||||
typedef struct ct_data_s {
|
||||
union {
|
||||
ush freq; /* frequency count */
|
||||
ush code; /* bit string */
|
||||
} fc;
|
||||
union {
|
||||
ush dad; /* father node in Huffman tree */
|
||||
ush len; /* length of bit string */
|
||||
} dl;
|
||||
} FAR ct_data;
|
||||
|
||||
#define Freq fc.freq
|
||||
#define Code fc.code
|
||||
#define Dad dl.dad
|
||||
#define Len dl.len
|
||||
|
||||
typedef struct static_tree_desc_s static_tree_desc;
|
||||
|
||||
typedef struct tree_desc_s {
|
||||
ct_data *dyn_tree; /* the dynamic tree */
|
||||
int max_code; /* largest code with non zero frequency */
|
||||
static_tree_desc *stat_desc; /* the corresponding static tree */
|
||||
} FAR tree_desc;
|
||||
|
||||
typedef ush Pos;
|
||||
typedef Pos FAR Posf;
|
||||
typedef unsigned IPos;
|
||||
|
||||
/* A Pos is an index in the character window. We use short instead of int to
|
||||
* save space in the various tables. IPos is used only for parameter passing.
|
||||
*/
|
||||
|
||||
typedef struct internal_state {
|
||||
z_streamp strm; /* pointer back to this zlib stream */
|
||||
int status; /* as the name implies */
|
||||
Bytef *pending_buf; /* output still pending */
|
||||
ulg pending_buf_size; /* size of pending_buf */
|
||||
Bytef *pending_out; /* next pending byte to output to the stream */
|
||||
uInt pending; /* nb of bytes in the pending buffer */
|
||||
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
|
||||
gz_headerp gzhead; /* gzip header information to write */
|
||||
uInt gzindex; /* where in extra, name, or comment */
|
||||
Byte method; /* STORED (for zip only) or DEFLATED */
|
||||
int last_flush; /* value of flush param for previous deflate call */
|
||||
|
||||
/* used by deflate.c: */
|
||||
|
||||
uInt w_size; /* LZ77 window size (32K by default) */
|
||||
uInt w_bits; /* log2(w_size) (8..16) */
|
||||
uInt w_mask; /* w_size - 1 */
|
||||
|
||||
Bytef *window;
|
||||
/* Sliding window. Input bytes are read into the second half of the window,
|
||||
* and move to the first half later to keep a dictionary of at least wSize
|
||||
* bytes. With this organization, matches are limited to a distance of
|
||||
* wSize-MAX_MATCH bytes, but this ensures that IO is always
|
||||
* performed with a length multiple of the block size. Also, it limits
|
||||
* the window size to 64K, which is quite useful on MSDOS.
|
||||
* To do: use the user input buffer as sliding window.
|
||||
*/
|
||||
|
||||
ulg window_size;
|
||||
/* Actual size of window: 2*wSize, except when the user input buffer
|
||||
* is directly used as sliding window.
|
||||
*/
|
||||
|
||||
Posf *prev;
|
||||
/* Link to older string with same hash index. To limit the size of this
|
||||
* array to 64K, this link is maintained only for the last 32K strings.
|
||||
* An index in this array is thus a window index modulo 32K.
|
||||
*/
|
||||
|
||||
Posf *head; /* Heads of the hash chains or NIL. */
|
||||
|
||||
uInt ins_h; /* hash index of string to be inserted */
|
||||
uInt hash_size; /* number of elements in hash table */
|
||||
uInt hash_bits; /* log2(hash_size) */
|
||||
uInt hash_mask; /* hash_size-1 */
|
||||
|
||||
uInt hash_shift;
|
||||
/* Number of bits by which ins_h must be shifted at each input
|
||||
* step. It must be such that after MIN_MATCH steps, the oldest
|
||||
* byte no longer takes part in the hash key, that is:
|
||||
* hash_shift * MIN_MATCH >= hash_bits
|
||||
*/
|
||||
|
||||
long block_start;
|
||||
/* Window position at the beginning of the current output block. Gets
|
||||
* negative when the window is moved backwards.
|
||||
*/
|
||||
|
||||
uInt match_length; /* length of best match */
|
||||
IPos prev_match; /* previous match */
|
||||
int match_available; /* set if previous match exists */
|
||||
uInt strstart; /* start of string to insert */
|
||||
uInt match_start; /* start of matching string */
|
||||
uInt lookahead; /* number of valid bytes ahead in window */
|
||||
|
||||
uInt prev_length;
|
||||
/* Length of the best match at previous step. Matches not greater than this
|
||||
* are discarded. This is used in the lazy match evaluation.
|
||||
*/
|
||||
|
||||
uInt max_chain_length;
|
||||
/* To speed up deflation, hash chains are never searched beyond this
|
||||
* length. A higher limit improves compression ratio but degrades the
|
||||
* speed.
|
||||
*/
|
||||
|
||||
uInt max_lazy_match;
|
||||
/* Attempt to find a better match only when the current match is strictly
|
||||
* smaller than this value. This mechanism is used only for compression
|
||||
* levels >= 4.
|
||||
*/
|
||||
# define max_insert_length max_lazy_match
|
||||
/* Insert new strings in the hash table only if the match length is not
|
||||
* greater than this length. This saves time but degrades compression.
|
||||
* max_insert_length is used only for compression levels <= 3.
|
||||
*/
|
||||
|
||||
int level; /* compression level (1..9) */
|
||||
int strategy; /* favor or force Huffman coding*/
|
||||
|
||||
uInt good_match;
|
||||
/* Use a faster search when the previous match is longer than this */
|
||||
|
||||
int nice_match; /* Stop searching when current match exceeds this */
|
||||
|
||||
/* used by trees.c: */
|
||||
/* Didn't use ct_data typedef below to supress compiler warning */
|
||||
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
|
||||
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
|
||||
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
|
||||
|
||||
struct tree_desc_s l_desc; /* desc. for literal tree */
|
||||
struct tree_desc_s d_desc; /* desc. for distance tree */
|
||||
struct tree_desc_s bl_desc; /* desc. for bit length tree */
|
||||
|
||||
ush bl_count[MAX_BITS+1];
|
||||
/* number of codes at each bit length for an optimal tree */
|
||||
|
||||
int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
|
||||
int heap_len; /* number of elements in the heap */
|
||||
int heap_max; /* element of largest frequency */
|
||||
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
|
||||
* The same heap array is used to build all trees.
|
||||
*/
|
||||
|
||||
uch depth[2*L_CODES+1];
|
||||
/* Depth of each subtree used as tie breaker for trees of equal frequency
|
||||
*/
|
||||
|
||||
uchf *l_buf; /* buffer for literals or lengths */
|
||||
|
||||
uInt lit_bufsize;
|
||||
/* Size of match buffer for literals/lengths. There are 4 reasons for
|
||||
* limiting lit_bufsize to 64K:
|
||||
* - frequencies can be kept in 16 bit counters
|
||||
* - if compression is not successful for the first block, all input
|
||||
* data is still in the window so we can still emit a stored block even
|
||||
* when input comes from standard input. (This can also be done for
|
||||
* all blocks if lit_bufsize is not greater than 32K.)
|
||||
* - if compression is not successful for a file smaller than 64K, we can
|
||||
* even emit a stored file instead of a stored block (saving 5 bytes).
|
||||
* This is applicable only for zip (not gzip or zlib).
|
||||
* - creating new Huffman trees less frequently may not provide fast
|
||||
* adaptation to changes in the input data statistics. (Take for
|
||||
* example a binary file with poorly compressible code followed by
|
||||
* a highly compressible string table.) Smaller buffer sizes give
|
||||
* fast adaptation but have of course the overhead of transmitting
|
||||
* trees more frequently.
|
||||
* - I can't count above 4
|
||||
*/
|
||||
|
||||
uInt last_lit; /* running index in l_buf */
|
||||
|
||||
ushf *d_buf;
|
||||
/* Buffer for distances. To simplify the code, d_buf and l_buf have
|
||||
* the same number of elements. To use different lengths, an extra flag
|
||||
* array would be necessary.
|
||||
*/
|
||||
|
||||
ulg opt_len; /* bit length of current block with optimal trees */
|
||||
ulg static_len; /* bit length of current block with static trees */
|
||||
uInt matches; /* number of string matches in current block */
|
||||
int last_eob_len; /* bit length of EOB code for last block */
|
||||
|
||||
#ifdef DEBUG
|
||||
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
|
||||
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
|
||||
#endif
|
||||
|
||||
ush bi_buf;
|
||||
/* Output buffer. bits are inserted starting at the bottom (least
|
||||
* significant bits).
|
||||
*/
|
||||
int bi_valid;
|
||||
/* Number of valid bits in bi_buf. All bits above the last valid bit
|
||||
* are always zero.
|
||||
*/
|
||||
|
||||
ulg high_water;
|
||||
/* High water mark offset in window for initialized bytes -- bytes above
|
||||
* this are set to zero in order to avoid memory check warnings when
|
||||
* longest match routines access bytes past the input. This is then
|
||||
* updated to the new high water mark.
|
||||
*/
|
||||
|
||||
} FAR deflate_state;
|
||||
|
||||
/* Output a byte on the stream.
|
||||
* IN assertion: there is enough room in pending_buf.
|
||||
*/
|
||||
#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
|
||||
|
||||
|
||||
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
|
||||
/* Minimum amount of lookahead, except at the end of the input file.
|
||||
* See deflate.c for comments about the MIN_MATCH+1.
|
||||
*/
|
||||
|
||||
#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
|
||||
/* In order to simplify the code, particularly on 16 bit machines, match
|
||||
* distances are limited to MAX_DIST instead of WSIZE.
|
||||
*/
|
||||
|
||||
#define WIN_INIT MAX_MATCH
|
||||
/* Number of bytes after end of data in window to initialize in order to avoid
|
||||
memory checker errors from longest match routines */
|
||||
|
||||
/* in trees.c */
|
||||
void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
|
||||
int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
|
||||
void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
|
||||
ulg stored_len, int last));
|
||||
void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
|
||||
void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
|
||||
ulg stored_len, int last));
|
||||
|
||||
#define d_code(dist) \
|
||||
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
|
||||
/* Mapping from a distance to a distance code. dist is the distance - 1 and
|
||||
* must not have side effects. _dist_code[256] and _dist_code[257] are never
|
||||
* used.
|
||||
*/
|
||||
|
||||
#ifndef DEBUG
|
||||
/* Inline versions of _tr_tally for speed: */
|
||||
|
||||
#if defined(GEN_TREES_H) || !defined(STDC)
|
||||
extern uch ZLIB_INTERNAL _length_code[];
|
||||
extern uch ZLIB_INTERNAL _dist_code[];
|
||||
#else
|
||||
extern const uch ZLIB_INTERNAL _length_code[];
|
||||
extern const uch ZLIB_INTERNAL _dist_code[];
|
||||
#endif
|
||||
|
||||
# define _tr_tally_lit(s, c, flush) \
|
||||
{ uch cc = (uch)(c); \
|
||||
s->d_buf[s->last_lit] = 0; \
|
||||
s->l_buf[s->last_lit++] = cc; \
|
||||
s->dyn_ltree[cc].Freq++; \
|
||||
flush = (s->last_lit == s->lit_bufsize-1); \
|
||||
}
|
||||
# define _tr_tally_dist(s, distance, length, flush) \
|
||||
{ uch len = (uch)(length); \
|
||||
ush dist = (ush)(distance); \
|
||||
s->d_buf[s->last_lit] = dist; \
|
||||
s->l_buf[s->last_lit++] = len; \
|
||||
dist--; \
|
||||
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
|
||||
s->dyn_dtree[d_code(dist)].Freq++; \
|
||||
flush = (s->last_lit == s->lit_bufsize-1); \
|
||||
}
|
||||
#else
|
||||
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
|
||||
# define _tr_tally_dist(s, distance, length, flush) \
|
||||
flush = _tr_tally(s, distance, length)
|
||||
#endif
|
||||
|
||||
#endif /* DEFLATE_H */
|
340
deps/zlib/inffast.c
vendored
Normal file
340
deps/zlib/inffast.c
vendored
Normal file
@ -0,0 +1,340 @@
|
||||
/* inffast.c -- fast decoding
|
||||
* Copyright (C) 1995-2008, 2010 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include "zutil.h"
|
||||
#include "inftrees.h"
|
||||
#include "inflate.h"
|
||||
#include "inffast.h"
|
||||
|
||||
#ifndef ASMINF
|
||||
|
||||
/* Allow machine dependent optimization for post-increment or pre-increment.
|
||||
Based on testing to date,
|
||||
Pre-increment preferred for:
|
||||
- PowerPC G3 (Adler)
|
||||
- MIPS R5000 (Randers-Pehrson)
|
||||
Post-increment preferred for:
|
||||
- none
|
||||
No measurable difference:
|
||||
- Pentium III (Anderson)
|
||||
- M68060 (Nikl)
|
||||
*/
|
||||
#ifdef POSTINC
|
||||
# define OFF 0
|
||||
# define PUP(a) *(a)++
|
||||
#else
|
||||
# define OFF 1
|
||||
# define PUP(a) *++(a)
|
||||
#endif
|
||||
|
||||
/*
|
||||
Decode literal, length, and distance codes and write out the resulting
|
||||
literal and match bytes until either not enough input or output is
|
||||
available, an end-of-block is encountered, or a data error is encountered.
|
||||
When large enough input and output buffers are supplied to inflate(), for
|
||||
example, a 16K input buffer and a 64K output buffer, more than 95% of the
|
||||
inflate execution time is spent in this routine.
|
||||
|
||||
Entry assumptions:
|
||||
|
||||
state->mode == LEN
|
||||
strm->avail_in >= 6
|
||||
strm->avail_out >= 258
|
||||
start >= strm->avail_out
|
||||
state->bits < 8
|
||||
|
||||
On return, state->mode is one of:
|
||||
|
||||
LEN -- ran out of enough output space or enough available input
|
||||
TYPE -- reached end of block code, inflate() to interpret next block
|
||||
BAD -- error in block data
|
||||
|
||||
Notes:
|
||||
|
||||
- The maximum input bits used by a length/distance pair is 15 bits for the
|
||||
length code, 5 bits for the length extra, 15 bits for the distance code,
|
||||
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
|
||||
Therefore if strm->avail_in >= 6, then there is enough input to avoid
|
||||
checking for available input while decoding.
|
||||
|
||||
- The maximum bytes that a single length/distance pair can output is 258
|
||||
bytes, which is the maximum length that can be coded. inflate_fast()
|
||||
requires strm->avail_out >= 258 for each loop to avoid checking for
|
||||
output space.
|
||||
*/
|
||||
void ZLIB_INTERNAL inflate_fast(strm, start)
|
||||
z_streamp strm;
|
||||
unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
{
|
||||
struct inflate_state FAR *state;
|
||||
unsigned char FAR *in; /* local strm->next_in */
|
||||
unsigned char FAR *last; /* while in < last, enough input available */
|
||||
unsigned char FAR *out; /* local strm->next_out */
|
||||
unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
|
||||
unsigned char FAR *end; /* while out < end, enough space available */
|
||||
#ifdef INFLATE_STRICT
|
||||
unsigned dmax; /* maximum distance from zlib header */
|
||||
#endif
|
||||
unsigned wsize; /* window size or zero if not using window */
|
||||
unsigned whave; /* valid bytes in the window */
|
||||
unsigned wnext; /* window write index */
|
||||
unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
|
||||
unsigned long hold; /* local strm->hold */
|
||||
unsigned bits; /* local strm->bits */
|
||||
code const FAR *lcode; /* local strm->lencode */
|
||||
code const FAR *dcode; /* local strm->distcode */
|
||||
unsigned lmask; /* mask for first level of length codes */
|
||||
unsigned dmask; /* mask for first level of distance codes */
|
||||
code here; /* retrieved table entry */
|
||||
unsigned op; /* code bits, operation, extra bits, or */
|
||||
/* window position, window bytes to copy */
|
||||
unsigned len; /* match length, unused bytes */
|
||||
unsigned dist; /* match distance */
|
||||
unsigned char FAR *from; /* where to copy match from */
|
||||
|
||||
/* copy state to local variables */
|
||||
state = (struct inflate_state FAR *)strm->state;
|
||||
in = strm->next_in - OFF;
|
||||
last = in + (strm->avail_in - 5);
|
||||
out = strm->next_out - OFF;
|
||||
beg = out - (start - strm->avail_out);
|
||||
end = out + (strm->avail_out - 257);
|
||||
#ifdef INFLATE_STRICT
|
||||
dmax = state->dmax;
|
||||
#endif
|
||||
wsize = state->wsize;
|
||||
whave = state->whave;
|
||||
wnext = state->wnext;
|
||||
window = state->window;
|
||||
hold = state->hold;
|
||||
bits = state->bits;
|
||||
lcode = state->lencode;
|
||||
dcode = state->distcode;
|
||||
lmask = (1U << state->lenbits) - 1;
|
||||
dmask = (1U << state->distbits) - 1;
|
||||
|
||||
/* decode literals and length/distances until end-of-block or not enough
|
||||
input data or output space */
|
||||
do {
|
||||
if (bits < 15) {
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
here = lcode[hold & lmask];
|
||||
dolen:
|
||||
op = (unsigned)(here.bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here.op);
|
||||
if (op == 0) { /* literal */
|
||||
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||||
"inflate: literal '%c'\n" :
|
||||
"inflate: literal 0x%02x\n", here.val));
|
||||
PUP(out) = (unsigned char)(here.val);
|
||||
}
|
||||
else if (op & 16) { /* length base */
|
||||
len = (unsigned)(here.val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (op) {
|
||||
if (bits < op) {
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
len += (unsigned)hold & ((1U << op) - 1);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
}
|
||||
Tracevv((stderr, "inflate: length %u\n", len));
|
||||
if (bits < 15) {
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
here = dcode[hold & dmask];
|
||||
dodist:
|
||||
op = (unsigned)(here.bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here.op);
|
||||
if (op & 16) { /* distance base */
|
||||
dist = (unsigned)(here.val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (bits < op) {
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
if (bits < op) {
|
||||
hold += (unsigned long)(PUP(in)) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
}
|
||||
dist += (unsigned)hold & ((1U << op) - 1);
|
||||
#ifdef INFLATE_STRICT
|
||||
if (dist > dmax) {
|
||||
strm->msg = (char *)"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
Tracevv((stderr, "inflate: distance %u\n", dist));
|
||||
op = (unsigned)(out - beg); /* max distance in output */
|
||||
if (dist > op) { /* see if copy from window */
|
||||
op = dist - op; /* distance back in window */
|
||||
if (op > whave) {
|
||||
if (state->sane) {
|
||||
strm->msg =
|
||||
(char *)"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||||
if (len <= op - whave) {
|
||||
do {
|
||||
PUP(out) = 0;
|
||||
} while (--len);
|
||||
continue;
|
||||
}
|
||||
len -= op - whave;
|
||||
do {
|
||||
PUP(out) = 0;
|
||||
} while (--op > whave);
|
||||
if (op == 0) {
|
||||
from = out - dist;
|
||||
do {
|
||||
PUP(out) = PUP(from);
|
||||
} while (--len);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
from = window - OFF;
|
||||
if (wnext == 0) { /* very common case */
|
||||
from += wsize - op;
|
||||
if (op < len) { /* some from window */
|
||||
len -= op;
|
||||
do {
|
||||
PUP(out) = PUP(from);
|
||||
} while (--op);
|
||||
from = out - dist; /* rest from output */
|
||||
}
|
||||
}
|
||||
else if (wnext < op) { /* wrap around window */
|
||||
from += wsize + wnext - op;
|
||||
op -= wnext;
|
||||
if (op < len) { /* some from end of window */
|
||||
len -= op;
|
||||
do {
|
||||
PUP(out) = PUP(from);
|
||||
} while (--op);
|
||||
from = window - OFF;
|
||||
if (wnext < len) { /* some from start of window */
|
||||
op = wnext;
|
||||
len -= op;
|
||||
do {
|
||||
PUP(out) = PUP(from);
|
||||
} while (--op);
|
||||
from = out - dist; /* rest from output */
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* contiguous in window */
|
||||
from += wnext - op;
|
||||
if (op < len) { /* some from window */
|
||||
len -= op;
|
||||
do {
|
||||
PUP(out) = PUP(from);
|
||||
} while (--op);
|
||||
from = out - dist; /* rest from output */
|
||||
}
|
||||
}
|
||||
while (len > 2) {
|
||||
PUP(out) = PUP(from);
|
||||
PUP(out) = PUP(from);
|
||||
PUP(out) = PUP(from);
|
||||
len -= 3;
|
||||
}
|
||||
if (len) {
|
||||
PUP(out) = PUP(from);
|
||||
if (len > 1)
|
||||
PUP(out) = PUP(from);
|
||||
}
|
||||
}
|
||||
else {
|
||||
from = out - dist; /* copy direct from output */
|
||||
do { /* minimum length is three */
|
||||
PUP(out) = PUP(from);
|
||||
PUP(out) = PUP(from);
|
||||
PUP(out) = PUP(from);
|
||||
len -= 3;
|
||||
} while (len > 2);
|
||||
if (len) {
|
||||
PUP(out) = PUP(from);
|
||||
if (len > 1)
|
||||
PUP(out) = PUP(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level distance code */
|
||||
here = dcode[here.val + (hold & ((1U << op) - 1))];
|
||||
goto dodist;
|
||||
}
|
||||
else {
|
||||
strm->msg = (char *)"invalid distance code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level length code */
|
||||
here = lcode[here.val + (hold & ((1U << op) - 1))];
|
||||
goto dolen;
|
||||
}
|
||||
else if (op & 32) { /* end-of-block */
|
||||
Tracevv((stderr, "inflate: end of block\n"));
|
||||
state->mode = TYPE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
strm->msg = (char *)"invalid literal/length code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
} while (in < last && out < end);
|
||||
|
||||
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
|
||||
len = bits >> 3;
|
||||
in -= len;
|
||||
bits -= len << 3;
|
||||
hold &= (1U << bits) - 1;
|
||||
|
||||
/* update state and return */
|
||||
strm->next_in = in + OFF;
|
||||
strm->next_out = out + OFF;
|
||||
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
|
||||
strm->avail_out = (unsigned)(out < end ?
|
||||
257 + (end - out) : 257 - (out - end));
|
||||
state->hold = hold;
|
||||
state->bits = bits;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
|
||||
- Using bit fields for code structure
|
||||
- Different op definition to avoid & for extra bits (do & for table bits)
|
||||
- Three separate decoding do-loops for direct, window, and wnext == 0
|
||||
- Special case for distance > 1 copies to do overlapped load and store copy
|
||||
- Explicit branch predictions (based on measured branch probabilities)
|
||||
- Deferring match copy and interspersed it with decoding subsequent codes
|
||||
- Swapping literal/length else
|
||||
- Swapping window/direct else
|
||||
- Larger unrolled copy loops (three is about right)
|
||||
- Moving len -= 3 statement into middle of loop
|
||||
*/
|
||||
|
||||
#endif /* !ASMINF */
|
11
deps/zlib/inffast.h
vendored
Normal file
11
deps/zlib/inffast.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/* inffast.h -- header to use inffast.c
|
||||
* Copyright (C) 1995-2003, 2010 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
|
94
deps/zlib/inffixed.h
vendored
Normal file
94
deps/zlib/inffixed.h
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/* inffixed.h -- table for decoding fixed codes
|
||||
* Generated automatically by makefixed().
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It
|
||||
is part of the implementation of the compression library and
|
||||
is subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
static const code lenfix[512] = {
|
||||
{96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
|
||||
{0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
|
||||
{0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
|
||||
{0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
|
||||
{0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
|
||||
{21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
|
||||
{0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
|
||||
{0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
|
||||
{18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
|
||||
{0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
|
||||
{0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
|
||||
{0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
|
||||
{20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
|
||||
{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
|
||||
{0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
|
||||
{0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
|
||||
{16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
|
||||
{0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
|
||||
{0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
|
||||
{0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
|
||||
{0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
|
||||
{0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
|
||||
{0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
|
||||
{0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
|
||||
{17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
|
||||
{0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
|
||||
{0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
|
||||
{0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
|
||||
{19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
|
||||
{0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
|
||||
{0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
|
||||
{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
|
||||
{16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
|
||||
{0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
|
||||
{0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
|
||||
{0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
|
||||
{0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
|
||||
{20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
|
||||
{0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
|
||||
{0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
|
||||
{17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
|
||||
{0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
|
||||
{0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
|
||||
{0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
|
||||
{20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
|
||||
{0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
|
||||
{0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
|
||||
{0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
|
||||
{16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
|
||||
{0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
|
||||
{0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
|
||||
{0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
|
||||
{0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
|
||||
{0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
|
||||
{0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
|
||||
{0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
|
||||
{16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
|
||||
{0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
|
||||
{0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
|
||||
{0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
|
||||
{19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
|
||||
{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
|
||||
{0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
|
||||
{0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
|
||||
{16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
|
||||
{0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
|
||||
{0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
|
||||
{0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
|
||||
{0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
|
||||
{64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
|
||||
{0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
|
||||
{0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
|
||||
{18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
|
||||
{0,9,255}
|
||||
};
|
||||
|
||||
static const code distfix[32] = {
|
||||
{16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
|
||||
{21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
|
||||
{18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
|
||||
{19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
|
||||
{16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
|
||||
{22,5,193},{64,5,0}
|
||||
};
|
1480
deps/zlib/inflate.c
vendored
Normal file
1480
deps/zlib/inflate.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
122
deps/zlib/inflate.h
vendored
Normal file
122
deps/zlib/inflate.h
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
/* inflate.h -- internal inflate state definition
|
||||
* Copyright (C) 1995-2009 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* define NO_GZIP when compiling if you want to disable gzip header and
|
||||
trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
|
||||
the crc code when it is not needed. For shared libraries, gzip decoding
|
||||
should be left enabled. */
|
||||
#ifndef NO_GZIP
|
||||
# define GUNZIP
|
||||
#endif
|
||||
|
||||
/* Possible inflate modes between inflate() calls */
|
||||
typedef enum {
|
||||
HEAD, /* i: waiting for magic header */
|
||||
FLAGS, /* i: waiting for method and flags (gzip) */
|
||||
TIME, /* i: waiting for modification time (gzip) */
|
||||
OS, /* i: waiting for extra flags and operating system (gzip) */
|
||||
EXLEN, /* i: waiting for extra length (gzip) */
|
||||
EXTRA, /* i: waiting for extra bytes (gzip) */
|
||||
NAME, /* i: waiting for end of file name (gzip) */
|
||||
COMMENT, /* i: waiting for end of comment (gzip) */
|
||||
HCRC, /* i: waiting for header crc (gzip) */
|
||||
DICTID, /* i: waiting for dictionary check value */
|
||||
DICT, /* waiting for inflateSetDictionary() call */
|
||||
TYPE, /* i: waiting for type bits, including last-flag bit */
|
||||
TYPEDO, /* i: same, but skip check to exit inflate on new block */
|
||||
STORED, /* i: waiting for stored size (length and complement) */
|
||||
COPY_, /* i/o: same as COPY below, but only first time in */
|
||||
COPY, /* i/o: waiting for input or output to copy stored block */
|
||||
TABLE, /* i: waiting for dynamic block table lengths */
|
||||
LENLENS, /* i: waiting for code length code lengths */
|
||||
CODELENS, /* i: waiting for length/lit and distance code lengths */
|
||||
LEN_, /* i: same as LEN below, but only first time in */
|
||||
LEN, /* i: waiting for length/lit/eob code */
|
||||
LENEXT, /* i: waiting for length extra bits */
|
||||
DIST, /* i: waiting for distance code */
|
||||
DISTEXT, /* i: waiting for distance extra bits */
|
||||
MATCH, /* o: waiting for output space to copy string */
|
||||
LIT, /* o: waiting for output space to write literal */
|
||||
CHECK, /* i: waiting for 32-bit check value */
|
||||
LENGTH, /* i: waiting for 32-bit length (gzip) */
|
||||
DONE, /* finished check, done -- remain here until reset */
|
||||
BAD, /* got a data error -- remain here until reset */
|
||||
MEM, /* got an inflate() memory error -- remain here until reset */
|
||||
SYNC /* looking for synchronization bytes to restart inflate() */
|
||||
} inflate_mode;
|
||||
|
||||
/*
|
||||
State transitions between above modes -
|
||||
|
||||
(most modes can go to BAD or MEM on error -- not shown for clarity)
|
||||
|
||||
Process header:
|
||||
HEAD -> (gzip) or (zlib) or (raw)
|
||||
(gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
|
||||
HCRC -> TYPE
|
||||
(zlib) -> DICTID or TYPE
|
||||
DICTID -> DICT -> TYPE
|
||||
(raw) -> TYPEDO
|
||||
Read deflate blocks:
|
||||
TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
|
||||
STORED -> COPY_ -> COPY -> TYPE
|
||||
TABLE -> LENLENS -> CODELENS -> LEN_
|
||||
LEN_ -> LEN
|
||||
Read deflate codes in fixed or dynamic block:
|
||||
LEN -> LENEXT or LIT or TYPE
|
||||
LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
|
||||
LIT -> LEN
|
||||
Process trailer:
|
||||
CHECK -> LENGTH -> DONE
|
||||
*/
|
||||
|
||||
/* state maintained between inflate() calls. Approximately 10K bytes. */
|
||||
struct inflate_state {
|
||||
inflate_mode mode; /* current inflate mode */
|
||||
int last; /* true if processing last block */
|
||||
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
|
||||
int havedict; /* true if dictionary provided */
|
||||
int flags; /* gzip header method and flags (0 if zlib) */
|
||||
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
|
||||
unsigned long check; /* protected copy of check value */
|
||||
unsigned long total; /* protected copy of output count */
|
||||
gz_headerp head; /* where to save gzip header information */
|
||||
/* sliding window */
|
||||
unsigned wbits; /* log base 2 of requested window size */
|
||||
unsigned wsize; /* window size or zero if not using window */
|
||||
unsigned whave; /* valid bytes in the window */
|
||||
unsigned wnext; /* window write index */
|
||||
unsigned char FAR *window; /* allocated sliding window, if needed */
|
||||
/* bit accumulator */
|
||||
unsigned long hold; /* input bit accumulator */
|
||||
unsigned bits; /* number of bits in "in" */
|
||||
/* for string and stored block copying */
|
||||
unsigned length; /* literal or length of data to copy */
|
||||
unsigned offset; /* distance back to copy string from */
|
||||
/* for table and code decoding */
|
||||
unsigned extra; /* extra bits needed */
|
||||
/* fixed and dynamic code tables */
|
||||
code const FAR *lencode; /* starting table for length/literal codes */
|
||||
code const FAR *distcode; /* starting table for distance codes */
|
||||
unsigned lenbits; /* index bits for lencode */
|
||||
unsigned distbits; /* index bits for distcode */
|
||||
/* dynamic table building */
|
||||
unsigned ncode; /* number of code length code lengths */
|
||||
unsigned nlen; /* number of length code lengths */
|
||||
unsigned ndist; /* number of distance code lengths */
|
||||
unsigned have; /* number of code lengths in lens[] */
|
||||
code FAR *next; /* next available space in codes[] */
|
||||
unsigned short lens[320]; /* temporary storage for code lengths */
|
||||
unsigned short work[288]; /* work area for code table building */
|
||||
code codes[ENOUGH]; /* space for code tables */
|
||||
int sane; /* if false, allow invalid distance too far */
|
||||
int back; /* bits back of last unprocessed length/lit */
|
||||
unsigned was; /* initial length of match */
|
||||
};
|
330
deps/zlib/inftrees.c
vendored
Normal file
330
deps/zlib/inftrees.c
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
/* inftrees.c -- generate Huffman trees for efficient decoding
|
||||
* Copyright (C) 1995-2010 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include "zutil.h"
|
||||
#include "inftrees.h"
|
||||
|
||||
#define MAXBITS 15
|
||||
|
||||
const char inflate_copyright[] =
|
||||
" inflate 1.2.5 Copyright 1995-2010 Mark Adler ";
|
||||
/*
|
||||
If you use the zlib library in a product, an acknowledgment is welcome
|
||||
in the documentation of your product. If for some reason you cannot
|
||||
include such an acknowledgment, I would appreciate that you keep this
|
||||
copyright string in the executable of your product.
|
||||
*/
|
||||
|
||||
/*
|
||||
Build a set of tables to decode the provided canonical Huffman code.
|
||||
The code lengths are lens[0..codes-1]. The result starts at *table,
|
||||
whose indices are 0..2^bits-1. work is a writable array of at least
|
||||
lens shorts, which is used as a work area. type is the type of code
|
||||
to be generated, CODES, LENS, or DISTS. On return, zero is success,
|
||||
-1 is an invalid code, and +1 means that ENOUGH isn't enough. table
|
||||
on return points to the next available entry's address. bits is the
|
||||
requested root table index bits, and on return it is the actual root
|
||||
table index bits. It will differ if the request is greater than the
|
||||
longest code or if it is less than the shortest code.
|
||||
*/
|
||||
int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
|
||||
codetype type;
|
||||
unsigned short FAR *lens;
|
||||
unsigned codes;
|
||||
code FAR * FAR *table;
|
||||
unsigned FAR *bits;
|
||||
unsigned short FAR *work;
|
||||
{
|
||||
unsigned len; /* a code's length in bits */
|
||||
unsigned sym; /* index of code symbols */
|
||||
unsigned min, max; /* minimum and maximum code lengths */
|
||||
unsigned root; /* number of index bits for root table */
|
||||
unsigned curr; /* number of index bits for current table */
|
||||
unsigned drop; /* code bits to drop for sub-table */
|
||||
int left; /* number of prefix codes available */
|
||||
unsigned used; /* code entries in table used */
|
||||
unsigned huff; /* Huffman code */
|
||||
unsigned incr; /* for incrementing code, index */
|
||||
unsigned fill; /* index for replicating entries */
|
||||
unsigned low; /* low bits for current root entry */
|
||||
unsigned mask; /* mask for low root bits */
|
||||
code here; /* table entry for duplication */
|
||||
code FAR *next; /* next available space in table */
|
||||
const unsigned short FAR *base; /* base value table to use */
|
||||
const unsigned short FAR *extra; /* extra bits table to use */
|
||||
int end; /* use base and extra for symbol > end */
|
||||
unsigned short count[MAXBITS+1]; /* number of codes of each length */
|
||||
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
|
||||
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
|
||||
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
||||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195};
|
||||
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
8193, 12289, 16385, 24577, 0, 0};
|
||||
static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
|
||||
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
|
||||
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
|
||||
28, 28, 29, 29, 64, 64};
|
||||
|
||||
/*
|
||||
Process a set of code lengths to create a canonical Huffman code. The
|
||||
code lengths are lens[0..codes-1]. Each length corresponds to the
|
||||
symbols 0..codes-1. The Huffman code is generated by first sorting the
|
||||
symbols by length from short to long, and retaining the symbol order
|
||||
for codes with equal lengths. Then the code starts with all zero bits
|
||||
for the first code of the shortest length, and the codes are integer
|
||||
increments for the same length, and zeros are appended as the length
|
||||
increases. For the deflate format, these bits are stored backwards
|
||||
from their more natural integer increment ordering, and so when the
|
||||
decoding tables are built in the large loop below, the integer codes
|
||||
are incremented backwards.
|
||||
|
||||
This routine assumes, but does not check, that all of the entries in
|
||||
lens[] are in the range 0..MAXBITS. The caller must assure this.
|
||||
1..MAXBITS is interpreted as that code length. zero means that that
|
||||
symbol does not occur in this code.
|
||||
|
||||
The codes are sorted by computing a count of codes for each length,
|
||||
creating from that a table of starting indices for each length in the
|
||||
sorted table, and then entering the symbols in order in the sorted
|
||||
table. The sorted table is work[], with that space being provided by
|
||||
the caller.
|
||||
|
||||
The length counts are used for other purposes as well, i.e. finding
|
||||
the minimum and maximum length codes, determining if there are any
|
||||
codes at all, checking for a valid set of lengths, and looking ahead
|
||||
at length counts to determine sub-table sizes when building the
|
||||
decoding tables.
|
||||
*/
|
||||
|
||||
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
|
||||
for (len = 0; len <= MAXBITS; len++)
|
||||
count[len] = 0;
|
||||
for (sym = 0; sym < codes; sym++)
|
||||
count[lens[sym]]++;
|
||||
|
||||
/* bound code lengths, force root to be within code lengths */
|
||||
root = *bits;
|
||||
for (max = MAXBITS; max >= 1; max--)
|
||||
if (count[max] != 0) break;
|
||||
if (root > max) root = max;
|
||||
if (max == 0) { /* no symbols to code at all */
|
||||
here.op = (unsigned char)64; /* invalid code marker */
|
||||
here.bits = (unsigned char)1;
|
||||
here.val = (unsigned short)0;
|
||||
*(*table)++ = here; /* make a table to force an error */
|
||||
*(*table)++ = here;
|
||||
*bits = 1;
|
||||
return 0; /* no symbols, but wait for decoding to report error */
|
||||
}
|
||||
for (min = 1; min < max; min++)
|
||||
if (count[min] != 0) break;
|
||||
if (root < min) root = min;
|
||||
|
||||
/* check for an over-subscribed or incomplete set of lengths */
|
||||
left = 1;
|
||||
for (len = 1; len <= MAXBITS; len++) {
|
||||
left <<= 1;
|
||||
left -= count[len];
|
||||
if (left < 0) return -1; /* over-subscribed */
|
||||
}
|
||||
if (left > 0 && (type == CODES || max != 1))
|
||||
return -1; /* incomplete set */
|
||||
|
||||
/* generate offsets into symbol table for each length for sorting */
|
||||
offs[1] = 0;
|
||||
for (len = 1; len < MAXBITS; len++)
|
||||
offs[len + 1] = offs[len] + count[len];
|
||||
|
||||
/* sort symbols by length, by symbol order within each length */
|
||||
for (sym = 0; sym < codes; sym++)
|
||||
if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
|
||||
|
||||
/*
|
||||
Create and fill in decoding tables. In this loop, the table being
|
||||
filled is at next and has curr index bits. The code being used is huff
|
||||
with length len. That code is converted to an index by dropping drop
|
||||
bits off of the bottom. For codes where len is less than drop + curr,
|
||||
those top drop + curr - len bits are incremented through all values to
|
||||
fill the table with replicated entries.
|
||||
|
||||
root is the number of index bits for the root table. When len exceeds
|
||||
root, sub-tables are created pointed to by the root entry with an index
|
||||
of the low root bits of huff. This is saved in low to check for when a
|
||||
new sub-table should be started. drop is zero when the root table is
|
||||
being filled, and drop is root when sub-tables are being filled.
|
||||
|
||||
When a new sub-table is needed, it is necessary to look ahead in the
|
||||
code lengths to determine what size sub-table is needed. The length
|
||||
counts are used for this, and so count[] is decremented as codes are
|
||||
entered in the tables.
|
||||
|
||||
used keeps track of how many table entries have been allocated from the
|
||||
provided *table space. It is checked for LENS and DIST tables against
|
||||
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
|
||||
the initial root table size constants. See the comments in inftrees.h
|
||||
for more information.
|
||||
|
||||
sym increments through all symbols, and the loop terminates when
|
||||
all codes of length max, i.e. all codes, have been processed. This
|
||||
routine permits incomplete codes, so another loop after this one fills
|
||||
in the rest of the decoding tables with invalid code markers.
|
||||
*/
|
||||
|
||||
/* set up for code type */
|
||||
switch (type) {
|
||||
case CODES:
|
||||
base = extra = work; /* dummy value--not used */
|
||||
end = 19;
|
||||
break;
|
||||
case LENS:
|
||||
base = lbase;
|
||||
base -= 257;
|
||||
extra = lext;
|
||||
extra -= 257;
|
||||
end = 256;
|
||||
break;
|
||||
default: /* DISTS */
|
||||
base = dbase;
|
||||
extra = dext;
|
||||
end = -1;
|
||||
}
|
||||
|
||||
/* initialize state for loop */
|
||||
huff = 0; /* starting code */
|
||||
sym = 0; /* starting code symbol */
|
||||
len = min; /* starting code length */
|
||||
next = *table; /* current table to fill in */
|
||||
curr = root; /* current table index bits */
|
||||
drop = 0; /* current bits to drop from code for index */
|
||||
low = (unsigned)(-1); /* trigger new sub-table when len > root */
|
||||
used = 1U << root; /* use root table entries */
|
||||
mask = used - 1; /* mask for comparing low */
|
||||
|
||||
/* check available table space */
|
||||
if ((type == LENS && used >= ENOUGH_LENS) ||
|
||||
(type == DISTS && used >= ENOUGH_DISTS))
|
||||
return 1;
|
||||
|
||||
/* process all codes and make table entries */
|
||||
for (;;) {
|
||||
/* create table entry */
|
||||
here.bits = (unsigned char)(len - drop);
|
||||
if ((int)(work[sym]) < end) {
|
||||
here.op = (unsigned char)0;
|
||||
here.val = work[sym];
|
||||
}
|
||||
else if ((int)(work[sym]) > end) {
|
||||
here.op = (unsigned char)(extra[work[sym]]);
|
||||
here.val = base[work[sym]];
|
||||
}
|
||||
else {
|
||||
here.op = (unsigned char)(32 + 64); /* end of block */
|
||||
here.val = 0;
|
||||
}
|
||||
|
||||
/* replicate for those indices with low len bits equal to huff */
|
||||
incr = 1U << (len - drop);
|
||||
fill = 1U << curr;
|
||||
min = fill; /* save offset to next table */
|
||||
do {
|
||||
fill -= incr;
|
||||
next[(huff >> drop) + fill] = here;
|
||||
} while (fill != 0);
|
||||
|
||||
/* backwards increment the len-bit code huff */
|
||||
incr = 1U << (len - 1);
|
||||
while (huff & incr)
|
||||
incr >>= 1;
|
||||
if (incr != 0) {
|
||||
huff &= incr - 1;
|
||||
huff += incr;
|
||||
}
|
||||
else
|
||||
huff = 0;
|
||||
|
||||
/* go to next symbol, update count, len */
|
||||
sym++;
|
||||
if (--(count[len]) == 0) {
|
||||
if (len == max) break;
|
||||
len = lens[work[sym]];
|
||||
}
|
||||
|
||||
/* create new sub-table if needed */
|
||||
if (len > root && (huff & mask) != low) {
|
||||
/* if first time, transition to sub-tables */
|
||||
if (drop == 0)
|
||||
drop = root;
|
||||
|
||||
/* increment past last table */
|
||||
next += min; /* here min is 1 << curr */
|
||||
|
||||
/* determine length of next table */
|
||||
curr = len - drop;
|
||||
left = (int)(1 << curr);
|
||||
while (curr + drop < max) {
|
||||
left -= count[curr + drop];
|
||||
if (left <= 0) break;
|
||||
curr++;
|
||||
left <<= 1;
|
||||
}
|
||||
|
||||
/* check for enough space */
|
||||
used += 1U << curr;
|
||||
if ((type == LENS && used >= ENOUGH_LENS) ||
|
||||
(type == DISTS && used >= ENOUGH_DISTS))
|
||||
return 1;
|
||||
|
||||
/* point entry in root table to sub-table */
|
||||
low = huff & mask;
|
||||
(*table)[low].op = (unsigned char)curr;
|
||||
(*table)[low].bits = (unsigned char)root;
|
||||
(*table)[low].val = (unsigned short)(next - *table);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fill in rest of table for incomplete codes. This loop is similar to the
|
||||
loop above in incrementing huff for table indices. It is assumed that
|
||||
len is equal to curr + drop, so there is no loop needed to increment
|
||||
through high index bits. When the current sub-table is filled, the loop
|
||||
drops back to the root table to fill in any remaining entries there.
|
||||
*/
|
||||
here.op = (unsigned char)64; /* invalid code marker */
|
||||
here.bits = (unsigned char)(len - drop);
|
||||
here.val = (unsigned short)0;
|
||||
while (huff != 0) {
|
||||
/* when done with sub-table, drop back to root table */
|
||||
if (drop != 0 && (huff & mask) != low) {
|
||||
drop = 0;
|
||||
len = root;
|
||||
next = *table;
|
||||
here.bits = (unsigned char)len;
|
||||
}
|
||||
|
||||
/* put invalid code marker in table */
|
||||
next[huff >> drop] = here;
|
||||
|
||||
/* backwards increment the len-bit code huff */
|
||||
incr = 1U << (len - 1);
|
||||
while (huff & incr)
|
||||
incr >>= 1;
|
||||
if (incr != 0) {
|
||||
huff &= incr - 1;
|
||||
huff += incr;
|
||||
}
|
||||
else
|
||||
huff = 0;
|
||||
}
|
||||
|
||||
/* set return parameters */
|
||||
*table += used;
|
||||
*bits = root;
|
||||
return 0;
|
||||
}
|
62
deps/zlib/inftrees.h
vendored
Normal file
62
deps/zlib/inftrees.h
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/* inftrees.h -- header to use inftrees.c
|
||||
* Copyright (C) 1995-2005, 2010 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* Structure for decoding tables. Each entry provides either the
|
||||
information needed to do the operation requested by the code that
|
||||
indexed that table entry, or it provides a pointer to another
|
||||
table that indexes more bits of the code. op indicates whether
|
||||
the entry is a pointer to another table, a literal, a length or
|
||||
distance, an end-of-block, or an invalid code. For a table
|
||||
pointer, the low four bits of op is the number of index bits of
|
||||
that table. For a length or distance, the low four bits of op
|
||||
is the number of extra bits to get after the code. bits is
|
||||
the number of bits in this code or part of the code to drop off
|
||||
of the bit buffer. val is the actual byte to output in the case
|
||||
of a literal, the base length or distance, or the offset from
|
||||
the current table to the next table. Each entry is four bytes. */
|
||||
typedef struct {
|
||||
unsigned char op; /* operation, extra bits, table bits */
|
||||
unsigned char bits; /* bits in this part of the code */
|
||||
unsigned short val; /* offset in table or code value */
|
||||
} code;
|
||||
|
||||
/* op values as set by inflate_table():
|
||||
00000000 - literal
|
||||
0000tttt - table link, tttt != 0 is the number of table index bits
|
||||
0001eeee - length or distance, eeee is the number of extra bits
|
||||
01100000 - end of block
|
||||
01000000 - invalid code
|
||||
*/
|
||||
|
||||
/* Maximum size of the dynamic table. The maximum number of code structures is
|
||||
1444, which is the sum of 852 for literal/length codes and 592 for distance
|
||||
codes. These values were found by exhaustive searches using the program
|
||||
examples/enough.c found in the zlib distribtution. The arguments to that
|
||||
program are the number of symbols, the initial root table size, and the
|
||||
maximum bit length of a code. "enough 286 9 15" for literal/length codes
|
||||
returns returns 852, and "enough 30 6 15" for distance codes returns 592.
|
||||
The initial root table size (9 or 6) is found in the fifth argument of the
|
||||
inflate_table() calls in inflate.c and infback.c. If the root table size is
|
||||
changed, then these maximum sizes would be need to be recalculated and
|
||||
updated. */
|
||||
#define ENOUGH_LENS 852
|
||||
#define ENOUGH_DISTS 592
|
||||
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
|
||||
|
||||
/* Type of code to build for inflate_table() */
|
||||
typedef enum {
|
||||
CODES,
|
||||
LENS,
|
||||
DISTS
|
||||
} codetype;
|
||||
|
||||
int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
|
||||
unsigned codes, code FAR * FAR *table,
|
||||
unsigned FAR *bits, unsigned short FAR *work));
|
1244
deps/zlib/trees.c
vendored
Normal file
1244
deps/zlib/trees.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
128
deps/zlib/trees.h
vendored
Normal file
128
deps/zlib/trees.h
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/* header created automatically with -DGEN_TREES_H */
|
||||
|
||||
local const ct_data static_ltree[L_CODES+2] = {
|
||||
{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
|
||||
{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
|
||||
{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
|
||||
{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
|
||||
{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
|
||||
{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
|
||||
{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
|
||||
{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
|
||||
{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
|
||||
{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
|
||||
{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
|
||||
{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
|
||||
{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
|
||||
{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
|
||||
{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
|
||||
{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
|
||||
{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
|
||||
{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
|
||||
{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
|
||||
{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
|
||||
{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
|
||||
{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
|
||||
{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
|
||||
{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
|
||||
{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
|
||||
{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
|
||||
{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
|
||||
{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
|
||||
{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
|
||||
{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
|
||||
{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
|
||||
{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
|
||||
{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
|
||||
{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
|
||||
{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
|
||||
{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
|
||||
{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
|
||||
{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
|
||||
{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
|
||||
{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
|
||||
{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
|
||||
{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
|
||||
{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
|
||||
{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
|
||||
{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
|
||||
{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
|
||||
{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
|
||||
{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
|
||||
{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
|
||||
{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
|
||||
{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
|
||||
{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
|
||||
{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
|
||||
{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
|
||||
{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
|
||||
{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
|
||||
{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
|
||||
{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
|
||||
};
|
||||
|
||||
local const ct_data static_dtree[D_CODES] = {
|
||||
{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
|
||||
{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
|
||||
{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
|
||||
{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
|
||||
{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
|
||||
{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
|
||||
};
|
||||
|
||||
const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
|
||||
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
|
||||
};
|
||||
|
||||
const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
|
||||
13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
|
||||
};
|
||||
|
||||
local const int base_length[LENGTH_CODES] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
|
||||
64, 80, 96, 112, 128, 160, 192, 224, 0
|
||||
};
|
||||
|
||||
local const int base_dist[D_CODES] = {
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
|
||||
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
|
||||
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
|
||||
};
|
||||
|
57
deps/zlib/zconf.h
vendored
Normal file
57
deps/zlib/zconf.h
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2010 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
#define NO_GZIP
|
||||
#define STDC
|
||||
|
||||
/* Jeez, don't complain about non-prototype
|
||||
* forms, we didn't write zlib */
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4131 )
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#define MAX_MEM_LEVEL 9
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
|
||||
#define ZEXTERN extern
|
||||
#define ZEXPORT
|
||||
#define ZEXPORTVA
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
#define OF(args) args
|
||||
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
typedef Byte FAR Bytef;
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
|
||||
#define z_off_t git_off_t
|
||||
#define z_off64_t z_off_t
|
||||
|
||||
#endif /* ZCONF_H */
|
1613
deps/zlib/zlib.h
vendored
Normal file
1613
deps/zlib/zlib.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
318
deps/zlib/zutil.c
vendored
Normal file
318
deps/zlib/zutil.c
vendored
Normal file
@ -0,0 +1,318 @@
|
||||
/* zutil.c -- target dependent utility functions for the compression library
|
||||
* Copyright (C) 1995-2005, 2010 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#include "zutil.h"
|
||||
|
||||
#ifndef NO_DUMMY_DECL
|
||||
struct internal_state {int dummy;}; /* for buggy compilers */
|
||||
#endif
|
||||
|
||||
const char * const z_errmsg[10] = {
|
||||
"need dictionary", /* Z_NEED_DICT 2 */
|
||||
"stream end", /* Z_STREAM_END 1 */
|
||||
"", /* Z_OK 0 */
|
||||
"file error", /* Z_ERRNO (-1) */
|
||||
"stream error", /* Z_STREAM_ERROR (-2) */
|
||||
"data error", /* Z_DATA_ERROR (-3) */
|
||||
"insufficient memory", /* Z_MEM_ERROR (-4) */
|
||||
"buffer error", /* Z_BUF_ERROR (-5) */
|
||||
"incompatible version",/* Z_VERSION_ERROR (-6) */
|
||||
""};
|
||||
|
||||
|
||||
const char * ZEXPORT zlibVersion()
|
||||
{
|
||||
return ZLIB_VERSION;
|
||||
}
|
||||
|
||||
uLong ZEXPORT zlibCompileFlags()
|
||||
{
|
||||
uLong flags;
|
||||
|
||||
flags = 0;
|
||||
switch ((int)(sizeof(uInt))) {
|
||||
case 2: break;
|
||||
case 4: flags += 1; break;
|
||||
case 8: flags += 2; break;
|
||||
default: flags += 3;
|
||||
}
|
||||
switch ((int)(sizeof(uLong))) {
|
||||
case 2: break;
|
||||
case 4: flags += 1 << 2; break;
|
||||
case 8: flags += 2 << 2; break;
|
||||
default: flags += 3 << 2;
|
||||
}
|
||||
switch ((int)(sizeof(voidpf))) {
|
||||
case 2: break;
|
||||
case 4: flags += 1 << 4; break;
|
||||
case 8: flags += 2 << 4; break;
|
||||
default: flags += 3 << 4;
|
||||
}
|
||||
switch ((int)(sizeof(z_off_t))) {
|
||||
case 2: break;
|
||||
case 4: flags += 1 << 6; break;
|
||||
case 8: flags += 2 << 6; break;
|
||||
default: flags += 3 << 6;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
flags += 1 << 8;
|
||||
#endif
|
||||
#if defined(ASMV) || defined(ASMINF)
|
||||
flags += 1 << 9;
|
||||
#endif
|
||||
#ifdef ZLIB_WINAPI
|
||||
flags += 1 << 10;
|
||||
#endif
|
||||
#ifdef BUILDFIXED
|
||||
flags += 1 << 12;
|
||||
#endif
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
flags += 1 << 13;
|
||||
#endif
|
||||
#ifdef NO_GZCOMPRESS
|
||||
flags += 1L << 16;
|
||||
#endif
|
||||
#ifdef NO_GZIP
|
||||
flags += 1L << 17;
|
||||
#endif
|
||||
#ifdef PKZIP_BUG_WORKAROUND
|
||||
flags += 1L << 20;
|
||||
#endif
|
||||
#ifdef FASTEST
|
||||
flags += 1L << 21;
|
||||
#endif
|
||||
#ifdef STDC
|
||||
# ifdef NO_vsnprintf
|
||||
flags += 1L << 25;
|
||||
# ifdef HAS_vsprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAS_vsnprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
flags += 1L << 24;
|
||||
# ifdef NO_snprintf
|
||||
flags += 1L << 25;
|
||||
# ifdef HAS_sprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAS_snprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
# ifndef verbose
|
||||
# define verbose 0
|
||||
# endif
|
||||
int ZLIB_INTERNAL z_verbose = verbose;
|
||||
|
||||
void ZLIB_INTERNAL z_error (m)
|
||||
char *m;
|
||||
{
|
||||
fprintf(stderr, "%s\n", m);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* exported to allow conversion of error code to string for compress() and
|
||||
* uncompress()
|
||||
*/
|
||||
const char * ZEXPORT zError(err)
|
||||
int err;
|
||||
{
|
||||
return ERR_MSG(err);
|
||||
}
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
/* The Microsoft C Run-Time Library for Windows CE doesn't have
|
||||
* errno. We define it as a global variable to simplify porting.
|
||||
* Its value is always 0 and should not be used.
|
||||
*/
|
||||
int errno = 0;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MEMCPY
|
||||
|
||||
void ZLIB_INTERNAL zmemcpy(dest, source, len)
|
||||
Bytef* dest;
|
||||
const Bytef* source;
|
||||
uInt len;
|
||||
{
|
||||
if (len == 0) return;
|
||||
do {
|
||||
*dest++ = *source++; /* ??? to be unrolled */
|
||||
} while (--len != 0);
|
||||
}
|
||||
|
||||
int ZLIB_INTERNAL zmemcmp(s1, s2, len)
|
||||
const Bytef* s1;
|
||||
const Bytef* s2;
|
||||
uInt len;
|
||||
{
|
||||
uInt j;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZLIB_INTERNAL zmemzero(dest, len)
|
||||
Bytef* dest;
|
||||
uInt len;
|
||||
{
|
||||
if (len == 0) return;
|
||||
do {
|
||||
*dest++ = 0; /* ??? to be unrolled */
|
||||
} while (--len != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SYS16BIT
|
||||
|
||||
#ifdef __TURBOC__
|
||||
/* Turbo C in 16-bit mode */
|
||||
|
||||
# define MY_ZCALLOC
|
||||
|
||||
/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
|
||||
* and farmalloc(64K) returns a pointer with an offset of 8, so we
|
||||
* must fix the pointer. Warning: the pointer must be put back to its
|
||||
* original form in order to free it, use zcfree().
|
||||
*/
|
||||
|
||||
#define MAX_PTR 10
|
||||
/* 10*64K = 640K */
|
||||
|
||||
local int next_ptr = 0;
|
||||
|
||||
typedef struct ptr_table_s {
|
||||
voidpf org_ptr;
|
||||
voidpf new_ptr;
|
||||
} ptr_table;
|
||||
|
||||
local ptr_table table[MAX_PTR];
|
||||
/* This table is used to remember the original form of pointers
|
||||
* to large buffers (64K). Such pointers are normalized with a zero offset.
|
||||
* Since MSDOS is not a preemptive multitasking OS, this table is not
|
||||
* protected from concurrent access. This hack doesn't work anyway on
|
||||
* a protected system like OS/2. Use Microsoft C instead.
|
||||
*/
|
||||
|
||||
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
|
||||
{
|
||||
voidpf buf = opaque; /* just to make some compilers happy */
|
||||
ulg bsize = (ulg)items*size;
|
||||
|
||||
/* If we allocate less than 65520 bytes, we assume that farmalloc
|
||||
* will return a usable pointer which doesn't have to be normalized.
|
||||
*/
|
||||
if (bsize < 65520L) {
|
||||
buf = farmalloc(bsize);
|
||||
if (*(ush*)&buf != 0) return buf;
|
||||
} else {
|
||||
buf = farmalloc(bsize + 16L);
|
||||
}
|
||||
if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
|
||||
table[next_ptr].org_ptr = buf;
|
||||
|
||||
/* Normalize the pointer to seg:0 */
|
||||
*((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
|
||||
*(ush*)&buf = 0;
|
||||
table[next_ptr++].new_ptr = buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
|
||||
{
|
||||
int n;
|
||||
if (*(ush*)&ptr != 0) { /* object < 64K */
|
||||
farfree(ptr);
|
||||
return;
|
||||
}
|
||||
/* Find the original pointer */
|
||||
for (n = 0; n < next_ptr; n++) {
|
||||
if (ptr != table[n].new_ptr) continue;
|
||||
|
||||
farfree(table[n].org_ptr);
|
||||
while (++n < next_ptr) {
|
||||
table[n-1] = table[n];
|
||||
}
|
||||
next_ptr--;
|
||||
return;
|
||||
}
|
||||
ptr = opaque; /* just to make some compilers happy */
|
||||
Assert(0, "zcfree: ptr not found");
|
||||
}
|
||||
|
||||
#endif /* __TURBOC__ */
|
||||
|
||||
|
||||
#ifdef M_I86
|
||||
/* Microsoft C in 16-bit mode */
|
||||
|
||||
# define MY_ZCALLOC
|
||||
|
||||
#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
|
||||
# define _halloc halloc
|
||||
# define _hfree hfree
|
||||
#endif
|
||||
|
||||
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
|
||||
{
|
||||
if (opaque) opaque = 0; /* to make compiler happy */
|
||||
return _halloc((long)items, size);
|
||||
}
|
||||
|
||||
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
|
||||
{
|
||||
if (opaque) opaque = 0; /* to make compiler happy */
|
||||
_hfree(ptr);
|
||||
}
|
||||
|
||||
#endif /* M_I86 */
|
||||
|
||||
#endif /* SYS16BIT */
|
||||
|
||||
|
||||
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
|
||||
|
||||
#ifndef STDC
|
||||
extern voidp malloc OF((uInt size));
|
||||
extern voidp calloc OF((uInt items, uInt size));
|
||||
extern void free OF((voidpf ptr));
|
||||
#endif
|
||||
|
||||
voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
|
||||
voidpf opaque;
|
||||
unsigned items;
|
||||
unsigned size;
|
||||
{
|
||||
if (opaque) items += size - size; /* make compiler happy */
|
||||
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
|
||||
(voidpf)calloc(items, size);
|
||||
}
|
||||
|
||||
void ZLIB_INTERNAL zcfree (opaque, ptr)
|
||||
voidpf opaque;
|
||||
voidpf ptr;
|
||||
{
|
||||
free(ptr);
|
||||
if (opaque) return; /* make compiler happy */
|
||||
}
|
||||
|
||||
#endif /* MY_ZCALLOC */
|
274
deps/zlib/zutil.h
vendored
Normal file
274
deps/zlib/zutil.h
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
/* zutil.h -- internal interface and configuration of the compression library
|
||||
* Copyright (C) 1995-2010 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZUTIL_H
|
||||
#define ZUTIL_H
|
||||
|
||||
#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)
|
||||
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
|
||||
#else
|
||||
# define ZLIB_INTERNAL
|
||||
#endif
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
#ifdef STDC
|
||||
# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
|
||||
# include <stddef.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef local
|
||||
# define local static
|
||||
#endif
|
||||
/* compile with -Dlocal if your debugger can't find static symbols */
|
||||
|
||||
typedef unsigned char uch;
|
||||
typedef uch FAR uchf;
|
||||
typedef unsigned short ush;
|
||||
typedef ush FAR ushf;
|
||||
typedef unsigned long ulg;
|
||||
|
||||
extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||
/* (size given to avoid silly warnings with Visual C++) */
|
||||
|
||||
#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
|
||||
|
||||
#define ERR_RETURN(strm,err) \
|
||||
return (strm->msg = (char*)ERR_MSG(err), (err))
|
||||
/* To be used only when the state is known to be valid */
|
||||
|
||||
/* common constants */
|
||||
|
||||
#ifndef DEF_WBITS
|
||||
# define DEF_WBITS MAX_WBITS
|
||||
#endif
|
||||
/* default windowBits for decompression. MAX_WBITS is for compression only */
|
||||
|
||||
#if MAX_MEM_LEVEL >= 8
|
||||
# define DEF_MEM_LEVEL 8
|
||||
#else
|
||||
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
|
||||
#endif
|
||||
/* default memLevel */
|
||||
|
||||
#define STORED_BLOCK 0
|
||||
#define STATIC_TREES 1
|
||||
#define DYN_TREES 2
|
||||
/* The three kinds of block type */
|
||||
|
||||
#define MIN_MATCH 3
|
||||
#define MAX_MATCH 258
|
||||
/* The minimum and maximum match lengths */
|
||||
|
||||
#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
|
||||
|
||||
/* target dependencies */
|
||||
|
||||
#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
|
||||
# define OS_CODE 0x00
|
||||
# if defined(__TURBOC__) || defined(__BORLANDC__)
|
||||
# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
|
||||
/* Allow compilation with ANSI keywords only enabled */
|
||||
void _Cdecl farfree( void *block );
|
||||
void *_Cdecl farmalloc( unsigned long nbytes );
|
||||
# else
|
||||
# include <alloc.h>
|
||||
# endif
|
||||
# else /* MSC or DJGPP */
|
||||
# include <malloc.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef AMIGA
|
||||
# define OS_CODE 0x01
|
||||
#endif
|
||||
|
||||
#if defined(VAXC) || defined(VMS)
|
||||
# define OS_CODE 0x02
|
||||
# define F_OPEN(name, mode) \
|
||||
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
|
||||
#endif
|
||||
|
||||
#if defined(ATARI) || defined(atarist)
|
||||
# define OS_CODE 0x05
|
||||
#endif
|
||||
|
||||
#ifdef OS2
|
||||
# define OS_CODE 0x06
|
||||
# ifdef M_I86
|
||||
# include <malloc.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(MACOS) || defined(TARGET_OS_MAC)
|
||||
# define OS_CODE 0x07
|
||||
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
|
||||
# include <unix.h> /* for fdopen */
|
||||
# else
|
||||
# ifndef fdopen
|
||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef TOPS20
|
||||
# define OS_CODE 0x0a
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
|
||||
# define OS_CODE 0x0b
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __50SERIES /* Prime/PRIMOS */
|
||||
# define OS_CODE 0x0f
|
||||
#endif
|
||||
|
||||
#if defined(_BEOS_) || defined(RISCOS)
|
||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
|
||||
# if defined(_WIN32_WCE)
|
||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||
# ifndef _PTRDIFF_T_DEFINED
|
||||
typedef int ptrdiff_t;
|
||||
# define _PTRDIFF_T_DEFINED
|
||||
# endif
|
||||
# else
|
||||
# define fdopen(fd,type) _fdopen(fd,type)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
#pragma warn -8004
|
||||
#pragma warn -8008
|
||||
#pragma warn -8066
|
||||
#endif
|
||||
|
||||
/* provide prototypes for these when building zlib without LFS */
|
||||
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
|
||||
#endif
|
||||
|
||||
/* common defaults */
|
||||
|
||||
#ifndef OS_CODE
|
||||
# define OS_CODE 0x03 /* assume Unix */
|
||||
#endif
|
||||
|
||||
#ifndef F_OPEN
|
||||
# define F_OPEN(name, mode) fopen((name), (mode))
|
||||
#endif
|
||||
|
||||
/* functions */
|
||||
|
||||
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
|
||||
# ifndef HAVE_VSNPRINTF
|
||||
# define HAVE_VSNPRINTF
|
||||
# endif
|
||||
#endif
|
||||
#if defined(__CYGWIN__)
|
||||
# ifndef HAVE_VSNPRINTF
|
||||
# define HAVE_VSNPRINTF
|
||||
# endif
|
||||
#endif
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
# ifdef MSDOS
|
||||
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
|
||||
but for now we just assume it doesn't. */
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef __TURBOC__
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef WIN32
|
||||
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
|
||||
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
|
||||
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
|
||||
# define vsnprintf _vsnprintf
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __SASC
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
#endif
|
||||
#ifdef VMS
|
||||
# define NO_vsnprintf
|
||||
#endif
|
||||
|
||||
#if defined(pyr)
|
||||
# define NO_MEMCPY
|
||||
#endif
|
||||
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
|
||||
/* Use our own functions for small and medium model with MSC <= 5.0.
|
||||
* You may have to use the same strategy for Borland C (untested).
|
||||
* The __SC__ check is for Symantec.
|
||||
*/
|
||||
# define NO_MEMCPY
|
||||
#endif
|
||||
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
|
||||
# define HAVE_MEMCPY
|
||||
#endif
|
||||
#ifdef HAVE_MEMCPY
|
||||
# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
|
||||
# define zmemcpy _fmemcpy
|
||||
# define zmemcmp _fmemcmp
|
||||
# define zmemzero(dest, len) _fmemset(dest, 0, len)
|
||||
# else
|
||||
# define zmemcpy memcpy
|
||||
# define zmemcmp memcmp
|
||||
# define zmemzero(dest, len) memset(dest, 0, len)
|
||||
# endif
|
||||
#else
|
||||
void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
|
||||
int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
|
||||
void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
|
||||
#endif
|
||||
|
||||
/* Diagnostic functions */
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
extern int ZLIB_INTERNAL z_verbose;
|
||||
extern void ZLIB_INTERNAL z_error OF((char *m));
|
||||
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
|
||||
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
|
||||
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
|
||||
# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
|
||||
# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
|
||||
# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
|
||||
#else
|
||||
# define Assert(cond,msg)
|
||||
# define Trace(x)
|
||||
# define Tracev(x)
|
||||
# define Tracevv(x)
|
||||
# define Tracec(c,x)
|
||||
# define Tracecv(c,x)
|
||||
#endif
|
||||
|
||||
|
||||
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
|
||||
unsigned size));
|
||||
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
|
||||
|
||||
#define ZALLOC(strm, items, size) \
|
||||
(*((strm)->zalloc))((strm)->opaque, (items), (size))
|
||||
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
|
||||
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
|
||||
|
||||
#endif /* ZUTIL_H */
|
@ -26,9 +26,9 @@
|
||||
#ifndef INCLUDE_git_git_h__
|
||||
#define INCLUDE_git_git_h__
|
||||
|
||||
#define LIBGIT2_VERSION "0.8.0"
|
||||
#define LIBGIT2_VERSION "0.11.0"
|
||||
#define LIBGIT2_VER_MAJOR 0
|
||||
#define LIBGIT2_VER_MINOR 8
|
||||
#define LIBGIT2_VER_MINOR 10
|
||||
#define LIBGIT2_VER_REVISION 0
|
||||
|
||||
#include "git2/common.h"
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a blob object from a repository.
|
||||
* The generated blob object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param blob pointer to the looked up blob
|
||||
* @param repo the repo to use when locating the blob.
|
||||
@ -55,41 +53,22 @@ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_blob.
|
||||
* Close an open blob
|
||||
*
|
||||
* The blob object must be manually filled using
|
||||
* the 'set_rawcontent' methods before it can
|
||||
* be written back to disk.
|
||||
* This is a wrapper around git_object_close()
|
||||
*
|
||||
* @param blob pointer to the new blob
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
* IMPORTANT:
|
||||
* It *is* necessary to call this method when you stop
|
||||
* using a blob. Failure to do so will cause a memory leak.
|
||||
*
|
||||
* @param blob the blob to close
|
||||
*/
|
||||
GIT_INLINE(int) git_blob_new(git_blob **blob, git_repository *repo)
|
||||
|
||||
GIT_INLINE(void) git_blob_close(git_blob *blob)
|
||||
{
|
||||
return git_object_new((git_object **)blob, repo, GIT_OBJ_BLOB);
|
||||
git_object_close((git_object *) blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a blob with the contents inside
|
||||
* the pointed file.
|
||||
*
|
||||
* @param blob pointer to the new blob
|
||||
* @param filename name of the file to read
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename);
|
||||
|
||||
/**
|
||||
* Fill a blob with the contents inside
|
||||
* the pointed buffer
|
||||
*
|
||||
* @param blob pointer to the blob
|
||||
* @param buffer buffer with the contents for the blob
|
||||
* @param len size of the buffer
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* Get a read-only buffer with the raw content of a blob.
|
||||
@ -97,7 +76,7 @@ GIT_EXTERN(int) git_blob_set_rawcontent(git_blob *blob, const void *buffer, size
|
||||
* A pointer to the raw content of a blob is returned;
|
||||
* this pointer is owned internally by the object and shall
|
||||
* not be free'd. The pointer may be invalidated at a later
|
||||
* time (e.g. when changing the contents of the blob).
|
||||
* time.
|
||||
*
|
||||
* @param blob pointer to the blob
|
||||
* @return the pointer; NULL if the blob has no contents
|
||||
@ -114,14 +93,28 @@ GIT_EXTERN(int) git_blob_rawsize(git_blob *blob);
|
||||
|
||||
/**
|
||||
* Read a file from the working folder of a repository
|
||||
* and write it to the Object Database as a loose blob,
|
||||
* if such doesn't exist yet.
|
||||
* and write it to the Object Database as a loose blob
|
||||
*
|
||||
* @param written_id return the id of the written blob
|
||||
* @param repo repository where the blob will be written
|
||||
* @param path file from which the blob will be created
|
||||
* @param oid return the id of the written blob
|
||||
* @param repo repository where the blob will be written.
|
||||
* this repository cannot be bare
|
||||
* @param path file from which the blob will be created,
|
||||
* relative to the repository's working dir
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path);
|
||||
GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path);
|
||||
|
||||
|
||||
/**
|
||||
* Write an in-memory buffer to the ODB as a blob
|
||||
*
|
||||
* @param oid return the oid of the written blob
|
||||
* @param repo repository where to blob will be written
|
||||
* @param buffer data to be written into the blob
|
||||
* @param len length of the data
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a commit object from a repository.
|
||||
* The generated commit object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param commit pointer to the looked up commit
|
||||
* @param repo the repo to use when locating the commit.
|
||||
@ -56,23 +54,25 @@ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, con
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_commit.
|
||||
* Close an open commit
|
||||
*
|
||||
* The commit object must be manually filled using
|
||||
* setter methods before it can be written to its
|
||||
* repository.
|
||||
* This is a wrapper around git_object_close()
|
||||
*
|
||||
* @param commit pointer to the new commit
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
* IMPORTANT:
|
||||
* It *is* necessary to call this method when you stop
|
||||
* using a commit. Failure to do so will cause a memory leak.
|
||||
*
|
||||
* @param commit the commit to close
|
||||
*/
|
||||
GIT_INLINE(int) git_commit_new(git_commit **commit, git_repository *repo)
|
||||
|
||||
GIT_INLINE(void) git_commit_close(git_commit *commit)
|
||||
{
|
||||
return git_object_new((git_object **)commit, repo, GIT_OBJ_COMMIT);
|
||||
git_object_close((git_object *) commit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return object identity for the commit.
|
||||
*/
|
||||
@ -80,6 +80,7 @@ GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the short (one line) message of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the short message of a commit
|
||||
*/
|
||||
@ -87,6 +88,7 @@ GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the full message of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the message of a commit
|
||||
*/
|
||||
@ -94,13 +96,15 @@ GIT_EXTERN(const char *) git_commit_message(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the commit time (i.e. committer time) of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the time of a commit
|
||||
*/
|
||||
GIT_EXTERN(time_t) git_commit_time(git_commit *commit);
|
||||
GIT_EXTERN(git_time_t) git_commit_time(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the commit timezone offset (i.e. committer's preferred timezone) of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return positive or negative timezone offset, in minutes from UTC
|
||||
*/
|
||||
@ -108,6 +112,7 @@ GIT_EXTERN(int) git_commit_time_offset(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the committer of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the committer of a commit
|
||||
*/
|
||||
@ -115,6 +120,7 @@ GIT_EXTERN(const git_signature *) git_commit_committer(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the author of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the author of a commit
|
||||
*/
|
||||
@ -122,10 +128,12 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the tree pointed to by a commit.
|
||||
*
|
||||
* @param tree_out pointer where to store the tree object
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the tree of a commit
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(const git_tree *) git_commit_tree(git_commit *commit);
|
||||
GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the number of parents of this commit
|
||||
@ -137,47 +145,137 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the specified parent of the commit.
|
||||
*
|
||||
* @param parent Pointer where to store the parent commit
|
||||
* @param commit a previously loaded commit.
|
||||
* @param n the position of the entry
|
||||
* @return a pointer to the commit; NULL if out of bounds
|
||||
*/
|
||||
GIT_EXTERN(git_commit *) git_commit_parent(git_commit *commit, unsigned int n);
|
||||
|
||||
/**
|
||||
* Add a new parent commit to an existing commit
|
||||
* @param commit the commit object
|
||||
* @param new_parent the new commit which will be a parent
|
||||
* @param n the position of the parent (from 0 to `parentcount`)
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_add_parent(git_commit *commit, git_commit *new_parent);
|
||||
GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n);
|
||||
|
||||
|
||||
/**
|
||||
* Set the message of a commit
|
||||
* @param commit the commit object
|
||||
* @param message the new message
|
||||
* Create a new commit in the repository
|
||||
*
|
||||
*
|
||||
* @param oid Pointer where to store the OID of the
|
||||
* newly created commit
|
||||
*
|
||||
* @param repo Repository where to store the commit
|
||||
*
|
||||
* @param update_ref If not NULL, name of the reference that
|
||||
* will be updated to point to this commit. If the reference
|
||||
* is not direct, it will be resolved to a direct reference.
|
||||
* Use "HEAD" to update the HEAD of the current branch and
|
||||
* make it point to this commit
|
||||
*
|
||||
* @param author Signature representing the author and the authory
|
||||
* time of this commit
|
||||
*
|
||||
* @param committer Signature representing the committer and the
|
||||
* commit time of this commit
|
||||
*
|
||||
* @param message Full message for this commit
|
||||
*
|
||||
* @param tree_oid Object ID of the tree for this commit. Note that
|
||||
* no validation is performed on this OID. Use the _o variants of
|
||||
* this method to assure a proper tree is passed to the commit.
|
||||
*
|
||||
* @param parent_count Number of parents for this commit
|
||||
*
|
||||
* @param parents Array of pointers to parent OIDs for this commit.
|
||||
* Note that no validation is performed on these OIDs. Use the _o
|
||||
* variants of this method to assure that are parents for the commit
|
||||
* are proper objects.
|
||||
*
|
||||
* @return 0 on success; error code otherwise
|
||||
* The created commit will be written to the Object Database and
|
||||
* the given reference will be updated to point to it
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_message(git_commit *commit, const char *message);
|
||||
GIT_EXTERN(int) git_commit_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
const git_oid *parent_oids[]);
|
||||
|
||||
/**
|
||||
* Set the committer of a commit
|
||||
* @param commit the commit object
|
||||
* @param author_sig signature of the committer
|
||||
* Create a new commit in the repository using `git_object`
|
||||
* instances as parameters.
|
||||
*
|
||||
* The `tree_oid` and `parent_oids` paremeters now take a instance
|
||||
* of `git_tree` and `git_commit`, respectively.
|
||||
*
|
||||
* All other parameters remain the same
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const git_signature *committer_sig);
|
||||
GIT_EXTERN(int) git_commit_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
const git_commit *parents[]);
|
||||
|
||||
/**
|
||||
* Set the author of a commit
|
||||
* @param commit the commit object
|
||||
* @param author_sig signature of the author
|
||||
* Create a new commit in the repository using `git_object`
|
||||
* instances and a variable argument list.
|
||||
*
|
||||
* The `tree_oid` paremeter now takes a instance
|
||||
* of `const git_tree *`.
|
||||
*
|
||||
* The parents for the commit are specified as a variable
|
||||
* list of pointers to `const git_commit *`. Note that this
|
||||
* is a convenience method which may not be safe to export
|
||||
* for certain languages or compilers
|
||||
*
|
||||
* All other parameters remain the same
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const git_signature *author_sig);
|
||||
GIT_EXTERN(int) git_commit_create_ov(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
...);
|
||||
|
||||
|
||||
/**
|
||||
* Set the tree which is pointed to by a commit
|
||||
* @param commit the commit object
|
||||
* @param tree the new tree
|
||||
* Create a new commit in the repository using
|
||||
* a variable argument list.
|
||||
*
|
||||
* The parents for the commit are specified as a variable
|
||||
* list of pointers to `const git_oid *`. Note that this
|
||||
* is a convenience method which may not be safe to export
|
||||
* for certain languages or compilers
|
||||
*
|
||||
* All other parameters remain the same
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_tree(git_commit *commit, git_tree *tree);
|
||||
GIT_EXTERN(int) git_commit_create_v(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
...);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "thread-utils.h"
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define GIT_BEGIN_DECL extern "C" {
|
||||
@ -118,13 +119,13 @@
|
||||
/** The object or config variable type is invalid or doesn't match */
|
||||
#define GIT_EINVALIDTYPE (GIT_ERROR - 8)
|
||||
|
||||
/** The object cannot be written that because it's missing internal data */
|
||||
/** 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 adquire or release a file lock */
|
||||
/** 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 */
|
||||
@ -145,7 +146,7 @@
|
||||
/** The specified symbolic reference is too deeply nested */
|
||||
#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17)
|
||||
|
||||
/** The pack-refs file is either corrupted of its format is not currently supported */
|
||||
/** The pack-refs file is either corrupted or its format is not currently supported */
|
||||
#define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18)
|
||||
|
||||
/** The path is invalid */
|
||||
@ -157,7 +158,21 @@
|
||||
/** 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)
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef struct {
|
||||
char **strings;
|
||||
size_t count;
|
||||
} git_strarray;
|
||||
|
||||
GIT_EXTERN(void) git_strarray_free(git_strarray *array);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -91,8 +91,8 @@ GIT_EXTERN(int) git_index_open_bare(git_index **index, const char *index_path);
|
||||
* Open the Index inside the git repository pointed
|
||||
* by 'repo'.
|
||||
*
|
||||
* @param index the pointer for the new index
|
||||
* @param repo the git repo which owns the index
|
||||
* @param index_path the path to the index file in disk
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_open_inrepo(git_index **index, git_repository *repo);
|
||||
@ -132,7 +132,7 @@ GIT_EXTERN(int) git_index_read(git_index *index);
|
||||
GIT_EXTERN(int) git_index_write(git_index *index);
|
||||
|
||||
/**
|
||||
* Find the first index of any entires which point to given
|
||||
* Find the first index of any entries which point to given
|
||||
* path in the Git index.
|
||||
*
|
||||
* @param index an existing index object
|
||||
|
@ -42,7 +42,8 @@ GIT_BEGIN_DECL
|
||||
* Lookup a reference to one of the objects in a repostory.
|
||||
*
|
||||
* The generated reference is owned by the repository and
|
||||
* should not be freed by the user.
|
||||
* should be closed with the `git_object_close` method
|
||||
* instead of free'd manually.
|
||||
*
|
||||
* The 'type' parameter must match the type of the object
|
||||
* in the odb; the method will fail otherwise.
|
||||
@ -57,55 +58,9 @@ GIT_BEGIN_DECL
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_lookup(git_object **object, git_repository *repo, const git_oid *id, git_otype type);
|
||||
|
||||
/**
|
||||
* Create a new in-memory repository object with
|
||||
* the given type.
|
||||
*
|
||||
* The object's attributes can be filled in using the
|
||||
* corresponding setter methods.
|
||||
*
|
||||
* The object will be written back to given git_repository
|
||||
* when the git_object_write() function is called; objects
|
||||
* cannot be written to disk until all their main
|
||||
* attributes have been properly filled.
|
||||
*
|
||||
* Objects are instantiated with no SHA1 id; their id
|
||||
* will be automatically generated when writing to the
|
||||
* repository.
|
||||
*
|
||||
* @param object pointer to the new object
|
||||
* @parem repo Repository where the object belongs
|
||||
* @param type Type of the object to be created
|
||||
* @return the new object
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_new(git_object **object, git_repository *repo, git_otype type);
|
||||
|
||||
|
||||
/**
|
||||
* Write back an object to disk.
|
||||
*
|
||||
* The object will be written to its corresponding
|
||||
* repository.
|
||||
*
|
||||
* If the object has no changes since it was first
|
||||
* read from the repository, no actions will take place.
|
||||
*
|
||||
* If the object has been modified since it was read from
|
||||
* the repository, or it has been created from scratch
|
||||
* in memory, it will be written to the repository and
|
||||
* its SHA1 ID will be updated accordingly.
|
||||
*
|
||||
* @param object Git object to write back
|
||||
* @return 0 on success; otherwise an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_write(git_object *object);
|
||||
|
||||
/**
|
||||
* Get the id (SHA1) of a repository object
|
||||
*
|
||||
* In-memory objects created by git_object_new() do not
|
||||
* have a SHA1 ID until they are written on a repository.
|
||||
*
|
||||
* @param obj the repository object
|
||||
* @return the SHA1 id
|
||||
*/
|
||||
@ -131,20 +86,14 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj);
|
||||
* Close an open object
|
||||
*
|
||||
* This method instructs the library to close an existing
|
||||
* object; note that git_objects are owned by the repository
|
||||
* and are reference counted, so the object may or may not be
|
||||
* freed after this library call, depending on whether any other
|
||||
* objects still depend on it.
|
||||
* object; note that git_objects are owned and cached by the repository
|
||||
* so the object may or may not be freed after this library call,
|
||||
* depending on how agressive is the caching mechanism used
|
||||
* by the repository.
|
||||
*
|
||||
* IMPORTANT:
|
||||
* It is *not* necessary to call this method when you stop using
|
||||
* an object, since all object memory is automatically reclaimed
|
||||
* by the repository when it is freed.
|
||||
*
|
||||
* Forgetting to call `git_object_close` does not cause memory
|
||||
* leaks, but it's is recommended to close as soon as possible
|
||||
* the biggest objects (e.g. blobs) to prevent wasting memory
|
||||
* space.
|
||||
* It *is* necessary to call this method when you stop using
|
||||
* an object. Failure to do so will cause a memory leak.
|
||||
*
|
||||
* @param object the object to close
|
||||
*/
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
#include "odb_backend.h"
|
||||
|
||||
/**
|
||||
* @file git2/odb.h
|
||||
@ -100,61 +101,49 @@ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, in
|
||||
|
||||
/**
|
||||
* Close an open object database.
|
||||
*
|
||||
* @param db database pointer to close. If NULL no action is taken.
|
||||
*/
|
||||
GIT_EXTERN(void) git_odb_close(git_odb *db);
|
||||
|
||||
/** An object read from the database. */
|
||||
typedef struct {
|
||||
void *data; /**< Raw, decompressed object data. */
|
||||
size_t len; /**< Total number of bytes in data. */
|
||||
git_otype type; /**< Type of this object. */
|
||||
} git_rawobj;
|
||||
|
||||
/**
|
||||
* Read an object from the database.
|
||||
*
|
||||
* If GIT_ENOTFOUND then out->data is set to NULL.
|
||||
* This method queries all avaiable ODB backends
|
||||
* trying to read the given OID.
|
||||
*
|
||||
* @param out object descriptor to populate upon reading.
|
||||
* The returned object is reference counted and
|
||||
* internally cached, so it should be closed
|
||||
* by the user once it's no longer in use.
|
||||
*
|
||||
* @param out pointer where to store the read object
|
||||
* @param db database to search for the object in.
|
||||
* @param id identity of the object to read.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object was read;
|
||||
* - GIT_ENOTFOUND if the object is not in the database.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id);
|
||||
GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Read the header of an object from the database, without
|
||||
* reading its full contents.
|
||||
*
|
||||
* Only the 'type' and 'len' fields of the git_rawobj structure
|
||||
* are filled. The 'data' pointer will always be NULL.
|
||||
* The header includes the length and the type of an object.
|
||||
*
|
||||
* The raw object pointed by 'out' doesn't need to be manually
|
||||
* closed with git_rawobj_close().
|
||||
* Note that most backends do not support reading only the header
|
||||
* of an object, so the whole object will be read and then the
|
||||
* header will be returned.
|
||||
*
|
||||
* @param out object descriptor to populate upon reading.
|
||||
* @param len_p pointer where to store the length
|
||||
* @param type_p pointer where to store the type
|
||||
* @param db database to search for the object in.
|
||||
* @param id identity of the object to read.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object was read;
|
||||
* - GIT_ENOTFOUND if the object is not in the database.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Write an object to the database.
|
||||
*
|
||||
* @param id identity of the object written.
|
||||
* @param db database to which the object should be written.
|
||||
* @param obj object descriptor for the object to write.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object was written;
|
||||
* - GIT_ERROR otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj);
|
||||
GIT_EXTERN(int) git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Determine if the given object can be found in the object database.
|
||||
@ -162,39 +151,151 @@ GIT_EXTERN(int) git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj);
|
||||
* @param db database to be searched for the given object.
|
||||
* @param id the object to search for.
|
||||
* @return
|
||||
* - true, if the object was found
|
||||
* - false, otherwise
|
||||
* - 1, if the object was found
|
||||
* - 0, otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write an object directly into the ODB
|
||||
*
|
||||
* This method writes a full object straight into the ODB.
|
||||
* For most cases, it is preferred to write objects through a write
|
||||
* stream, which is both faster and less memory intensive, specially
|
||||
* for big objects.
|
||||
*
|
||||
* This method is provided for compatibility with custom backends
|
||||
* which are not able to support streaming writes
|
||||
*
|
||||
* @param oid pointer to store the OID result of the write
|
||||
* @param odb object database where to store the object
|
||||
* @param data buffer with the data to storr
|
||||
* @param len size of the buffer
|
||||
* @param type type of the data to store
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_write(git_oid *oid, git_odb *odb, const void *data, size_t len, git_otype type);
|
||||
|
||||
/**
|
||||
* Determine the object-ID (sha1 hash) of the given git_rawobj.
|
||||
* Open a stream to write an object into the ODB
|
||||
*
|
||||
* The input obj must be a valid loose object type and the data
|
||||
* pointer must not be NULL, unless the len field is also zero.
|
||||
* The type and final length of the object must be specified
|
||||
* when opening the stream.
|
||||
*
|
||||
* The returned stream will be of type `GIT_STREAM_WRONLY` and
|
||||
* will have the following methods:
|
||||
*
|
||||
* - stream->write: write `n` bytes into the stream
|
||||
* - stream->finalize_write: close the stream and store the object in
|
||||
* the odb
|
||||
* - stream->free: free the stream
|
||||
*
|
||||
* The streaming write won't be effective until `stream->finalize_write`
|
||||
* is called and returns without an error
|
||||
*
|
||||
* The stream must always be free'd or will leak memory.
|
||||
*
|
||||
* @see git_odb_stream
|
||||
*
|
||||
* @param stream pointer where to store the stream
|
||||
* @param db object database where the stream will write
|
||||
* @param size final size of the object that will be written
|
||||
* @param type type of the object that will be written
|
||||
* @return 0 if the stream was created; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_otype type);
|
||||
|
||||
/**
|
||||
* Open a stream to read an object from the ODB
|
||||
*
|
||||
* Note that most backends do *not* support streaming reads
|
||||
* because they store their objects as compressed/delta'ed blobs.
|
||||
*
|
||||
* It's recommended to use `git_odb_read` instead, which is
|
||||
* assured to work on all backends.
|
||||
*
|
||||
* The returned stream will be of type `GIT_STREAM_RDONLY` and
|
||||
* will have the following methods:
|
||||
*
|
||||
* - stream->read: read `n` bytes from the stream
|
||||
* - stream->free: free the stream
|
||||
*
|
||||
* The stream must always be free'd or will leak memory.
|
||||
*
|
||||
* @see git_odb_stream
|
||||
*
|
||||
* @param stream pointer where to store the stream
|
||||
* @param db object database where the stream will read from
|
||||
* @param oid oid of the object the stream will read from
|
||||
* @return 0 if the stream was created; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid);
|
||||
|
||||
/**
|
||||
* Determine the object-ID (sha1 hash) of a data buffer
|
||||
*
|
||||
* The resulting SHA-1 OID will the itentifier for the data
|
||||
* buffer as if the data buffer it were to written to the ODB.
|
||||
*
|
||||
* @param id the resulting object-ID.
|
||||
* @param obj the object whose hash is to be determined.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object-ID was correctly determined.
|
||||
* - GIT_ERROR if the given object is malformed.
|
||||
* @param data data to hash
|
||||
* @param len size of the data
|
||||
* @param type of the data to hash
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_rawobj_hash(git_oid *id, git_rawobj *obj);
|
||||
GIT_EXTERN(int) git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type);
|
||||
|
||||
/**
|
||||
* Release all memory used by the obj structure.
|
||||
* Close an ODB object
|
||||
*
|
||||
* As a result of this call, obj->data will be set to NULL.
|
||||
* This method must always be called once a `git_odb_object` is no
|
||||
* longer needed, otherwise memory will leak.
|
||||
*
|
||||
* If obj->data is already NULL, nothing happens.
|
||||
*
|
||||
* @param obj object descriptor to free.
|
||||
* @param object object to close
|
||||
*/
|
||||
GIT_EXTERN(void) git_rawobj_close(git_rawobj *obj);
|
||||
GIT_EXTERN(void) git_odb_object_close(git_odb_object *object);
|
||||
|
||||
/**
|
||||
* Return the OID of an ODB object
|
||||
*
|
||||
* This is the OID from which the object was read from
|
||||
*
|
||||
* @param object the object
|
||||
* @return a pointer to the OID
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_odb_object_id(git_odb_object *object);
|
||||
|
||||
/**
|
||||
* Return the data of an ODB object
|
||||
*
|
||||
* This is the uncompressed, raw data as read from the ODB,
|
||||
* without the leading header.
|
||||
*
|
||||
* This pointer is owned by the object and shall not be free'd.
|
||||
*
|
||||
* @param object the object
|
||||
* @return a pointer to the data
|
||||
*/
|
||||
GIT_EXTERN(const void *) git_odb_object_data(git_odb_object *object);
|
||||
|
||||
/**
|
||||
* Return the size of an ODB object
|
||||
*
|
||||
* This is the real size of the `data` buffer, not the
|
||||
* actual size of the object.
|
||||
*
|
||||
* @param object the object
|
||||
* @return the size
|
||||
*/
|
||||
GIT_EXTERN(size_t) git_odb_object_size(git_odb_object *object);
|
||||
|
||||
/**
|
||||
* Return the type of an ODB object
|
||||
*
|
||||
* @param object the object
|
||||
* @return the type
|
||||
*/
|
||||
GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
#include "odb.h"
|
||||
|
||||
/**
|
||||
* @file git2/backend.h
|
||||
@ -39,24 +38,39 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
struct git_odb_stream;
|
||||
|
||||
/** An instance for a custom backend */
|
||||
struct git_odb_backend {
|
||||
git_odb *odb;
|
||||
|
||||
int (* read)(
|
||||
git_rawobj *,
|
||||
void **, size_t *, git_otype *,
|
||||
struct git_odb_backend *,
|
||||
const git_oid *);
|
||||
|
||||
int (* read_header)(
|
||||
git_rawobj *,
|
||||
size_t *, git_otype *,
|
||||
struct git_odb_backend *,
|
||||
const git_oid *);
|
||||
|
||||
int (* write)(
|
||||
git_oid *id,
|
||||
git_oid *,
|
||||
struct git_odb_backend *,
|
||||
git_rawobj *obj);
|
||||
const void *,
|
||||
size_t,
|
||||
git_otype);
|
||||
|
||||
int (* writestream)(
|
||||
struct git_odb_stream **,
|
||||
struct git_odb_backend *,
|
||||
size_t,
|
||||
git_otype);
|
||||
|
||||
int (* readstream)(
|
||||
struct git_odb_stream **,
|
||||
struct git_odb_backend *,
|
||||
const git_oid *);
|
||||
|
||||
int (* exists)(
|
||||
struct git_odb_backend *,
|
||||
@ -65,12 +79,28 @@ struct git_odb_backend {
|
||||
void (* free)(struct git_odb_backend *);
|
||||
};
|
||||
|
||||
/** A stream to read/write from a backend */
|
||||
struct git_odb_stream {
|
||||
struct git_odb_backend *backend;
|
||||
int mode;
|
||||
|
||||
int (*read)(struct git_odb_stream *stream, char *buffer, size_t len);
|
||||
int (*write)(struct git_odb_stream *stream, const char *buffer, size_t len);
|
||||
int (*finalize_write)(git_oid *oid_p, struct git_odb_stream *stream);
|
||||
void (*free)(struct git_odb_stream *stream);
|
||||
};
|
||||
|
||||
/** Streaming mode */
|
||||
typedef enum {
|
||||
GIT_STREAM_RDONLY = (1 << 1),
|
||||
GIT_STREAM_WRONLY = (1 << 2),
|
||||
GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY),
|
||||
} git_odb_streammode;
|
||||
|
||||
|
||||
GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir);
|
||||
GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir);
|
||||
|
||||
#ifdef GIT2_SQLITE_BACKEND
|
||||
GIT_EXTERN(int) git_odb_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db);
|
||||
#endif
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -68,6 +68,27 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_reposito
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target);
|
||||
|
||||
/**
|
||||
* Create a new symbolic reference, overwriting an existing one with
|
||||
* the same name, if it exists.
|
||||
*
|
||||
* If the new reference isn't a symbolic one, any pointers to the old
|
||||
* reference become invalid.
|
||||
*
|
||||
* The reference will be created in the repository and written
|
||||
* to the disk.
|
||||
*
|
||||
* This reference is owned by the repository and shall not
|
||||
* be free'd by the user.
|
||||
*
|
||||
* @param ref_out Pointer to the newly created reference
|
||||
* @param repo Repository where that reference will live
|
||||
* @param name The name of the reference
|
||||
* @param target The target of the reference
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_create_symbolic_f(git_reference **ref_out, git_repository *repo, const char *name, const char *target);
|
||||
|
||||
/**
|
||||
* Create a new object id reference.
|
||||
*
|
||||
@ -85,6 +106,27 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Create a new object id reference, overwriting an existing one with
|
||||
* the same name, if it exists.
|
||||
*
|
||||
* If the new reference isn't an object id one, any pointers to the
|
||||
* old reference become invalid.
|
||||
*
|
||||
* The reference will be created in the repository and written
|
||||
* to the disk.
|
||||
*
|
||||
* This reference is owned by the repository and shall not
|
||||
* be free'd by the user.
|
||||
*
|
||||
* @param ref_out Pointer to the newly created reference
|
||||
* @param repo Repository where that reference will live
|
||||
* @param name The name of the reference
|
||||
* @param id The object id pointed to by the reference.
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_create_oid_f(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Get the OID pointed to by a reference.
|
||||
*
|
||||
@ -189,6 +231,20 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id);
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name);
|
||||
|
||||
/**
|
||||
* Rename an existing reference, overwriting an existing one with the
|
||||
* same name, if it exists.
|
||||
*
|
||||
* This method works for both direct and symbolic references.
|
||||
* The new name will be checked for validity and may be
|
||||
* modified into a normalized form.
|
||||
*
|
||||
* The refernece will be immediately renamed in-memory
|
||||
* and on disk.
|
||||
*
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_rename_f(git_reference *ref, const char *new_name);
|
||||
|
||||
/**
|
||||
* Delete an existing reference
|
||||
*
|
||||
@ -218,6 +274,52 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref);
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_packall(git_repository *repo);
|
||||
|
||||
/**
|
||||
* Fill a list with all the references that can be found
|
||||
* in a repository.
|
||||
*
|
||||
* The listed references may be filtered by type, or using
|
||||
* a bitwise OR of several types. Use the magic value
|
||||
* `GIT_REF_LISTALL` to obtain all references, including
|
||||
* packed ones.
|
||||
*
|
||||
* The string array will be filled with the names of all
|
||||
* references; these values are owned by the user and
|
||||
* should be free'd manually when no longer needed, using
|
||||
* `git_strarray_free`.
|
||||
*
|
||||
* @param array Pointer to a git_strarray structure where
|
||||
* the reference names will be stored
|
||||
* @param repo Repository where to find the refs
|
||||
* @param list_flags Filtering flags for the reference
|
||||
* listing.
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags);
|
||||
|
||||
|
||||
/**
|
||||
* List all the references in the repository, calling a custom
|
||||
* callback for each one.
|
||||
*
|
||||
* The listed references may be filtered by type, or using
|
||||
* a bitwise OR of several types. Use the magic value
|
||||
* `GIT_REF_LISTALL` to obtain all references, including
|
||||
* packed ones.
|
||||
*
|
||||
* The `callback` function will be called for each of the references
|
||||
* in the repository, and will receive the name of the reference and
|
||||
* the `payload` value passed to this method.
|
||||
*
|
||||
* @param repo Repository where to find the refs
|
||||
* @param list_flags Filtering flags for the reference
|
||||
* listing.
|
||||
* @param callback Function which will be called for every listed ref
|
||||
* @param payload Additional data to pass to the callback
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_listcb(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -154,13 +154,17 @@ GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo);
|
||||
|
||||
/**
|
||||
* Free a previously allocated repository
|
||||
*
|
||||
* Note that after a repository is free'd, all the objects it has spawned
|
||||
* will still exist until they are manually closed by the user
|
||||
* with `git_object_close`, but accessing any of the attributes of
|
||||
* an object without a backing repository will result in undefined
|
||||
* behavior
|
||||
*
|
||||
* @param repo repository handle to close. If NULL nothing occurs.
|
||||
*/
|
||||
GIT_EXTERN(void) git_repository_free(git_repository *repo);
|
||||
|
||||
|
||||
GIT_EXTERN(void) git_repository_free__no_gc(git_repository *repo);
|
||||
|
||||
/**
|
||||
* Creates a new Git repository in the given folder.
|
||||
*
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
|
||||
/**
|
||||
* @file git2/revwalk.h
|
||||
@ -69,6 +70,17 @@ GIT_BEGIN_DECL
|
||||
/**
|
||||
* Allocate a new revision walker to iterate through a repo.
|
||||
*
|
||||
* This revision walker uses a custom memory pool and an internal
|
||||
* commit cache, so it is relatively expensive to allocate.
|
||||
*
|
||||
* For maximum performance, this revision walker should be
|
||||
* reused for different walks.
|
||||
*
|
||||
* This revision walker is *not* thread safe: it may only be
|
||||
* used to walk a repository on a single thread; however,
|
||||
* it is possible to have several revision walkers in
|
||||
* several different threads walking the same repository.
|
||||
*
|
||||
* @param walker pointer to the new revision walker
|
||||
* @param repo the repo to walk through
|
||||
* @return 0 on success; error code otherwise
|
||||
@ -76,48 +88,87 @@ GIT_BEGIN_DECL
|
||||
GIT_EXTERN(int) git_revwalk_new(git_revwalk **walker, git_repository *repo);
|
||||
|
||||
/**
|
||||
* Reset the walking machinery for reuse.
|
||||
* Reset the revision walker for reuse.
|
||||
*
|
||||
* This will clear all the pushed and hidden commits, and
|
||||
* leave the walker in a blank state (just like at
|
||||
* creation) ready to receive new commit pushes and
|
||||
* start a new walk.
|
||||
*
|
||||
* The revision walk is automatically reset when a walk
|
||||
* is over.
|
||||
*
|
||||
* @param walker handle to reset.
|
||||
*/
|
||||
GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
|
||||
|
||||
/**
|
||||
* Mark a commit to start traversal from.
|
||||
* The commit object must belong to the repo which is being walked through.
|
||||
*
|
||||
* The given OID must belong to a commit on the walked
|
||||
* repository.
|
||||
*
|
||||
* The given commit will be used as one of the roots
|
||||
* when starting the revision walk. At least one commit
|
||||
* must be pushed the repository before a walk can
|
||||
* be started.
|
||||
*
|
||||
* @param walker the walker being used for the traversal.
|
||||
* @param commit the commit to start from.
|
||||
* @param oid the oid of the commit to start from.
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, git_commit *commit);
|
||||
GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid);
|
||||
|
||||
|
||||
/**
|
||||
* Mark a commit (and its ancestors) uninteresting for the output.
|
||||
*
|
||||
* The given OID must belong to a commit on the walked
|
||||
* repository.
|
||||
*
|
||||
* The resolved commit and all its parents will be hidden from the
|
||||
* output on the revision walk.
|
||||
*
|
||||
* @param walker the walker being used for the traversal.
|
||||
* @param commit the commit that will be ignored during the traversal
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, git_commit *commit);
|
||||
GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid);
|
||||
|
||||
/**
|
||||
* Get the next commit from the revision traversal.
|
||||
* Get the next commit from the revision walk.
|
||||
*
|
||||
* @param commit Pointer where to store the next commit
|
||||
* The initial call to this method is *not* blocking when
|
||||
* iterating through a repo with a time-sorting mode.
|
||||
*
|
||||
* Iterating with Topological or inverted modes makes the initial
|
||||
* call blocking to preprocess the commit list, but this block should be
|
||||
* mostly unnoticeable on most repositories (topological preprocessing
|
||||
* times at 0.3s on the git.git repo).
|
||||
*
|
||||
* The revision walker is reset when the walk is over.
|
||||
*
|
||||
* @param oid Pointer where to store the oid of the next commit
|
||||
* @param walk the walker to pop the commit from.
|
||||
* @return GIT_SUCCESS if the next commit was found;
|
||||
* GIT_EREVWALKOVER if there are no commits left to iterate
|
||||
*/
|
||||
GIT_EXTERN(int) git_revwalk_next(git_commit **commit, git_revwalk *walk);
|
||||
GIT_EXTERN(int) git_revwalk_next(git_oid *oid, git_revwalk *walk);
|
||||
|
||||
/**
|
||||
* Change the sorting mode when iterating through the
|
||||
* repository's contents.
|
||||
*
|
||||
* Changing the sorting mode resets the walker.
|
||||
*
|
||||
* @param walk the walker being used for the traversal.
|
||||
* @param sort_mode combination of GIT_RPSORT_XXX flags
|
||||
* @param sort_mode combination of GIT_SORT_XXX flags
|
||||
*/
|
||||
GIT_EXTERN(int) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
|
||||
GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
|
||||
|
||||
/**
|
||||
* Free a revwalk previously allocated.
|
||||
* Free a revision walker previously allocated.
|
||||
*
|
||||
* @param walk traversal handle to close. If NULL nothing occurs.
|
||||
*/
|
||||
GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk);
|
||||
|
@ -45,9 +45,9 @@ GIT_BEGIN_DECL
|
||||
* @email email of the person
|
||||
* @time time when the action happened
|
||||
* @offset timezone offset in minutes for the time
|
||||
* @return the new sig, NULl on out of memory
|
||||
* @return the new sig, NULL on out of memory
|
||||
*/
|
||||
GIT_EXTERN(git_signature *) git_signature_new(const char *name, const char *email, time_t time, int offset);
|
||||
GIT_EXTERN(git_signature *) git_signature_new(const char *name, const char *email, git_time_t time, int offset);
|
||||
|
||||
/**
|
||||
* Create a copy of an existing signature.
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a tag object from the repository.
|
||||
* The generated tag object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param tag pointer to the looked up tag
|
||||
* @param repo the repo to use when locating the tag.
|
||||
@ -55,23 +53,26 @@ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oi
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_tag.
|
||||
* Close an open tag
|
||||
*
|
||||
* The tag object must be manually filled using
|
||||
* setter methods before it can be written to its
|
||||
* repository.
|
||||
* This is a wrapper around git_object_close()
|
||||
*
|
||||
* @param tag pointer to the new tag
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
* IMPORTANT:
|
||||
* It *is* necessary to call this method when you stop
|
||||
* using a tag. Failure to do so will cause a memory leak.
|
||||
*
|
||||
* @param tag the tag to close
|
||||
*/
|
||||
GIT_INLINE(int) git_tag_new(git_tag **tag, git_repository *repo)
|
||||
|
||||
GIT_INLINE(void) git_tag_close(git_tag *tag)
|
||||
{
|
||||
return git_object_new((git_object **)tag, repo, (git_otype)GIT_OBJ_TAG);
|
||||
git_object_close((git_object *) tag);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the id of a tag.
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return object identity for the tag.
|
||||
*/
|
||||
@ -79,13 +80,27 @@ GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag);
|
||||
|
||||
/**
|
||||
* Get the tagged object of a tag
|
||||
*
|
||||
* This method performs a repository lookup for the
|
||||
* given object and returns it
|
||||
*
|
||||
* @param target pointer where to store the target
|
||||
* @param tag a previously loaded tag.
|
||||
* @return reference to a repository object
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(const git_object *) git_tag_target(git_tag *t);
|
||||
GIT_EXTERN(int) git_tag_target(git_object **target, git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the OID of the tagged object of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return pointer to the OID
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_tag_target_oid(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the type of a tag's tagged object
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return type of the tagged object
|
||||
*/
|
||||
@ -93,6 +108,7 @@ GIT_EXTERN(git_otype) git_tag_type(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the name of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return name of the tag
|
||||
*/
|
||||
@ -100,6 +116,7 @@ GIT_EXTERN(const char *) git_tag_name(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the tagger (author) of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return reference to the tag's author
|
||||
*/
|
||||
@ -107,38 +124,69 @@ GIT_EXTERN(const git_signature *) git_tag_tagger(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the message of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return message of the tag
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_tag_message(git_tag *t);
|
||||
|
||||
/**
|
||||
* Set the target of a tag (i.e. the object that the tag points to)
|
||||
* @param tag The tag to modify
|
||||
* @param target the new tagged target
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_target(git_tag *tag, git_object *target);
|
||||
|
||||
/**
|
||||
* Set the name of a tag
|
||||
* @param tag The tag to modify
|
||||
* @param name the new name for the tag
|
||||
* Create a new tag in the repository from an OID
|
||||
*
|
||||
* @param oid Pointer where to store the OID of the
|
||||
* newly created tag
|
||||
*
|
||||
* @param repo Repository where to store the tag
|
||||
*
|
||||
* @param tag_name Name for the tag; this name is validated
|
||||
* for consistency
|
||||
*
|
||||
* @param target OID to which this tag points; note that no
|
||||
* validation is done on this OID. Use the _o version of this
|
||||
* method to assure a proper object is being tagged
|
||||
*
|
||||
* @param target_type Type of the tagged OID; note that no
|
||||
* validation is performed here either
|
||||
*
|
||||
* @param tagger Signature of the tagger for this tag, and
|
||||
* of the tagging time
|
||||
*
|
||||
* @param message Full message for this tag
|
||||
*
|
||||
* @return 0 on success; error code otherwise.
|
||||
* A tag object is written to the ODB, and a proper reference
|
||||
* is written in the /refs/tags folder, pointing to it
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name);
|
||||
GIT_EXTERN(int) git_tag_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_oid *target,
|
||||
git_otype target_type,
|
||||
const git_signature *tagger,
|
||||
const char *message);
|
||||
|
||||
|
||||
/**
|
||||
* Set the tagger of a tag
|
||||
* @param tag The tag to modify
|
||||
* @param tagger_sig signature of the tagging action
|
||||
* Create a new tag in the repository from an existing
|
||||
* `git_object` instance
|
||||
*
|
||||
* This method replaces the `target` and `target_type`
|
||||
* paremeters of `git_tag_create` by a single instance
|
||||
* of a `const git_object *`, which is assured to be
|
||||
* a proper object in the ODB and hence will create
|
||||
* a valid tag
|
||||
*
|
||||
* @see git_tag_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig);
|
||||
|
||||
/**
|
||||
* Set the message of a tag
|
||||
* @param tag The tag to modify
|
||||
* @param message the new tagger for the tag
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_message(git_tag *tag, const char *message);
|
||||
GIT_EXTERN(int) git_tag_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_object *target,
|
||||
const git_signature *tagger,
|
||||
const char *message);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -32,7 +32,6 @@
|
||||
*/
|
||||
|
||||
#define GIT_HAS_TLS 1
|
||||
#define GIT_HAS_PTHREAD 1
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
# undef GIT_TLS
|
||||
@ -47,7 +46,6 @@
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
# if defined(_WIN32) || defined(_WIN32_CE)
|
||||
# define GIT_TLS __declspec(thread)
|
||||
# undef GIT_HAS_PTHREAD
|
||||
# else
|
||||
# define GIT_TLS __thread
|
||||
# endif
|
||||
@ -56,11 +54,9 @@
|
||||
defined(_WIN32_CE) || \
|
||||
defined(__BORLANDC__)
|
||||
# define GIT_TLS __declspec(thread)
|
||||
# undef GIT_HAS_PTHREAD
|
||||
|
||||
#else
|
||||
# undef GIT_HAS_TLS
|
||||
# undef GIT_HAS_PTHREAD
|
||||
# define GIT_TLS /* nothing: tls vars are thread-global */
|
||||
#endif
|
||||
|
||||
@ -71,10 +67,4 @@
|
||||
# define GIT_TLS
|
||||
#endif
|
||||
|
||||
#ifdef GIT_HAS_PTHREAD
|
||||
# define GIT_THREADS 1
|
||||
#else
|
||||
# undef GIT_THREADS
|
||||
#endif
|
||||
|
||||
#endif /* INCLUDE_git_thread_utils_h__ */
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a tree object from the repository.
|
||||
* The generated tree object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param tree pointer to the looked up tree
|
||||
* @param repo the repo to use when locating the tree.
|
||||
@ -55,31 +53,34 @@ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_tree.
|
||||
* Close an open tree
|
||||
*
|
||||
* The tree object must be manually filled using
|
||||
* setter methods before it can be written to its
|
||||
* repository.
|
||||
* This is a wrapper around git_object_close()
|
||||
*
|
||||
* @param tree pointer to the new tree
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
* IMPORTANT:
|
||||
* It *is* necessary to call this method when you stop
|
||||
* using a tree. Failure to do so will cause a memory leak.
|
||||
*
|
||||
* @param tree the tree to close
|
||||
*/
|
||||
GIT_INLINE(int) git_tree_new(git_tree **tree, git_repository *repo)
|
||||
|
||||
GIT_INLINE(void) git_tree_close(git_tree *tree)
|
||||
{
|
||||
return git_object_new((git_object **)tree, repo, GIT_OBJ_TREE);
|
||||
git_object_close((git_object *) tree);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the id of a tree.
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @return object identity for the tree.
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of entries listed in a tree
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @return the number of entries in the tree
|
||||
*/
|
||||
@ -87,6 +88,7 @@ GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree);
|
||||
|
||||
/**
|
||||
* Lookup a tree entry by its filename
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @param filename the filename of the desired entry
|
||||
* @return the tree entry; NULL if not found
|
||||
@ -95,6 +97,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *f
|
||||
|
||||
/**
|
||||
* Lookup a tree entry by its position in the tree
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @param idx the position in the entry list
|
||||
* @return the tree entry; NULL if not found
|
||||
@ -103,6 +106,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx);
|
||||
|
||||
/**
|
||||
* Get the UNIX file attributes of a tree entry
|
||||
*
|
||||
* @param entry a tree entry
|
||||
* @return attributes as an integer
|
||||
*/
|
||||
@ -110,6 +114,7 @@ GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry);
|
||||
|
||||
/**
|
||||
* Get the filename of a tree entry
|
||||
*
|
||||
* @param entry a tree entry
|
||||
* @return the name of the file
|
||||
*/
|
||||
@ -117,6 +122,7 @@ GIT_EXTERN(const char *) git_tree_entry_name(git_tree_entry *entry);
|
||||
|
||||
/**
|
||||
* Get the id of the object pointed by the entry
|
||||
*
|
||||
* @param entry a tree entry
|
||||
* @return the oid of the object
|
||||
*/
|
||||
@ -126,97 +132,11 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry);
|
||||
* Convert a tree entry to the git_object it points too.
|
||||
*
|
||||
* @param object pointer to the converted object
|
||||
* @param repo repository where to lookup the pointed object
|
||||
* @param entry a tree entry
|
||||
* @return a reference to the pointed object in the repository
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_entry_2object(git_object **object, git_tree_entry *entry);
|
||||
|
||||
/**
|
||||
* Add a new entry to a tree and return the new entry.
|
||||
*
|
||||
* This will mark the tree as modified; the new entry will
|
||||
* be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry_out Pointer to the entry that just got
|
||||
* created. May be NULL if you are not interested on
|
||||
* getting the new entry
|
||||
* @param tree Tree object to store the entry
|
||||
* @iparam id OID for the tree entry
|
||||
* @param filename Filename for the tree entry
|
||||
* @param attributes UNIX file attributes for the entry
|
||||
* @return 0 on success; otherwise error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes);
|
||||
|
||||
/**
|
||||
* Remove an entry by its index.
|
||||
*
|
||||
* Index must be >= 0 and < than git_tree_entrycount().
|
||||
*
|
||||
* This will mark the tree as modified; the modified entry will
|
||||
* be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param tree Tree where to remove the entry
|
||||
* @param idx index of the entry
|
||||
* @return 0 on successful removal; GIT_ENOTFOUND if the entry wasn't found
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_remove_entry_byindex(git_tree *tree, int idx);
|
||||
|
||||
/**
|
||||
* Remove an entry by its filename.
|
||||
*
|
||||
* This will mark the tree as modified; the modified entry will
|
||||
* be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param tree Tree where to remove the entry
|
||||
* @param filename File name of the entry
|
||||
* @return 0 on successful removal; GIT_ENOTFOUND if the entry wasn't found
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_remove_entry_byname(git_tree *tree, const char *filename);
|
||||
|
||||
/**
|
||||
* Clear all the entries in a tree.
|
||||
*
|
||||
* This will mark the tree as modified; the modified entry will
|
||||
* be written back to disk on the next git_object_write().
|
||||
*
|
||||
* @param tree Tree object whose entries are to be sorted
|
||||
*/
|
||||
GIT_EXTERN(void) git_tree_clear_entries(git_tree *tree);
|
||||
|
||||
/**
|
||||
* Change the SHA1 id of a tree entry.
|
||||
*
|
||||
* This will mark the tree that contains the entry as modified;
|
||||
* the modified entry will be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry Entry object which will be modified
|
||||
* @param oid new SHA1 oid for the entry
|
||||
*/
|
||||
GIT_EXTERN(void) git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid);
|
||||
|
||||
/**
|
||||
* Change the filename of a tree entry.
|
||||
*
|
||||
* This will mark the tree that contains the entry as modified;
|
||||
* the modified entry will be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry Entry object which will be modified
|
||||
* @param oid new filename for the entry
|
||||
*/
|
||||
GIT_EXTERN(void) git_tree_entry_set_name(git_tree_entry *entry, const char *name);
|
||||
|
||||
/**
|
||||
* Change the attributes of a tree entry.
|
||||
*
|
||||
* This will mark the tree that contains the entry as modified;
|
||||
* the modified entry will be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry Entry object which will be modified
|
||||
* @param oid new attributes for the entry
|
||||
* @return 0 if the attributes were properly set; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr);
|
||||
GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -52,12 +52,12 @@ GIT_BEGIN_DECL
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
typedef __int64 git_off_t;
|
||||
typedef __time64_t git_time_t;
|
||||
typedef __time64_t git_time_t;
|
||||
|
||||
#elif defined(__MINGW32__)
|
||||
|
||||
typedef off64_t git_off_t;
|
||||
typedef time_t git_time_t;
|
||||
typedef __time64_t git_time_t;
|
||||
|
||||
#else /* POSIX */
|
||||
|
||||
@ -66,12 +66,11 @@ typedef time_t git_time_t;
|
||||
* before us (directly or indirectly), they'll get 32 bit off_t in their client
|
||||
* app, even though /we/ define _FILE_OFFSET_BITS=64.
|
||||
*/
|
||||
typedef long long git_off_t;
|
||||
typedef time_t git_time_t;
|
||||
typedef int64_t git_off_t;
|
||||
typedef int64_t git_time_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Basic type (loose or packed) of any Git object. */
|
||||
typedef enum {
|
||||
GIT_OBJ_ANY = -2, /**< Object can be any of the following */
|
||||
@ -92,6 +91,12 @@ typedef struct git_odb git_odb;
|
||||
/** A custom backend in an ODB */
|
||||
typedef struct git_odb_backend git_odb_backend;
|
||||
|
||||
/** An object read from the ODB */
|
||||
typedef struct git_odb_object git_odb_object;
|
||||
|
||||
/** A stream to read/write from the ODB */
|
||||
typedef struct git_odb_stream git_odb_stream;
|
||||
|
||||
/**
|
||||
* Representation of an existing git repository,
|
||||
* including all its object contents
|
||||
@ -130,7 +135,7 @@ typedef struct git_cvar git_cvar;
|
||||
|
||||
/** Time in a signature */
|
||||
typedef struct git_time {
|
||||
time_t time; /** time in seconds from epoch */
|
||||
git_time_t time; /** time in seconds from epoch */
|
||||
int offset; /** timezone offset, in minutes */
|
||||
} git_time;
|
||||
|
||||
@ -151,6 +156,7 @@ typedef enum {
|
||||
GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */
|
||||
GIT_REF_PACKED = 4,
|
||||
GIT_REF_HAS_PEEL = 8,
|
||||
GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED,
|
||||
} git_rtype;
|
||||
|
||||
/** @} */
|
||||
|
@ -44,21 +44,20 @@ typedef struct {
|
||||
sqlite3_stmt *st_read_header;
|
||||
} sqlite_backend;
|
||||
|
||||
int sqlite_backend__read_header(git_rawobj *obj, git_odb_backend *_backend, const git_oid *oid)
|
||||
int sqlite_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid)
|
||||
{
|
||||
sqlite_backend *backend;
|
||||
int error;
|
||||
|
||||
assert(obj && _backend && oid);
|
||||
assert(len_p && type_p && _backend && oid);
|
||||
|
||||
backend = (sqlite_backend *)_backend;
|
||||
error = GIT_ERROR;
|
||||
obj->data = NULL;
|
||||
|
||||
if (sqlite3_bind_text(backend->st_read_header, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) == SQLITE_OK) {
|
||||
if (sqlite3_step(backend->st_read_header) == SQLITE_ROW) {
|
||||
obj->type = sqlite3_column_int(backend->st_read_header, 0);
|
||||
obj->len = sqlite3_column_int(backend->st_read_header, 1);
|
||||
*type_p = (git_otype)sqlite3_column_int(backend->st_read_header, 0);
|
||||
*len_p = (size_t)sqlite3_column_int(backend->st_read_header, 1);
|
||||
assert(sqlite3_step(backend->st_read_header) == SQLITE_DONE);
|
||||
error = GIT_SUCCESS;
|
||||
} else {
|
||||
@ -71,26 +70,26 @@ int sqlite_backend__read_header(git_rawobj *obj, git_odb_backend *_backend, cons
|
||||
}
|
||||
|
||||
|
||||
int sqlite_backend__read(git_rawobj *obj, git_odb_backend *_backend, const git_oid *oid)
|
||||
int sqlite_backend__read(void **data_p, size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid)
|
||||
{
|
||||
sqlite_backend *backend;
|
||||
int error;
|
||||
|
||||
assert(obj && _backend && oid);
|
||||
assert(data_p && len_p && type_p && _backend && oid);
|
||||
|
||||
backend = (sqlite_backend *)_backend;
|
||||
error = GIT_ERROR;
|
||||
|
||||
if (sqlite3_bind_text(backend->st_read, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) == SQLITE_OK) {
|
||||
if (sqlite3_step(backend->st_read) == SQLITE_ROW) {
|
||||
obj->type = sqlite3_column_int(backend->st_read, 0);
|
||||
obj->len = sqlite3_column_int(backend->st_read, 1);
|
||||
obj->data = git__malloc(obj->len);
|
||||
*type_p = (git_otype)sqlite3_column_int(backend->st_read, 0);
|
||||
*len_p = (size_t)sqlite3_column_int(backend->st_read, 1);
|
||||
*data_p = git__malloc(*len_p);
|
||||
|
||||
if (obj->data == NULL) {
|
||||
if (*data_p == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
} else {
|
||||
memcpy(obj->data, sqlite3_column_blob(backend->st_read, 2), obj->len);
|
||||
memcpy(*data_p, sqlite3_column_blob(backend->st_read, 2), *len_p);
|
||||
error = GIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -126,27 +125,24 @@ int sqlite_backend__exists(git_odb_backend *_backend, const git_oid *oid)
|
||||
}
|
||||
|
||||
|
||||
int sqlite_backend__write(git_oid *id, git_odb_backend *_backend, git_rawobj *obj)
|
||||
int sqlite_backend__write(git_oid *id, git_odb_backend *_backend, const void *data, size_t len, git_otype type)
|
||||
{
|
||||
char hdr[64];
|
||||
int hdrlen;
|
||||
|
||||
int error;
|
||||
sqlite_backend *backend;
|
||||
|
||||
assert(id && _backend && obj);
|
||||
assert(id && _backend && data);
|
||||
|
||||
backend = (sqlite_backend *)_backend;
|
||||
|
||||
if ((error = git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj)) < 0)
|
||||
if ((error = git_odb_hash(id, data, len, type)) < 0)
|
||||
return error;
|
||||
|
||||
error = SQLITE_ERROR;
|
||||
|
||||
if (sqlite3_bind_text(backend->st_write, 1, (char *)id->id, 20, SQLITE_TRANSIENT) == SQLITE_OK &&
|
||||
sqlite3_bind_int(backend->st_write, 2, (int)obj->type) == SQLITE_OK &&
|
||||
sqlite3_bind_int(backend->st_write, 3, obj->len) == SQLITE_OK &&
|
||||
sqlite3_bind_blob(backend->st_write, 4, obj->data, obj->len, SQLITE_TRANSIENT) == SQLITE_OK) {
|
||||
sqlite3_bind_int(backend->st_write, 2, (int)type) == SQLITE_OK &&
|
||||
sqlite3_bind_int(backend->st_write, 3, len) == SQLITE_OK &&
|
||||
sqlite3_bind_blob(backend->st_write, 4, data, len, SQLITE_TRANSIENT) == SQLITE_OK) {
|
||||
error = sqlite3_step(backend->st_write);
|
||||
}
|
||||
|
||||
@ -272,4 +268,13 @@ cleanup:
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int git_odb_backend_sqlite(git_odb_backend **GIT_UNUSED(backend_out), const char *GIT_UNUSED(sqlite_db))
|
||||
{
|
||||
GIT_UNUSED_ARG(backend_out);
|
||||
GIT_UNUSED_ARG(sqlite_db);
|
||||
return GIT_ENOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SQLITE3 */
|
||||
|
137
src/blob.c
137
src/blob.c
@ -33,106 +33,89 @@
|
||||
const void *git_blob_rawcontent(git_blob *blob)
|
||||
{
|
||||
assert(blob);
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
return blob->content.data;
|
||||
|
||||
if (blob->object.in_memory)
|
||||
return NULL;
|
||||
|
||||
if (!blob->object.source.open && git_object__source_open((git_object *)blob) < GIT_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
return blob->object.source.raw.data;
|
||||
return blob->odb_object->raw.data;
|
||||
}
|
||||
|
||||
int git_blob_rawsize(git_blob *blob)
|
||||
{
|
||||
assert(blob);
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
return blob->content.len;
|
||||
|
||||
return blob->object.source.raw.len;
|
||||
return blob->odb_object->raw.len;
|
||||
}
|
||||
|
||||
void git_blob__free(git_blob *blob)
|
||||
{
|
||||
gitfo_free_buf(&blob->content);
|
||||
git_odb_object_close(blob->odb_object);
|
||||
free(blob);
|
||||
}
|
||||
|
||||
int git_blob__parse(git_blob *blob)
|
||||
int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
|
||||
{
|
||||
assert(blob);
|
||||
git_cached_obj_incref((git_cached_obj *)odb_obj);
|
||||
blob->odb_object = odb_obj;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_blob__writeback(git_blob *blob, git_odb_source *src)
|
||||
{
|
||||
assert(blob->object.modified);
|
||||
|
||||
if (blob->content.data == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
return git__source_write(src, blob->content.data, blob->content.len);
|
||||
}
|
||||
|
||||
int git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len)
|
||||
{
|
||||
assert(blob && buffer);
|
||||
|
||||
blob->object.modified = 1;
|
||||
|
||||
git_object__source_close((git_object *)blob);
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
gitfo_free_buf(&blob->content);
|
||||
|
||||
blob->content.data = git__malloc(len);
|
||||
blob->content.len = len;
|
||||
|
||||
if (blob->content.data == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memcpy(blob->content.data, buffer, len);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename)
|
||||
{
|
||||
assert(blob && filename);
|
||||
blob->object.modified = 1;
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
gitfo_free_buf(&blob->content);
|
||||
|
||||
return gitfo_read_file(&blob->content, filename);
|
||||
}
|
||||
|
||||
int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path)
|
||||
int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
|
||||
{
|
||||
int error;
|
||||
git_blob *blob;
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (gitfo_exists(path) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if ((error = git_blob_new(&blob, repo)) < GIT_SUCCESS)
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if ((error = git_blob_set_rawcontent_fromfile(blob, path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
stream->write(stream, buffer, len);
|
||||
|
||||
if ((error = git_object_write((git_object *)blob)) < GIT_SUCCESS)
|
||||
return error;
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
git_oid_cpy(written_id, git_object_id((git_object *)blob));
|
||||
|
||||
/* FIXME: maybe we don't want to free this already?
|
||||
* the user may want to access it again */
|
||||
GIT_OBJECT_DECREF(repo, blob);
|
||||
return GIT_SUCCESS;
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
|
||||
{
|
||||
int error, fd;
|
||||
char full_path[GIT_PATH_MAX];
|
||||
char buffer[2048];
|
||||
git_off_t size;
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (repo->path_workdir == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
git__joinpath(full_path, repo->path_workdir, path);
|
||||
|
||||
if ((fd = gitfo_open(full_path, O_RDONLY)) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if ((size = gitfo_size(fd)) < 0 || !git__is_sizet(size)) {
|
||||
gitfo_close(fd);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) {
|
||||
gitfo_close(fd);
|
||||
return error;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
ssize_t read_len;
|
||||
|
||||
read_len = read(fd, buffer, sizeof(buffer));
|
||||
|
||||
if (read_len < 0) {
|
||||
gitfo_close(fd);
|
||||
stream->free(stream);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
stream->write(stream, buffer, read_len);
|
||||
size -= read_len;
|
||||
}
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,15 @@
|
||||
|
||||
#include "git2/blob.h"
|
||||
#include "repository.h"
|
||||
#include "odb.h"
|
||||
#include "fileops.h"
|
||||
|
||||
struct git_blob {
|
||||
git_object object;
|
||||
gitfo_buf content;
|
||||
git_odb_object *odb_object;
|
||||
};
|
||||
|
||||
void git_blob__free(git_blob *blob);
|
||||
int git_blob__parse(git_blob *blob);
|
||||
int git_blob__writeback(git_blob *blob, git_odb_source *src);
|
||||
int git_blob__parse(git_blob *blob, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
161
src/cache.c
Normal file
161
src/cache.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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 "repository.h"
|
||||
#include "commit.h"
|
||||
#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)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (size < 8)
|
||||
size = 8;
|
||||
|
||||
/* round up size to closest power of 2 */
|
||||
size--;
|
||||
size |= size >> 1;
|
||||
size |= size >> 2;
|
||||
size |= size >> 4;
|
||||
size |= size >> 8;
|
||||
size |= size >> 16;
|
||||
|
||||
cache->size_mask = size;
|
||||
cache->lru_count = 0;
|
||||
cache->free_obj = free_ptr;
|
||||
|
||||
cache->nodes = git__malloc((size + 1) * sizeof(cache_node));
|
||||
|
||||
for (i = 0; i < (size + 1); ++i) {
|
||||
git_mutex_init(&cache->nodes[i].lock);
|
||||
cache->nodes[i].ptr = NULL;
|
||||
cache->nodes[i].lru = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void git_cache_free(git_cache *cache)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (cache->size_mask + 1); ++i) {
|
||||
if (cache->nodes[i].ptr)
|
||||
git_cached_obj_decref(cache->nodes[i].ptr, cache->free_obj);
|
||||
|
||||
git_mutex_free(&cache->nodes[i].lock);
|
||||
}
|
||||
|
||||
free(cache->nodes);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
hash = (const uint32_t *)oid->id;
|
||||
|
||||
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_unlock(&node->lock);
|
||||
}
|
||||
|
||||
|
||||
return found ? node->ptr : NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
oid = &((git_cached_obj*)entry)->oid;
|
||||
hash = (const uint32_t *)oid->id;
|
||||
|
||||
/* increase the refcount on this object, because
|
||||
* the cache now owns it */
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
return entry;
|
||||
}
|
59
src/cache.h
Normal file
59
src/cache.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef INCLUDE_cache_h__
|
||||
#define INCLUDE_cache_h__
|
||||
|
||||
#include "git2/common.h"
|
||||
#include "git2/oid.h"
|
||||
#include "git2/odb.h"
|
||||
|
||||
#include "thread-utils.h"
|
||||
|
||||
#define GIT_DEFAULT_CACHE_SIZE 128
|
||||
|
||||
typedef void (*git_cached_obj_freeptr)(void *);
|
||||
|
||||
typedef struct {
|
||||
git_oid oid;
|
||||
git_atomic refcount;
|
||||
} git_cached_obj;
|
||||
|
||||
typedef struct {
|
||||
git_cached_obj *ptr;
|
||||
git_mutex lock;
|
||||
unsigned int lru;
|
||||
} cache_node;
|
||||
|
||||
typedef struct {
|
||||
cache_node *nodes;
|
||||
|
||||
unsigned int lru_count;
|
||||
size_t size_mask;
|
||||
git_cached_obj_freeptr free_obj;
|
||||
} git_cache;
|
||||
|
||||
|
||||
void 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);
|
||||
void *git_cache_get(git_cache *cache, const git_oid *oid);
|
||||
|
||||
|
||||
GIT_INLINE(int) git_cached_obj_compare(git_cached_obj *obj, const git_oid *oid)
|
||||
{
|
||||
return git_oid_cmp(&obj->oid, oid);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_cached_obj_incref(git_cached_obj *obj)
|
||||
{
|
||||
git_atomic_inc(&obj->refcount);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_cached_obj_decref(git_cached_obj *obj, git_cached_obj_freeptr free_obj)
|
||||
{
|
||||
if (git_atomic_dec(&obj->refcount) == 0)
|
||||
free_obj(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
413
src/commit.c
413
src/commit.c
@ -29,10 +29,12 @@
|
||||
#include "git2/signature.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "odb.h"
|
||||
#include "commit.h"
|
||||
#include "revwalk.h"
|
||||
#include "signature.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define COMMIT_BASIC_PARSE 0x0
|
||||
#define COMMIT_FULL_PARSE 0x1
|
||||
|
||||
@ -46,24 +48,22 @@ static void clear_parents(git_commit *commit)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < commit->parents.length; ++i) {
|
||||
git_commit *parent = git_vector_get(&commit->parents, i);
|
||||
GIT_OBJECT_DECREF(commit->object.repo, parent);
|
||||
for (i = 0; i < commit->parent_oids.length; ++i) {
|
||||
git_oid *parent = git_vector_get(&commit->parent_oids, i);
|
||||
free(parent);
|
||||
}
|
||||
|
||||
git_vector_clear(&commit->parents);
|
||||
git_vector_clear(&commit->parent_oids);
|
||||
}
|
||||
|
||||
void git_commit__free(git_commit *commit)
|
||||
{
|
||||
clear_parents(commit);
|
||||
git_vector_free(&commit->parents);
|
||||
git_vector_free(&commit->parent_oids);
|
||||
|
||||
git_signature_free(commit->author);
|
||||
git_signature_free(commit->committer);
|
||||
|
||||
GIT_OBJECT_DECREF(commit->object.repo, commit->tree);
|
||||
|
||||
free(commit->message);
|
||||
free(commit->message_short);
|
||||
free(commit);
|
||||
@ -74,100 +74,199 @@ const git_oid *git_commit_id(git_commit *c)
|
||||
return git_object_id((git_object *)c);
|
||||
}
|
||||
|
||||
int git_commit__writeback(git_commit *commit, git_odb_source *src)
|
||||
|
||||
int git_commit_create_v(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
...)
|
||||
{
|
||||
unsigned int i;
|
||||
va_list ap;
|
||||
int i, error;
|
||||
const git_oid **oids;
|
||||
|
||||
if (commit->tree == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
oids = git__malloc(parent_count * sizeof(git_oid *));
|
||||
|
||||
git__write_oid(src, "tree", git_tree_id(commit->tree));
|
||||
va_start(ap, parent_count);
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
oids[i] = va_arg(ap, const git_oid *);
|
||||
va_end(ap);
|
||||
|
||||
for (i = 0; i < commit->parents.length; ++i) {
|
||||
git_commit *parent;
|
||||
error = git_commit_create(
|
||||
oid, repo, update_ref, author, committer, message,
|
||||
tree_oid, parent_count, oids);
|
||||
|
||||
parent = git_vector_get(&commit->parents, i);
|
||||
git__write_oid(src, "parent", git_commit_id(parent));
|
||||
}
|
||||
|
||||
if (commit->author == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
git_signature__write(src, "author", commit->author);
|
||||
|
||||
if (commit->committer == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
git_signature__write(src, "committer", commit->committer);
|
||||
|
||||
if (commit->message != NULL) {
|
||||
git__source_write(src, "\n", 1);
|
||||
git__source_write(src, commit->message, strlen(commit->message));
|
||||
}
|
||||
|
||||
/* Mark the commit as having all attributes */
|
||||
commit->full_parse = 1;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
free((void *)oids);
|
||||
return error;
|
||||
}
|
||||
|
||||
int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags)
|
||||
int git_commit_create_ov(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, error;
|
||||
const git_oid **oids;
|
||||
|
||||
oids = git__malloc(parent_count * sizeof(git_oid *));
|
||||
|
||||
va_start(ap, parent_count);
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
oids[i] = git_object_id(va_arg(ap, const git_object *));
|
||||
va_end(ap);
|
||||
|
||||
error = git_commit_create(
|
||||
oid, repo, update_ref, author, committer, message,
|
||||
git_object_id((git_object *)tree),
|
||||
parent_count, oids);
|
||||
|
||||
free((void *)oids);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_commit_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
const git_commit *parents[])
|
||||
{
|
||||
int i, error;
|
||||
const git_oid **oids;
|
||||
|
||||
oids = git__malloc(parent_count * sizeof(git_oid *));
|
||||
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
oids[i] = git_object_id((git_object *)parents[i]);
|
||||
|
||||
error = git_commit_create(
|
||||
oid, repo, update_ref, author, committer, message,
|
||||
git_object_id((git_object *)tree),
|
||||
parent_count, oids);
|
||||
|
||||
free((void *)oids);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_commit_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
const git_oid *parents[])
|
||||
{
|
||||
size_t final_size = 0;
|
||||
int message_length, author_length, committer_length;
|
||||
|
||||
char *author_str, *committer_str;
|
||||
|
||||
int error, i;
|
||||
git_odb_stream *stream;
|
||||
|
||||
message_length = strlen(message);
|
||||
author_length = git_signature__write(&author_str, "author", author);
|
||||
committer_length = git_signature__write(&committer_str, "committer", committer);
|
||||
|
||||
if (author_length < 0 || committer_length < 0)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
final_size += GIT_OID_LINE_LENGTH("tree");
|
||||
final_size += GIT_OID_LINE_LENGTH("parent") * parent_count;
|
||||
final_size += author_length;
|
||||
final_size += committer_length;
|
||||
final_size += 1 + message_length;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
git__write_oid(stream, "tree", tree_oid);
|
||||
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
git__write_oid(stream, "parent", parents[i]);
|
||||
|
||||
stream->write(stream, author_str, author_length);
|
||||
free(author_str);
|
||||
|
||||
stream->write(stream, committer_str, committer_length);
|
||||
free(committer_str);
|
||||
|
||||
|
||||
stream->write(stream, "\n", 1);
|
||||
stream->write(stream, message, message_length);
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
if (error == GIT_SUCCESS && update_ref != NULL) {
|
||||
git_reference *head;
|
||||
|
||||
error = git_reference_lookup(&head, repo, update_ref);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (git_reference_type(head) == GIT_REF_SYMBOLIC) {
|
||||
if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = git_reference_set_oid(head, oid);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int commit_parse_buffer(git_commit *commit, void *data, size_t len)
|
||||
{
|
||||
char *buffer = (char *)data;
|
||||
const char *buffer_end = (char *)data + len;
|
||||
|
||||
git_oid oid;
|
||||
git_oid parent_oid;
|
||||
int error;
|
||||
|
||||
/* first parse; the vector hasn't been initialized yet */
|
||||
if (commit->parents.contents == NULL) {
|
||||
git_vector_init(&commit->parents, 4, NULL);
|
||||
}
|
||||
git_vector_init(&commit->parent_oids, 4, NULL);
|
||||
|
||||
clear_parents(commit);
|
||||
|
||||
|
||||
if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
GIT_OBJECT_DECREF(commit->object.repo, commit->tree);
|
||||
if ((error = git_object_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS)
|
||||
if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* TODO: commit grafts!
|
||||
*/
|
||||
|
||||
while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {
|
||||
git_commit *parent;
|
||||
while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {
|
||||
git_oid *new_oid;
|
||||
|
||||
if ((error = git_object_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
|
||||
return error;
|
||||
new_oid = git__malloc(sizeof(git_oid));
|
||||
git_oid_cpy(new_oid, &parent_oid);
|
||||
|
||||
if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS)
|
||||
if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
if (parse_flags & COMMIT_FULL_PARSE) {
|
||||
if (commit->author)
|
||||
git_signature_free(commit->author);
|
||||
|
||||
commit->author = git__malloc(sizeof(git_signature));
|
||||
if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
} else {
|
||||
if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
buffer++;
|
||||
}
|
||||
commit->author = git__malloc(sizeof(git_signature));
|
||||
if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Always parse the committer; we need the commit time */
|
||||
if (commit->committer)
|
||||
git_signature_free(commit->committer);
|
||||
|
||||
commit->committer = git__malloc(sizeof(git_signature));
|
||||
if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
@ -176,7 +275,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
|
||||
while (buffer <= buffer_end && *buffer == '\n')
|
||||
buffer++;
|
||||
|
||||
if (parse_flags & COMMIT_FULL_PARSE && buffer < buffer_end) {
|
||||
if (buffer < buffer_end) {
|
||||
const char *line_end;
|
||||
size_t message_len = buffer_end - buffer;
|
||||
|
||||
@ -199,160 +298,44 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_commit__parse(git_commit *commit)
|
||||
int git_commit__parse(git_commit *commit, git_odb_object *obj)
|
||||
{
|
||||
assert(commit && commit->object.source.open);
|
||||
return commit_parse_buffer(commit,
|
||||
commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE);
|
||||
assert(commit);
|
||||
return commit_parse_buffer(commit, obj->raw.data, obj->raw.len);
|
||||
}
|
||||
|
||||
int git_commit__parse_full(git_commit *commit)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (commit->full_parse)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if ((error = git_object__source_open((git_object *)commit)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
error = commit_parse_buffer(commit,
|
||||
commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE);
|
||||
|
||||
git_object__source_close((git_object *)commit);
|
||||
|
||||
commit->full_parse = 1;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define GIT_COMMIT_GETTER(_rvalue, _name) \
|
||||
const _rvalue git_commit_##_name(git_commit *commit) \
|
||||
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
|
||||
_rvalue git_commit_##_name(git_commit *commit) \
|
||||
{\
|
||||
assert(commit); \
|
||||
if (commit->_name) \
|
||||
return commit->_name; \
|
||||
if (!commit->object.in_memory) \
|
||||
git_commit__parse_full(commit); \
|
||||
return commit->_name; \
|
||||
return _return; \
|
||||
}
|
||||
|
||||
#define CHECK_FULL_PARSE() \
|
||||
if (!commit->object.in_memory && !commit->full_parse)\
|
||||
git_commit__parse_full(commit);
|
||||
GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
|
||||
GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
|
||||
GIT_COMMIT_GETTER(const char *, message, commit->message)
|
||||
GIT_COMMIT_GETTER(const char *, message_short, commit->message_short)
|
||||
GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
|
||||
GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
|
||||
GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)
|
||||
|
||||
const git_tree *git_commit_tree(git_commit *commit)
|
||||
|
||||
int git_commit_tree(git_tree **tree_out, git_commit *commit)
|
||||
{
|
||||
assert(commit);
|
||||
|
||||
if (!commit->object.in_memory && commit->tree == NULL)
|
||||
git_commit__parse_full(commit);
|
||||
|
||||
GIT_OBJECT_INCREF(commit->object.repo, commit->tree);
|
||||
return commit->tree;
|
||||
return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid);
|
||||
}
|
||||
|
||||
GIT_COMMIT_GETTER(git_signature *, author)
|
||||
GIT_COMMIT_GETTER(git_signature *, committer)
|
||||
GIT_COMMIT_GETTER(char *, message)
|
||||
GIT_COMMIT_GETTER(char *, message_short)
|
||||
|
||||
time_t git_commit_time(git_commit *commit)
|
||||
int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)
|
||||
{
|
||||
assert(commit && commit->committer);
|
||||
return commit->committer->when.time;
|
||||
}
|
||||
|
||||
int git_commit_time_offset(git_commit *commit)
|
||||
{
|
||||
assert(commit && commit->committer);
|
||||
return commit->committer->when.offset;
|
||||
}
|
||||
|
||||
unsigned int git_commit_parentcount(git_commit *commit)
|
||||
{
|
||||
assert(commit);
|
||||
return commit->parents.length;
|
||||
}
|
||||
|
||||
git_commit *git_commit_parent(git_commit *commit, unsigned int n)
|
||||
{
|
||||
git_commit *parent;
|
||||
|
||||
git_oid *parent_oid;
|
||||
assert(commit);
|
||||
|
||||
parent = git_vector_get(&commit->parents, n);
|
||||
GIT_OBJECT_INCREF(commit->object.repo, parent);
|
||||
return parent;
|
||||
parent_oid = git_vector_get(&commit->parent_oids, n);
|
||||
if (parent_oid == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return git_commit_lookup(parent, commit->object.repo, parent_oid);
|
||||
}
|
||||
|
||||
void git_commit_set_tree(git_commit *commit, git_tree *tree)
|
||||
{
|
||||
assert(commit && tree);
|
||||
commit->object.modified = 1;
|
||||
CHECK_FULL_PARSE();
|
||||
|
||||
GIT_OBJECT_DECREF(commit->object.repo, commit->tree);
|
||||
GIT_OBJECT_INCREF(commit->object.repo, tree);
|
||||
commit->tree = tree;
|
||||
}
|
||||
|
||||
void git_commit_set_author(git_commit *commit, const git_signature *author_sig)
|
||||
{
|
||||
assert(commit && author_sig);
|
||||
commit->object.modified = 1;
|
||||
CHECK_FULL_PARSE();
|
||||
|
||||
git_signature_free(commit->author);
|
||||
commit->author = git_signature_dup(author_sig);
|
||||
}
|
||||
|
||||
void git_commit_set_committer(git_commit *commit, const git_signature *committer_sig)
|
||||
{
|
||||
assert(commit && committer_sig);
|
||||
commit->object.modified = 1;
|
||||
CHECK_FULL_PARSE();
|
||||
|
||||
git_signature_free(commit->committer);
|
||||
commit->committer = git_signature_dup(committer_sig);
|
||||
}
|
||||
|
||||
void git_commit_set_message(git_commit *commit, const char *message)
|
||||
{
|
||||
const char *line_end;
|
||||
size_t message_len;
|
||||
|
||||
commit->object.modified = 1;
|
||||
CHECK_FULL_PARSE();
|
||||
|
||||
if (commit->message)
|
||||
free(commit->message);
|
||||
|
||||
if (commit->message_short)
|
||||
free(commit->message_short);
|
||||
|
||||
commit->message = git__strdup(message);
|
||||
|
||||
/* Short message */
|
||||
if((line_end = strchr(message, '\n')) == NULL) {
|
||||
commit->message_short = git__strdup(message);
|
||||
return;
|
||||
}
|
||||
|
||||
message_len = line_end - message;
|
||||
|
||||
commit->message_short = git__malloc(message_len + 1);
|
||||
memcpy(commit->message_short, message, message_len);
|
||||
commit->message_short[message_len] = 0;
|
||||
}
|
||||
|
||||
int git_commit_add_parent(git_commit *commit, git_commit *new_parent)
|
||||
{
|
||||
assert(commit && new_parent);
|
||||
|
||||
CHECK_FULL_PARSE();
|
||||
commit->object.modified = 1;
|
||||
GIT_OBJECT_INCREF(commit->object.repo, new_parent);
|
||||
return git_vector_insert(&commit->parents, new_parent);
|
||||
}
|
||||
|
11
src/commit.h
11
src/commit.h
@ -11,22 +11,17 @@
|
||||
struct git_commit {
|
||||
git_object object;
|
||||
|
||||
git_vector parents;
|
||||
git_vector parent_oids;
|
||||
git_oid tree_oid;
|
||||
|
||||
git_tree *tree;
|
||||
git_signature *author;
|
||||
git_signature *committer;
|
||||
|
||||
char *message;
|
||||
char *message_short;
|
||||
|
||||
unsigned full_parse:1;
|
||||
};
|
||||
|
||||
void git_commit__free(git_commit *c);
|
||||
int git_commit__parse(git_commit *commit);
|
||||
int git_commit__parse_full(git_commit *commit);
|
||||
|
||||
int git_commit__writeback(git_commit *commit, git_odb_source *src);
|
||||
int git_commit__parse(git_commit *commit, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
10
src/common.h
10
src/common.h
@ -11,9 +11,6 @@
|
||||
#include "git2/thread-utils.h"
|
||||
#include "cc-compat.h"
|
||||
|
||||
#ifdef GIT_HAS_PTHREAD
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
#ifdef GIT_HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
@ -34,16 +31,21 @@
|
||||
# include <windows.h>
|
||||
# include "msvc-compat.h"
|
||||
# include "mingw-compat.h"
|
||||
# ifdef GIT_THREADS
|
||||
# include "win32/pthread.h"
|
||||
#endif
|
||||
|
||||
# define snprintf _snprintf
|
||||
|
||||
typedef SSIZE_T ssize_t;
|
||||
|
||||
#else
|
||||
|
||||
# include <unistd.h>
|
||||
# include <arpa/inet.h>
|
||||
|
||||
# ifdef GIT_THREADS
|
||||
# include <pthread.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "git2/common.h"
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef INCLUDE_delta_apply_h__
|
||||
#define INCLUDE_delta_apply_h__
|
||||
|
||||
#include "odb.h"
|
||||
|
||||
/**
|
||||
* Apply a git binary delta to recover the original content.
|
||||
*
|
||||
|
@ -27,7 +27,9 @@ static struct {
|
||||
{GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},
|
||||
{GIT_EINVALIDPATH, "The path is invalid" },
|
||||
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
|
||||
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"}
|
||||
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
|
||||
{GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"},
|
||||
{GIT_EEXISTS, "A reference with this name already exists"}
|
||||
};
|
||||
|
||||
const char *git_strerror(int num)
|
||||
|
185
src/filebuf.c
185
src/filebuf.c
@ -77,44 +77,81 @@ void git_filebuf_cleanup(git_filebuf *file)
|
||||
if (file->fd >= 0)
|
||||
gitfo_close(file->fd);
|
||||
|
||||
if (gitfo_exists(file->path_lock) == GIT_SUCCESS)
|
||||
if (file->path_lock && gitfo_exists(file->path_lock) == GIT_SUCCESS)
|
||||
gitfo_unlink(file->path_lock);
|
||||
|
||||
if (file->digest)
|
||||
git_hash_free_ctx(file->digest);
|
||||
|
||||
free(file->buffer);
|
||||
free(file->z_buf);
|
||||
|
||||
#ifdef GIT_FILEBUF_THREADS
|
||||
free(file->buffer_back);
|
||||
#endif
|
||||
deflateEnd(&file->zs);
|
||||
|
||||
free(file->path_original);
|
||||
free(file->path_lock);
|
||||
}
|
||||
|
||||
static int flush_buffer(git_filebuf *file)
|
||||
GIT_INLINE(int) flush_buffer(git_filebuf *file)
|
||||
{
|
||||
int result = GIT_SUCCESS;
|
||||
int result = file->write(file, file->buffer, file->buf_pos);
|
||||
file->buf_pos = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (file->buf_pos > 0) {
|
||||
result = gitfo_write(file->fd, file->buffer, file->buf_pos);
|
||||
static int write_normal(git_filebuf *file, const void *source, size_t len)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (len > 0) {
|
||||
result = gitfo_write(file->fd, (void *)source, len);
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, file->buffer, file->buf_pos);
|
||||
|
||||
file->buf_pos = 0;
|
||||
git_hash_update(file->digest, source, len);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int write_deflate(git_filebuf *file, const void *source, size_t len)
|
||||
{
|
||||
int result = Z_OK;
|
||||
z_stream *zs = &file->zs;
|
||||
|
||||
if (len > 0 || file->flush_mode == Z_FINISH) {
|
||||
zs->next_in = (void *)source;
|
||||
zs->avail_in = len;
|
||||
|
||||
do {
|
||||
int have;
|
||||
|
||||
zs->next_out = file->z_buf;
|
||||
zs->avail_out = file->buf_size;
|
||||
|
||||
result = deflate(zs, file->flush_mode);
|
||||
assert(result != Z_STREAM_ERROR);
|
||||
|
||||
have = file->buf_size - zs->avail_out;
|
||||
|
||||
if (gitfo_write(file->fd, file->z_buf, have) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
|
||||
} while (zs->avail_out == 0);
|
||||
|
||||
assert(zs->avail_in == 0);
|
||||
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, source, len);
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
{
|
||||
int error;
|
||||
size_t path_len;
|
||||
|
||||
if (file == NULL || path == NULL)
|
||||
return GIT_ERROR;
|
||||
assert(file && path);
|
||||
|
||||
memset(file, 0x0, sizeof(git_filebuf));
|
||||
|
||||
@ -122,37 +159,14 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
file->buf_pos = 0;
|
||||
file->fd = -1;
|
||||
|
||||
path_len = strlen(path);
|
||||
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
|
||||
if (file->path_lock == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(file->path_lock, file->path_original, path_len);
|
||||
memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
|
||||
|
||||
/* Allocate the main cache buffer */
|
||||
file->buffer = git__malloc(file->buf_size);
|
||||
if (file->buffer == NULL){
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef GIT_FILEBUF_THREADS
|
||||
file->buffer_back = git__malloc(file->buf_size);
|
||||
if (file->buffer_back == NULL){
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we are hashing on-write, allocate a new hash context */
|
||||
if (flags & GIT_FILEBUF_HASH_CONTENTS) {
|
||||
if ((file->digest = git_hash_new_ctx()) == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
@ -160,8 +174,72 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = lock_file(file, flags)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
/* If we are deflating on-write, */
|
||||
if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) {
|
||||
|
||||
/* Initialize the ZLib stream */
|
||||
if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
||||
error = GIT_EZLIB;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate the Zlib cache buffer */
|
||||
file->z_buf = git__malloc(file->buf_size);
|
||||
if (file->z_buf == NULL){
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Never flush */
|
||||
file->flush_mode = Z_NO_FLUSH;
|
||||
file->write = &write_deflate;
|
||||
} else {
|
||||
file->write = &write_normal;
|
||||
}
|
||||
|
||||
/* If we are writing to a temp file */
|
||||
if (flags & GIT_FILEBUF_TEMPORARY) {
|
||||
char tmp_path[GIT_PATH_MAX];
|
||||
|
||||
/* Open the file as temporary for locking */
|
||||
file->fd = gitfo_mktemp(tmp_path, path);
|
||||
if (file->fd < 0) {
|
||||
error = GIT_EOSERR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* No original path */
|
||||
file->path_original = NULL;
|
||||
file->path_lock = git__strdup(tmp_path);
|
||||
|
||||
if (file->path_lock == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
path_len = strlen(path);
|
||||
|
||||
/* Save the original path of the file */
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* create the locking path by appending ".lock" to the original */
|
||||
file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
|
||||
if (file->path_lock == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(file->path_lock, file->path_original, path_len);
|
||||
memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
|
||||
|
||||
/* open the file for locking */
|
||||
if ((error = lock_file(file, flags)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
|
||||
@ -187,10 +265,25 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_filebuf_commit_at(git_filebuf *file, const char *path)
|
||||
{
|
||||
free(file->path_original);
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
return git_filebuf_commit(file);
|
||||
}
|
||||
|
||||
int git_filebuf_commit(git_filebuf *file)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* tmp file cannot be commited */
|
||||
if (file->path_original == NULL)
|
||||
return GIT_EOSERR;
|
||||
|
||||
file->flush_mode = Z_FINISH;
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
@ -204,16 +297,16 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
GIT_INLINE(void) add_to_cache(git_filebuf *file, void *buf, size_t len)
|
||||
GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len)
|
||||
{
|
||||
memcpy(file->buffer + file->buf_pos, buf, len);
|
||||
file->buf_pos += len;
|
||||
}
|
||||
|
||||
int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
|
||||
int git_filebuf_write(git_filebuf *file, const void *buff, size_t len)
|
||||
{
|
||||
int error;
|
||||
unsigned char *buf = buff;
|
||||
const unsigned char *buf = buff;
|
||||
|
||||
for (;;) {
|
||||
size_t space_left = file->buf_size - file->buf_pos;
|
||||
@ -237,9 +330,9 @@ int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
|
||||
|
||||
/* write too-large chunks immediately */
|
||||
if (len > file->buf_size) {
|
||||
error = gitfo_write(file->fd, buf, len);
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, buf, len);
|
||||
error = file->write(file, buf, len);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,17 @@
|
||||
|
||||
#include "fileops.h"
|
||||
#include "hash.h"
|
||||
#include "git2/zlib.h"
|
||||
|
||||
#ifdef GIT_THREADS
|
||||
# define GIT_FILEBUF_THREADS
|
||||
#endif
|
||||
|
||||
#define GIT_FILEBUF_HASH_CONTENTS 0x1
|
||||
#define GIT_FILEBUF_APPEND 0x2
|
||||
#define GIT_FILEBUF_FORCE 0x4
|
||||
#define GIT_FILEBUF_HASH_CONTENTS (1 << 0)
|
||||
#define GIT_FILEBUF_APPEND (1 << 2)
|
||||
#define GIT_FILEBUF_FORCE (1 << 3)
|
||||
#define GIT_FILEBUF_TEMPORARY (1 << 4)
|
||||
#define GIT_FILEBUF_DEFLATE_CONTENTS (1 << 5)
|
||||
|
||||
#define GIT_FILELOCK_EXTENSION ".lock\0"
|
||||
#define GIT_FILELOCK_EXTLENGTH 6
|
||||
@ -19,12 +22,16 @@ struct git_filebuf {
|
||||
char *path_original;
|
||||
char *path_lock;
|
||||
|
||||
int (*write)(struct git_filebuf *file,
|
||||
const void *source, size_t len);
|
||||
|
||||
git_hash_ctx *digest;
|
||||
|
||||
unsigned char *buffer;
|
||||
#ifdef GIT_FILEBUF_THREADS
|
||||
unsigned char *buffer_back;
|
||||
#endif
|
||||
unsigned char *z_buf;
|
||||
|
||||
z_stream zs;
|
||||
int flush_mode;
|
||||
|
||||
size_t buf_size, buf_pos;
|
||||
git_file fd;
|
||||
@ -32,12 +39,13 @@ struct git_filebuf {
|
||||
|
||||
typedef struct git_filebuf git_filebuf;
|
||||
|
||||
int git_filebuf_write(git_filebuf *lock, void *buff, size_t len);
|
||||
int git_filebuf_write(git_filebuf *lock, const void *buff, size_t len);
|
||||
int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);
|
||||
int git_filebuf_printf(git_filebuf *file, const char *format, ...);
|
||||
|
||||
int git_filebuf_open(git_filebuf *lock, const char *path, int flags);
|
||||
int git_filebuf_commit(git_filebuf *lock);
|
||||
int git_filebuf_commit_at(git_filebuf *lock, const char *path);
|
||||
void git_filebuf_cleanup(git_filebuf *lock);
|
||||
int git_filebuf_hash(git_oid *oid, git_filebuf *file);
|
||||
|
||||
|
131
src/fileops.c
131
src/fileops.c
@ -2,13 +2,13 @@
|
||||
#include "fileops.h"
|
||||
#include <ctype.h>
|
||||
|
||||
static int force_path(const char *to)
|
||||
int gitfo_mkdir_2file(const char *file_path)
|
||||
{
|
||||
const int mode = 0755; /* or 0777 ? */
|
||||
int error = GIT_SUCCESS;
|
||||
char target_folder_path[GIT_PATH_MAX];
|
||||
|
||||
error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to);
|
||||
error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -25,6 +25,27 @@ static int force_path(const char *to)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int gitfo_mktemp(char *path_out, const char *filename)
|
||||
{
|
||||
int fd;
|
||||
|
||||
strcpy(path_out, filename);
|
||||
strcat(path_out, "_git2_XXXXXX");
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* FIXME: there may be race conditions when multi-threading
|
||||
* with the library */
|
||||
if (_mktemp_s(path_out, GIT_PATH_MAX) != 0)
|
||||
return GIT_EOSERR;
|
||||
|
||||
fd = gitfo_creat(path_out, 0744);
|
||||
#else
|
||||
fd = mkstemp(path_out);
|
||||
#endif
|
||||
|
||||
return fd >= 0 ? fd : GIT_EOSERR;
|
||||
}
|
||||
|
||||
int gitfo_open(const char *path, int flags)
|
||||
{
|
||||
int fd = open(path, flags | O_BINARY);
|
||||
@ -39,7 +60,7 @@ int gitfo_creat(const char *path, int mode)
|
||||
|
||||
int gitfo_creat_force(const char *path, int mode)
|
||||
{
|
||||
if (force_path(path) < GIT_SUCCESS)
|
||||
if (gitfo_mkdir_2file(path) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
|
||||
return gitfo_creat(path, mode);
|
||||
@ -117,6 +138,7 @@ int gitfo_isdir(const char *path)
|
||||
|
||||
int gitfo_exists(const char *path)
|
||||
{
|
||||
assert(path);
|
||||
return access(path, F_OK);
|
||||
}
|
||||
|
||||
@ -181,7 +203,7 @@ int gitfo_mv(const char *from, const char *to)
|
||||
* file exists, the `rename` call fails. This is as
|
||||
* close as it gets with the Win32 API.
|
||||
*/
|
||||
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) ? GIT_SUCCESS : GIT_EOSERR;
|
||||
return 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)) {
|
||||
@ -198,7 +220,7 @@ int gitfo_mv(const char *from, const char *to)
|
||||
|
||||
int gitfo_mv_force(const char *from, const char *to)
|
||||
{
|
||||
if (force_path(to) < GIT_SUCCESS)
|
||||
if (gitfo_mkdir_2file(to) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
|
||||
return gitfo_mv(from, to);
|
||||
@ -361,22 +383,29 @@ int gitfo_dirent(
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int retrieve_path_root_offset(const char *path)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
|
||||
static int is_windows_rooted_path(const char *path)
|
||||
{
|
||||
/* Does the root of the path look like a windows drive ? */
|
||||
if (isalpha(path[0]) && (path[1] == ':'))
|
||||
return GIT_SUCCESS;
|
||||
offset += 2;
|
||||
|
||||
#endif
|
||||
|
||||
if (*(path + offset) == '/')
|
||||
return offset;
|
||||
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int gitfo_mkdir_recurs(const char *path, int mode)
|
||||
{
|
||||
int error;
|
||||
int error, root_path_offset;
|
||||
char *pp, *sp;
|
||||
char *path_copy = git__strdup(path);
|
||||
|
||||
@ -386,12 +415,9 @@ int gitfo_mkdir_recurs(const char *path, int mode)
|
||||
error = GIT_SUCCESS;
|
||||
pp = path_copy;
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
|
||||
if (!is_windows_rooted_path(pp))
|
||||
pp += 2; /* Skip the drive name (eg. C: or D:) */
|
||||
|
||||
#endif
|
||||
root_path_offset = retrieve_path_root_offset(pp);
|
||||
if (root_path_offset > 0)
|
||||
pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
|
||||
|
||||
while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != 0) {
|
||||
if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) {
|
||||
@ -417,8 +443,12 @@ int gitfo_mkdir_recurs(const char *path, int mode)
|
||||
|
||||
static int retrieve_previous_path_component_start(const char *path)
|
||||
{
|
||||
int offset, len, start = 0;
|
||||
|
||||
int offset, len, root_offset, start = 0;
|
||||
|
||||
root_offset = retrieve_path_root_offset(path);
|
||||
if (root_offset > -1)
|
||||
start += root_offset;
|
||||
|
||||
len = strlen(path);
|
||||
offset = len - 1;
|
||||
|
||||
@ -430,7 +460,7 @@ static int retrieve_previous_path_component_start(const char *path)
|
||||
if (path[offset] == '/')
|
||||
offset--;
|
||||
|
||||
if (offset < 0)
|
||||
if (offset < root_offset)
|
||||
return GIT_ERROR;
|
||||
|
||||
while (offset > start && path[offset-1] != '/') {
|
||||
@ -440,15 +470,25 @@ static int retrieve_previous_path_component_start(const char *path)
|
||||
return offset;
|
||||
}
|
||||
|
||||
int gitfo_prettify_dir_path(char *buffer_out, const char *path)
|
||||
int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
||||
{
|
||||
int len = 0, segment_len, only_dots;
|
||||
int len = 0, segment_len, only_dots, root_path_offset, error = GIT_SUCCESS;
|
||||
char *current;
|
||||
const char *buffer_out_start, *buffer_end;
|
||||
|
||||
buffer_out_start = buffer_out;
|
||||
current = (char *)path;
|
||||
buffer_end = path + strlen(path);
|
||||
buffer_out_start = buffer_out;
|
||||
|
||||
root_path_offset = retrieve_path_root_offset(path);
|
||||
if (root_path_offset < 0) {
|
||||
error = gitfo_getcwd(buffer_out, size);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
len = strlen(buffer_out);
|
||||
buffer_out += len;
|
||||
}
|
||||
|
||||
while (current < buffer_end) {
|
||||
/* Prevent multiple slashes from being added to the output */
|
||||
@ -461,7 +501,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
|
||||
segment_len = 0;
|
||||
|
||||
/* Copy path segment to the output */
|
||||
while (current < buffer_end && *current !='/')
|
||||
while (current < buffer_end && *current != '/')
|
||||
{
|
||||
only_dots &= (*current == '.');
|
||||
*buffer_out++ = *current++;
|
||||
@ -486,7 +526,9 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
|
||||
|
||||
*buffer_out ='\0';
|
||||
len = retrieve_previous_path_component_start(buffer_out_start);
|
||||
if (len < GIT_SUCCESS)
|
||||
|
||||
/* Are we escaping out of the root dir? */
|
||||
if (len < 0)
|
||||
return GIT_EINVALIDPATH;
|
||||
|
||||
buffer_out = (char *)buffer_out_start + len;
|
||||
@ -494,7 +536,7 @@ int gitfo_prettify_dir_path(char *buffer_out, 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)
|
||||
if (only_dots && segment_len > 0)
|
||||
return GIT_EINVALIDPATH;
|
||||
|
||||
*buffer_out++ = '/';
|
||||
@ -506,20 +548,24 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int gitfo_prettify_file_path(char *buffer_out, const char *path)
|
||||
int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path)
|
||||
{
|
||||
int error, path_len, i;
|
||||
const char* pattern = "/..";
|
||||
|
||||
path_len = strlen(path);
|
||||
|
||||
/* Let's make sure the filename isn't empty nor a dot */
|
||||
if (path_len == 0 || (path_len == 1 && *path == '.'))
|
||||
return GIT_EINVALIDPATH;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
error = gitfo_prettify_dir_path(buffer_out, path);
|
||||
error = gitfo_prettify_dir_path(buffer_out, size, path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -551,3 +597,34 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void posixify_path(char *path)
|
||||
{
|
||||
while (*path) {
|
||||
if (*path == '\\')
|
||||
*path = '/';
|
||||
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
int gitfo_getcwd(char *buffer_out, size_t size)
|
||||
{
|
||||
char *cwd_buffer;
|
||||
|
||||
assert(buffer_out && size > 0);
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
if (cwd_buffer == NULL)
|
||||
return GIT_EOSERR;
|
||||
|
||||
posixify_path(buffer_out);
|
||||
|
||||
git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
@ -58,8 +58,10 @@ extern int gitfo_exists(const char *path);
|
||||
extern int gitfo_open(const char *path, int flags);
|
||||
extern int gitfo_creat(const char *path, int mode);
|
||||
extern int gitfo_creat_force(const char *path, int mode);
|
||||
extern int gitfo_mktemp(char *path_out, const char *filename);
|
||||
extern int gitfo_isdir(const char *path);
|
||||
extern int gitfo_mkdir_recurs(const char *path, int mode);
|
||||
extern int gitfo_mkdir_2file(const char *path);
|
||||
#define gitfo_close(fd) close(fd)
|
||||
|
||||
extern int gitfo_read(git_file fd, void *buf, size_t cnt);
|
||||
@ -142,6 +144,8 @@ extern int gitfo_close_cached(gitfo_cache *ioc);
|
||||
extern int gitfo_cmp_path(const char *name1, int len1, int isdir1,
|
||||
const char *name2, int len2, int isdir2);
|
||||
|
||||
extern int gitfo_getcwd(char *buffer_out, size_t size);
|
||||
|
||||
/**
|
||||
* Clean up a provided absolute or relative directory path.
|
||||
*
|
||||
@ -159,12 +163,13 @@ extern int gitfo_cmp_path(const char *name1, int len1, int isdir1,
|
||||
* the file system perspective.
|
||||
*
|
||||
* @param buffer_out buffer to populate with the normalized path.
|
||||
* @param size buffer size.
|
||||
* @param path directory path to clean up.
|
||||
* @return
|
||||
* - GIT_SUCCESS on success;
|
||||
* - GIT_ERROR when the input path is invalid or escapes the current directory.
|
||||
*/
|
||||
GIT_EXTERN(int) gitfo_prettify_dir_path(char *buffer_out, const char *path);
|
||||
int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path);
|
||||
|
||||
/**
|
||||
* Clean up a provided absolute or relative file path.
|
||||
@ -181,11 +186,13 @@ GIT_EXTERN(int) gitfo_prettify_dir_path(char *buffer_out, const char *path);
|
||||
* the file system perspective.
|
||||
*
|
||||
* @param buffer_out buffer to populate with the normalized path.
|
||||
* @param size buffer size.
|
||||
* @param path file path to clean up.
|
||||
* @return
|
||||
* - GIT_SUCCESS on success;
|
||||
* - GIT_ERROR when the input path is invalid or escapes the current directory.
|
||||
*/
|
||||
GIT_EXTERN(int) gitfo_prettify_file_path(char *buffer_out, const char *path);
|
||||
int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path);
|
||||
|
||||
int retrieve_path_root_offset(const char *path);
|
||||
#endif /* INCLUDE_fileops_h__ */
|
||||
|
@ -184,6 +184,8 @@ int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, voi
|
||||
int hash_id;
|
||||
git_hashtable_node *node;
|
||||
|
||||
assert(self && self->nodes);
|
||||
|
||||
*old_value = NULL;
|
||||
|
||||
for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {
|
||||
@ -218,6 +220,8 @@ void *git_hashtable_lookup(git_hashtable *self, const void *key)
|
||||
int hash_id;
|
||||
git_hashtable_node *node;
|
||||
|
||||
assert(self && self->nodes);
|
||||
|
||||
for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {
|
||||
node = node_with_hash(self, key, hash_id);
|
||||
if (node->key && self->key_equal(key, node->key) == 0)
|
||||
@ -232,6 +236,8 @@ int git_hashtable_remove(git_hashtable *self, const void *key)
|
||||
int hash_id;
|
||||
git_hashtable_node *node;
|
||||
|
||||
assert(self && self->nodes);
|
||||
|
||||
for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {
|
||||
node = node_with_hash(self, key, hash_id);
|
||||
if (node->key && self->key_equal(key, node->key) == 0) {
|
||||
|
20
src/index.c
20
src/index.c
@ -74,7 +74,7 @@ struct entry_short {
|
||||
uint32_t file_size;
|
||||
git_oid oid;
|
||||
uint16_t flags;
|
||||
char path[1]; /* arbritrary length */
|
||||
char path[1]; /* arbitrary length */
|
||||
};
|
||||
|
||||
struct entry_long {
|
||||
@ -89,7 +89,7 @@ struct entry_long {
|
||||
git_oid oid;
|
||||
uint16_t flags;
|
||||
uint16_t flags_extended;
|
||||
char path[1]; /* arbritrary length */
|
||||
char path[1]; /* arbitrary length */
|
||||
};
|
||||
|
||||
/* local declarations */
|
||||
@ -148,7 +148,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const
|
||||
index->on_disk = 1;
|
||||
|
||||
*index_out = index;
|
||||
return GIT_SUCCESS;
|
||||
return git_index_read(index);
|
||||
}
|
||||
|
||||
int git_index_open_bare(git_index **index_out, const char *index_path)
|
||||
@ -312,8 +312,8 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
|
||||
|
||||
memset(&entry, 0x0, sizeof(git_index_entry));
|
||||
|
||||
entry.ctime.seconds = st.st_ctime;
|
||||
entry.mtime.seconds = st.st_mtime;
|
||||
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;
|
||||
@ -324,7 +324,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
|
||||
entry.file_size = st.st_size;
|
||||
|
||||
/* write the blob to disk and get the oid */
|
||||
if ((error = git_blob_writefile(&entry.oid, index->repository, full_path)) < GIT_SUCCESS)
|
||||
if ((error = git_blob_create_fromfile(&entry.oid, index->repository, rel_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
|
||||
@ -491,10 +491,10 @@ static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffe
|
||||
|
||||
source = (const struct entry_short *)(buffer);
|
||||
|
||||
dest->ctime.seconds = (time_t)ntohl(source->ctime.seconds);
|
||||
dest->ctime.nanoseconds = (time_t)ntohl(source->ctime.nanoseconds);
|
||||
dest->mtime.seconds = (time_t)ntohl(source->mtime.seconds);
|
||||
dest->mtime.nanoseconds = (time_t)ntohl(source->mtime.nanoseconds);
|
||||
dest->ctime.seconds = (git_time_t)ntohl(source->ctime.seconds);
|
||||
dest->ctime.nanoseconds = ntohl(source->ctime.nanoseconds);
|
||||
dest->mtime.seconds = (git_time_t)ntohl(source->mtime.seconds);
|
||||
dest->mtime.nanoseconds = ntohl(source->mtime.nanoseconds);
|
||||
dest->dev = ntohl(source->dev);
|
||||
dest->ino = ntohl(source->ino);
|
||||
dest->mode = ntohl(source->mode);
|
||||
|
281
src/object.c
281
src/object.c
@ -66,153 +66,6 @@ static struct {
|
||||
{ "REF_DELTA", 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Object source methods
|
||||
*
|
||||
* Abstract buffer methods that allow the writeback system
|
||||
* to prepare the contents of any git file in-memory before
|
||||
* writing them to disk.
|
||||
*/
|
||||
static int source_resize(git_odb_source *src)
|
||||
{
|
||||
size_t write_offset, new_size;
|
||||
void *new_data;
|
||||
|
||||
write_offset = (size_t)((char *)src->write_ptr - (char *)src->raw.data);
|
||||
|
||||
new_size = src->raw.len * 2;
|
||||
if ((new_data = git__malloc(new_size)) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memcpy(new_data, src->raw.data, src->written_bytes);
|
||||
free(src->raw.data);
|
||||
|
||||
src->raw.data = new_data;
|
||||
src->raw.len = new_size;
|
||||
src->write_ptr = (char *)new_data + write_offset;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__source_printf(git_odb_source *source, const char *format, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
int len;
|
||||
|
||||
assert(source->open && source->write_ptr);
|
||||
|
||||
va_start(arglist, format);
|
||||
|
||||
len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
|
||||
|
||||
while (source->written_bytes + len >= source->raw.len) {
|
||||
if (source_resize(source) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
|
||||
}
|
||||
|
||||
source->write_ptr = (char *)source->write_ptr + len;
|
||||
source->written_bytes += len;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__source_write(git_odb_source *source, const void *bytes, size_t len)
|
||||
{
|
||||
assert(source);
|
||||
|
||||
assert(source->open && source->write_ptr);
|
||||
|
||||
while (source->written_bytes + len >= source->raw.len) {
|
||||
if (source_resize(source) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(source->write_ptr, bytes, len);
|
||||
source->write_ptr = (char *)source->write_ptr + len;
|
||||
source->written_bytes += len;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void prepare_write(git_object *object)
|
||||
{
|
||||
if (object->source.write_ptr != NULL || object->source.open)
|
||||
git_object__source_close(object);
|
||||
|
||||
/* TODO: proper size calculation */
|
||||
object->source.raw.data = git__malloc(OBJECT_BASE_SIZE);
|
||||
object->source.raw.len = OBJECT_BASE_SIZE;
|
||||
|
||||
object->source.write_ptr = object->source.raw.data;
|
||||
object->source.written_bytes = 0;
|
||||
|
||||
object->source.open = 1;
|
||||
}
|
||||
|
||||
static int write_back(git_object *object)
|
||||
{
|
||||
int error;
|
||||
git_oid new_id;
|
||||
|
||||
assert(object);
|
||||
|
||||
assert(object->source.open);
|
||||
assert(object->modified);
|
||||
|
||||
object->source.raw.len = object->source.written_bytes;
|
||||
|
||||
if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (object->in_memory) {
|
||||
int idx = git_vector_search(&object->repo->memory_objects, object);
|
||||
git_vector_remove(&object->repo->memory_objects, idx);
|
||||
} else {
|
||||
git_hashtable_remove(object->repo->objects, &object->id);
|
||||
}
|
||||
|
||||
git_oid_cpy(&object->id, &new_id);
|
||||
git_hashtable_insert(object->repo->objects, &object->id, object);
|
||||
|
||||
object->source.write_ptr = NULL;
|
||||
object->source.written_bytes = 0;
|
||||
|
||||
object->modified = 0;
|
||||
object->in_memory = 0;
|
||||
|
||||
git_object__source_close(object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_object__source_open(git_object *object)
|
||||
{
|
||||
int error;
|
||||
|
||||
assert(object && !object->in_memory);
|
||||
|
||||
if (object->source.open)
|
||||
git_object__source_close(object);
|
||||
|
||||
error = git_odb_read(&object->source.raw, object->repo->db, &object->id);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
object->source.open = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_object__source_close(git_object *object)
|
||||
{
|
||||
assert(object);
|
||||
|
||||
if (object->source.open) {
|
||||
git_rawobj_close(&object->source.raw);
|
||||
object->source.open = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int create_object(git_object **object_out, git_otype type)
|
||||
{
|
||||
git_object *object = NULL;
|
||||
@ -225,43 +78,19 @@ static int create_object(git_object **object_out, git_otype type)
|
||||
case GIT_OBJ_COMMIT:
|
||||
case GIT_OBJ_TAG:
|
||||
case GIT_OBJ_BLOB:
|
||||
case GIT_OBJ_TREE:
|
||||
object = git__malloc(git_object__size(type));
|
||||
if (object == NULL)
|
||||
return GIT_ENOMEM;
|
||||
memset(object, 0x0, git_object__size(type));
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TREE:
|
||||
object = (git_object *)git_tree__new();
|
||||
if (object == NULL)
|
||||
return GIT_ENOMEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
|
||||
*object_out = object;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
object->type = type;
|
||||
|
||||
int git_object_new(git_object **object_out, git_repository *repo, git_otype type)
|
||||
{
|
||||
git_object *object = NULL;
|
||||
int error;
|
||||
|
||||
assert(object_out && repo);
|
||||
|
||||
if ((error = create_object(&object, type)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
object->repo = repo;
|
||||
object->in_memory = 1;
|
||||
object->modified = 1;
|
||||
|
||||
object->source.raw.type = type;
|
||||
|
||||
object->refcount++;
|
||||
*object_out = object;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
@ -269,122 +98,77 @@ int git_object_new(git_object **object_out, git_repository *repo, git_otype type
|
||||
int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type)
|
||||
{
|
||||
git_object *object = NULL;
|
||||
git_rawobj obj_file;
|
||||
git_odb_object *odb_obj;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
assert(repo && object_out && id);
|
||||
|
||||
object = git_hashtable_lookup(repo->objects, id);
|
||||
object = git_cache_get(&repo->objects, id);
|
||||
if (object != NULL) {
|
||||
if (type != GIT_OBJ_ANY && type != object->type)
|
||||
return GIT_EINVALIDTYPE;
|
||||
|
||||
*object_out = object;
|
||||
GIT_OBJECT_INCREF(repo, object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
error = git_odb_read(&obj_file, repo->db, id);
|
||||
error = git_odb_read(&odb_obj, repo->db, id);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (type != GIT_OBJ_ANY && type != obj_file.type) {
|
||||
git_rawobj_close(&obj_file);
|
||||
if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
|
||||
git_odb_object_close(odb_obj);
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
|
||||
type = obj_file.type;
|
||||
type = odb_obj->raw.type;
|
||||
|
||||
if ((error = create_object(&object, type)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Initialize parent object */
|
||||
git_oid_cpy(&object->id, id);
|
||||
git_oid_cpy(&object->cached.oid, id);
|
||||
object->repo = repo;
|
||||
memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj));
|
||||
object->source.open = 1;
|
||||
|
||||
switch (type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
error = git_commit__parse((git_commit *)object);
|
||||
error = git_commit__parse((git_commit *)object, odb_obj);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TREE:
|
||||
error = git_tree__parse((git_tree *)object);
|
||||
error = git_tree__parse((git_tree *)object, odb_obj);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TAG:
|
||||
error = git_tag__parse((git_tag *)object);
|
||||
error = git_tag__parse((git_tag *)object, odb_obj);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_BLOB:
|
||||
error = git_blob__parse((git_blob *)object);
|
||||
error = git_blob__parse((git_blob *)object, odb_obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
git_odb_object_close(odb_obj);
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_object__free(object);
|
||||
return error;
|
||||
}
|
||||
|
||||
git_object__source_close(object);
|
||||
git_hashtable_insert(repo->objects, &object->id, object);
|
||||
|
||||
GIT_OBJECT_INCREF(repo, object);
|
||||
*object_out = object;
|
||||
*object_out = git_cache_try_store(&repo->objects, object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_object_write(git_object *object)
|
||||
void git_object__free(void *_obj)
|
||||
{
|
||||
int error;
|
||||
git_odb_source *source;
|
||||
git_object *object = (git_object *)_obj;
|
||||
|
||||
assert(object);
|
||||
|
||||
if (object->modified == 0)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
prepare_write(object);
|
||||
source = &object->source;
|
||||
|
||||
switch (source->raw.type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
error = git_commit__writeback((git_commit *)object, source);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TREE:
|
||||
error = git_tree__writeback((git_tree *)object, source);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TAG:
|
||||
error = git_tag__writeback((git_tag *)object, source);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_BLOB:
|
||||
error = git_blob__writeback((git_blob *)object, source);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = GIT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_object__source_close(object);
|
||||
return error;
|
||||
}
|
||||
|
||||
return write_back(object);
|
||||
}
|
||||
|
||||
void git_object__free(git_object *object)
|
||||
{
|
||||
assert(object);
|
||||
|
||||
git_object__source_close(object);
|
||||
|
||||
switch (object->source.raw.type) {
|
||||
switch (object->type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
git_commit__free((git_commit *)object);
|
||||
break;
|
||||
@ -412,34 +196,19 @@ void git_object_close(git_object *object)
|
||||
if (object == NULL)
|
||||
return;
|
||||
|
||||
if (--object->refcount <= 0) {
|
||||
if (object->repo != NULL) {
|
||||
if (object->in_memory) {
|
||||
int idx = git_vector_search(&object->repo->memory_objects, object);
|
||||
git_vector_remove(&object->repo->memory_objects, idx);
|
||||
} else {
|
||||
git_hashtable_remove(object->repo->objects, &object->id);
|
||||
}
|
||||
}
|
||||
|
||||
git_object__free(object);
|
||||
}
|
||||
git_cached_obj_decref((git_cached_obj *)object, git_object__free);
|
||||
}
|
||||
|
||||
const git_oid *git_object_id(const git_object *obj)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
if (obj->in_memory)
|
||||
return NULL;
|
||||
|
||||
return &obj->id;
|
||||
return &obj->cached.oid;
|
||||
}
|
||||
|
||||
git_otype git_object_type(const git_object *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return obj->source.raw.type;
|
||||
return obj->type;
|
||||
}
|
||||
|
||||
git_repository *git_object_owner(const git_object *obj)
|
||||
|
196
src/odb.c
196
src/odb.c
@ -87,55 +87,68 @@ int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *ob
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_rawobj_close(git_rawobj *obj)
|
||||
|
||||
static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source)
|
||||
{
|
||||
free(obj->data);
|
||||
obj->data = NULL;
|
||||
git_odb_object *object = git__malloc(sizeof(git_odb_object));
|
||||
memset(object, 0x0, sizeof(git_odb_object));
|
||||
|
||||
git_oid_cpy(&object->cached.oid, oid);
|
||||
memcpy(&object->raw, source, sizeof(git_rawobj));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
int git_rawobj_hash(git_oid *id, git_rawobj *obj)
|
||||
static void free_odb_object(void *o)
|
||||
{
|
||||
git_odb_object *object = (git_odb_object *)o;
|
||||
|
||||
if (object != NULL) {
|
||||
free(object->raw.data);
|
||||
free(object);
|
||||
}
|
||||
}
|
||||
|
||||
const git_oid *git_odb_object_id(git_odb_object *object)
|
||||
{
|
||||
return &object->cached.oid;
|
||||
}
|
||||
|
||||
const void *git_odb_object_data(git_odb_object *object)
|
||||
{
|
||||
return object->raw.data;
|
||||
}
|
||||
|
||||
size_t git_odb_object_size(git_odb_object *object)
|
||||
{
|
||||
return object->raw.len;
|
||||
}
|
||||
|
||||
git_otype git_odb_object_type(git_odb_object *object)
|
||||
{
|
||||
return object->raw.type;
|
||||
}
|
||||
|
||||
void git_odb_object_close(git_odb_object *object)
|
||||
{
|
||||
git_cached_obj_decref((git_cached_obj *)object, &free_odb_object);
|
||||
}
|
||||
|
||||
int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type)
|
||||
{
|
||||
char hdr[64];
|
||||
int hdrlen;
|
||||
git_rawobj raw;
|
||||
|
||||
assert(id && obj);
|
||||
assert(id);
|
||||
|
||||
return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj);
|
||||
raw.data = (void *)data;
|
||||
raw.len = len;
|
||||
raw.type = type;
|
||||
|
||||
return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, &raw);
|
||||
}
|
||||
|
||||
int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
|
||||
{
|
||||
z_stream zs;
|
||||
int status = Z_OK;
|
||||
|
||||
memset(&zs, 0x0, sizeof(zs));
|
||||
|
||||
zs.next_out = out;
|
||||
zs.avail_out = outlen;
|
||||
|
||||
zs.next_in = in;
|
||||
zs.avail_in = inlen;
|
||||
|
||||
if (inflateInit(&zs) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
while (status == Z_OK)
|
||||
status = inflate(&zs, Z_FINISH);
|
||||
|
||||
inflateEnd(&zs);
|
||||
|
||||
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
|
||||
return GIT_ERROR;
|
||||
|
||||
if (zs.total_out != outlen)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
*
|
||||
@ -162,6 +175,8 @@ int git_odb_new(git_odb **out)
|
||||
if (!db)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
|
||||
|
||||
if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
|
||||
free(db);
|
||||
return GIT_ENOMEM;
|
||||
@ -306,16 +321,23 @@ void git_odb_close(git_odb *db)
|
||||
}
|
||||
|
||||
git_vector_free(&db->backends);
|
||||
git_cache_free(&db->cache);
|
||||
free(db);
|
||||
}
|
||||
|
||||
int git_odb_exists(git_odb *db, const git_oid *id)
|
||||
{
|
||||
git_odb_object *object;
|
||||
unsigned int i;
|
||||
int found = 0;
|
||||
|
||||
assert(db && id);
|
||||
|
||||
if ((object = git_cache_get(&db->cache, id)) != NULL) {
|
||||
git_odb_object_close(object);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < db->backends.length && !found; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
@ -327,19 +349,27 @@ int git_odb_exists(git_odb *db, const git_oid *id)
|
||||
return found;
|
||||
}
|
||||
|
||||
int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
|
||||
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ENOTFOUND;
|
||||
git_odb_object *object;
|
||||
|
||||
assert(out && db && id);
|
||||
assert(db && id);
|
||||
|
||||
if ((object = git_cache_get(&db->cache, id)) != NULL) {
|
||||
*len_p = object->raw.len;
|
||||
*type_p = object->raw.type;
|
||||
git_odb_object_close(object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
if (b->read_header != NULL)
|
||||
error = b->read_header(out, b, id);
|
||||
error = b->read_header(len_p, type_p, b, id);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -347,37 +377,50 @@ int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
|
||||
* try reading the whole object and freeing the contents
|
||||
*/
|
||||
if (error < 0) {
|
||||
error = git_odb_read(out, db, id);
|
||||
git_rawobj_close(out);
|
||||
if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*len_p = object->raw.len;
|
||||
*type_p = object->raw.len;
|
||||
git_odb_object_close(object);
|
||||
}
|
||||
|
||||
return error;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id)
|
||||
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ENOTFOUND;
|
||||
git_rawobj raw;
|
||||
|
||||
assert(out && db && id);
|
||||
|
||||
*out = git_cache_get(&db->cache, id);
|
||||
if (*out != NULL)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
if (b->read != NULL)
|
||||
error = b->read(out, b, id);
|
||||
error = b->read(&raw.data, &raw.len, &raw.type, b, id);
|
||||
}
|
||||
|
||||
if (error == GIT_SUCCESS) {
|
||||
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
|
||||
int git_odb_write(git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
assert(obj && db && id);
|
||||
assert(oid && db);
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
@ -388,7 +431,60 @@ int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
|
||||
continue;
|
||||
|
||||
if (b->write != NULL)
|
||||
error = b->write(id, b, obj);
|
||||
error = b->write(oid, b, data, len, type);
|
||||
}
|
||||
|
||||
/* if no backends were able to write the object directly, we try a streaming
|
||||
* write to the backends; just write the whole object into the stream in one
|
||||
* push */
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_odb_stream *stream;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, db, len, type)) == GIT_SUCCESS) {
|
||||
stream->write(stream, data, len);
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_otype type)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
assert(stream && db);
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
/* we don't write in alternates! */
|
||||
if (internal->is_alternate)
|
||||
continue;
|
||||
|
||||
if (b->writestream != NULL)
|
||||
error = b->writestream(stream, b, size, type);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
assert(stream && db);
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
if (b->readstream != NULL)
|
||||
error = b->readstream(stream, b, oid);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
18
src/odb.h
18
src/odb.h
@ -3,15 +3,31 @@
|
||||
|
||||
#include "git2/odb.h"
|
||||
#include "git2/oid.h"
|
||||
#include "git2/types.h"
|
||||
|
||||
#include "vector.h"
|
||||
#include "cache.h"
|
||||
|
||||
/* DO NOT EXPORT */
|
||||
typedef struct {
|
||||
void *data; /**< Raw, decompressed object data. */
|
||||
size_t len; /**< Total number of bytes in data. */
|
||||
git_otype type; /**< Type of this object. */
|
||||
} git_rawobj;
|
||||
|
||||
/* EXPORT */
|
||||
struct git_odb_object {
|
||||
git_cached_obj cached;
|
||||
git_rawobj raw;
|
||||
};
|
||||
|
||||
/* EXPORT */
|
||||
struct git_odb {
|
||||
void *_internal;
|
||||
git_vector backends;
|
||||
git_cache cache;
|
||||
};
|
||||
|
||||
int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *obj);
|
||||
int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen);
|
||||
|
||||
#endif
|
||||
|
300
src/odb_loose.c
300
src/odb_loose.c
@ -30,14 +30,22 @@
|
||||
#include "hash.h"
|
||||
#include "odb.h"
|
||||
#include "delta-apply.h"
|
||||
#include "filebuf.h"
|
||||
|
||||
#include "git2/odb_backend.h"
|
||||
#include "git2/types.h"
|
||||
|
||||
typedef struct { /* object header data */
|
||||
git_otype type; /* object type */
|
||||
size_t size; /* object size */
|
||||
} obj_hdr;
|
||||
|
||||
typedef struct {
|
||||
git_odb_stream stream;
|
||||
git_filebuf fbuf;
|
||||
int finished;
|
||||
} loose_writestream;
|
||||
|
||||
typedef struct loose_backend {
|
||||
git_odb_backend parent;
|
||||
|
||||
@ -53,38 +61,6 @@ typedef struct loose_backend {
|
||||
*
|
||||
***********************************************************/
|
||||
|
||||
static int make_temp_file(git_file *fd, char *tmp, size_t n, char *file)
|
||||
{
|
||||
char *template = "/tmp_obj_XXXXXX";
|
||||
size_t tmplen = strlen(template);
|
||||
int dirlen;
|
||||
|
||||
if ((dirlen = git__dirname_r(tmp, n, file)) < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
if ((dirlen + tmplen) >= n)
|
||||
return GIT_ERROR;
|
||||
|
||||
strcpy(tmp + dirlen, (dirlen) ? template : template + 1);
|
||||
|
||||
*fd = gitfo_mkstemp(tmp);
|
||||
if (*fd < 0 && dirlen) {
|
||||
/* create directory if it doesn't exist */
|
||||
tmp[dirlen] = '\0';
|
||||
if ((gitfo_exists(tmp) < 0) && gitfo_mkdir(tmp, 0755))
|
||||
return GIT_ERROR;
|
||||
/* try again */
|
||||
strcpy(tmp + dirlen, template);
|
||||
*fd = gitfo_mkstemp(tmp);
|
||||
}
|
||||
if (*fd < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
|
||||
{
|
||||
size_t len = strlen(dir);
|
||||
@ -236,64 +212,6 @@ static int finish_inflate(z_stream *s)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int deflate_buf(z_stream *s, void *in, size_t len, int flush)
|
||||
{
|
||||
int status = Z_OK;
|
||||
|
||||
set_stream_input(s, in, len);
|
||||
while (status == Z_OK) {
|
||||
status = deflate(s, flush);
|
||||
if (s->avail_in == 0)
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int deflate_obj(gitfo_buf *buf, char *hdr, int hdrlen, git_rawobj *obj, int level)
|
||||
{
|
||||
z_stream zs;
|
||||
int status;
|
||||
size_t size;
|
||||
|
||||
assert(buf && !buf->data && hdr && obj);
|
||||
assert(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));
|
||||
|
||||
buf->data = NULL;
|
||||
buf->len = 0;
|
||||
init_stream(&zs, NULL, 0);
|
||||
|
||||
if (deflateInit(&zs, level) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
size = deflateBound(&zs, hdrlen + obj->len);
|
||||
|
||||
if ((buf->data = git__malloc(size)) == NULL) {
|
||||
deflateEnd(&zs);
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
set_stream_output(&zs, buf->data, size);
|
||||
|
||||
/* compress the header */
|
||||
status = deflate_buf(&zs, hdr, hdrlen, Z_NO_FLUSH);
|
||||
|
||||
/* if header compressed OK, compress the object */
|
||||
if (status == Z_OK)
|
||||
status = deflate_buf(&zs, obj->data, obj->len, Z_FINISH);
|
||||
|
||||
if (status != Z_STREAM_END) {
|
||||
deflateEnd(&zs);
|
||||
free(buf->data);
|
||||
buf->data = NULL;
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
buf->len = zs.total_out;
|
||||
deflateEnd(&zs);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int is_zlib_compressed_data(unsigned char *data)
|
||||
{
|
||||
unsigned int w;
|
||||
@ -302,6 +220,36 @@ static int is_zlib_compressed_data(unsigned char *data)
|
||||
return data[0] == 0x78 && !(w % 31);
|
||||
}
|
||||
|
||||
static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
|
||||
{
|
||||
z_stream zs;
|
||||
int status = Z_OK;
|
||||
|
||||
memset(&zs, 0x0, sizeof(zs));
|
||||
|
||||
zs.next_out = out;
|
||||
zs.avail_out = outlen;
|
||||
|
||||
zs.next_in = in;
|
||||
zs.avail_in = inlen;
|
||||
|
||||
if (inflateInit(&zs) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
while (status == Z_OK)
|
||||
status = inflate(&zs, Z_FINISH);
|
||||
|
||||
inflateEnd(&zs);
|
||||
|
||||
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
|
||||
return GIT_ERROR;
|
||||
|
||||
if (zs.total_out != outlen)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
|
||||
{
|
||||
unsigned char *buf, *head = hb;
|
||||
@ -371,7 +319,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, gitfo_buf *obj)
|
||||
|
||||
in = ((unsigned char *)obj->data) + used;
|
||||
len = obj->len - used;
|
||||
if (git_odb__inflate_buffer(in, len, buf, hdr.size)) {
|
||||
if (inflate_buffer(in, len, buf, hdr.size)) {
|
||||
free(buf);
|
||||
return GIT_ERROR;
|
||||
}
|
||||
@ -505,37 +453,6 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int write_obj(gitfo_buf *buf, git_oid *id, loose_backend *backend)
|
||||
{
|
||||
char file[GIT_PATH_MAX];
|
||||
char temp[GIT_PATH_MAX];
|
||||
git_file fd;
|
||||
|
||||
if (object_file_name(file, sizeof(file), backend->objects_dir, id))
|
||||
return GIT_EOSERR;
|
||||
|
||||
if (make_temp_file(&fd, temp, sizeof(temp), file) < 0)
|
||||
return GIT_EOSERR;
|
||||
|
||||
if (gitfo_write(fd, buf->data, buf->len) < 0) {
|
||||
gitfo_close(fd);
|
||||
gitfo_unlink(temp);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
if (backend->fsync_object_files)
|
||||
gitfo_fsync(fd);
|
||||
gitfo_close(fd);
|
||||
gitfo_chmod(temp, 0444);
|
||||
|
||||
if (gitfo_mv(temp, file) < 0) {
|
||||
gitfo_unlink(temp);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)
|
||||
{
|
||||
object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);
|
||||
@ -558,29 +475,44 @@ static int locate_object(char *object_location, loose_backend *backend, const gi
|
||||
*
|
||||
***********************************************************/
|
||||
|
||||
int loose_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
|
||||
int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
|
||||
{
|
||||
char object_path[GIT_PATH_MAX];
|
||||
git_rawobj raw;
|
||||
int error;
|
||||
|
||||
assert(obj && backend && oid);
|
||||
assert(backend && oid);
|
||||
|
||||
if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return read_header_loose(obj, object_path);
|
||||
if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*len_p = raw.len;
|
||||
*type_p = raw.type;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int loose_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
|
||||
int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
|
||||
{
|
||||
char object_path[GIT_PATH_MAX];
|
||||
git_rawobj raw;
|
||||
int error;
|
||||
|
||||
assert(obj && backend && oid);
|
||||
assert(backend && oid);
|
||||
|
||||
if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return read_loose(obj, object_path);
|
||||
if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*buffer_p = raw.data;
|
||||
*len_p = raw.len;
|
||||
*type_p = raw.type;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
|
||||
@ -592,32 +524,106 @@ int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
|
||||
return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int loose_backend__write(git_oid *id, git_odb_backend *_backend, git_rawobj *obj)
|
||||
int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
|
||||
{
|
||||
char hdr[64];
|
||||
int hdrlen;
|
||||
gitfo_buf buf = GITFO_BUF_INIT;
|
||||
int error;
|
||||
loose_backend *backend;
|
||||
loose_writestream *stream = (loose_writestream *)_stream;
|
||||
loose_backend *backend = (loose_backend *)_stream->backend;
|
||||
|
||||
assert(id && _backend && obj);
|
||||
int error;
|
||||
char final_path[GIT_PATH_MAX];
|
||||
|
||||
if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
|
||||
return GIT_ENOMEM;
|
||||
|
||||
if ((error = gitfo_mkdir_2file(final_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
stream->finished = 1;
|
||||
return git_filebuf_commit_at(&stream->fbuf, final_path);
|
||||
}
|
||||
|
||||
int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
|
||||
{
|
||||
loose_writestream *stream = (loose_writestream *)_stream;
|
||||
return git_filebuf_write(&stream->fbuf, data, len);
|
||||
}
|
||||
|
||||
void loose_backend__stream_free(git_odb_stream *_stream)
|
||||
{
|
||||
loose_writestream *stream = (loose_writestream *)_stream;
|
||||
|
||||
if (!stream->finished)
|
||||
git_filebuf_cleanup(&stream->fbuf);
|
||||
|
||||
free(stream);
|
||||
}
|
||||
|
||||
static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
|
||||
{
|
||||
const char *type_str = git_object_type2string(obj_type);
|
||||
int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
|
||||
|
||||
assert(len > 0); /* otherwise snprintf() is broken */
|
||||
assert(((size_t) len) < n); /* otherwise the caller is broken! */
|
||||
|
||||
if (len < 0 || ((size_t) len) >= n)
|
||||
return GIT_ERROR;
|
||||
return len+1;
|
||||
}
|
||||
|
||||
int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
|
||||
{
|
||||
loose_backend *backend;
|
||||
loose_writestream *stream;
|
||||
|
||||
char hdr[64], tmp_path[GIT_PATH_MAX];
|
||||
int hdrlen;
|
||||
int error;
|
||||
|
||||
assert(_backend);
|
||||
|
||||
backend = (loose_backend *)_backend;
|
||||
*stream_out = NULL;
|
||||
|
||||
if ((error = git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj)) < 0)
|
||||
hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
|
||||
if (hdrlen < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
stream = git__calloc(1, sizeof(loose_writestream));
|
||||
if (stream == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
stream->stream.backend = _backend;
|
||||
stream->stream.read = NULL; /* read only */
|
||||
stream->stream.write = &loose_backend__stream_write;
|
||||
stream->stream.finalize_write = &loose_backend__stream_fwrite;
|
||||
stream->stream.free = &loose_backend__stream_free;
|
||||
stream->stream.mode = GIT_STREAM_WRONLY;
|
||||
|
||||
git__joinpath(tmp_path, backend->objects_dir, "tmp_object");
|
||||
|
||||
error = git_filebuf_open(&stream->fbuf, tmp_path,
|
||||
GIT_FILEBUF_HASH_CONTENTS |
|
||||
GIT_FILEBUF_DEFLATE_CONTENTS |
|
||||
GIT_FILEBUF_TEMPORARY);
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (git_odb_exists(_backend->odb, id))
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if ((error = deflate_obj(&buf, hdr, hdrlen, obj, backend->object_zlib_level)) < 0)
|
||||
error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_filebuf_cleanup(&stream->fbuf);
|
||||
free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = write_obj(&buf, id, backend);
|
||||
|
||||
gitfo_free_buf(&buf);
|
||||
return error;
|
||||
*stream_out = (git_odb_stream *)stream;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void loose_backend__free(git_odb_backend *_backend)
|
||||
@ -649,7 +655,7 @@ int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir
|
||||
|
||||
backend->parent.read = &loose_backend__read;
|
||||
backend->parent.read_header = &loose_backend__read_header;
|
||||
backend->parent.write = &loose_backend__write;
|
||||
backend->parent.writestream = &loose_backend__stream;
|
||||
backend->parent.exists = &loose_backend__exists;
|
||||
backend->parent.free = &loose_backend__free;
|
||||
|
||||
|
2299
src/odb_pack.c
2299
src/odb_pack.c
File diff suppressed because it is too large
Load Diff
14
src/oid.c
14
src/oid.c
@ -143,14 +143,18 @@ int git__parse_oid(git_oid *oid, char **buffer_out,
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid)
|
||||
int git__write_oid(git_odb_stream *stream, const char *header, const git_oid *oid)
|
||||
{
|
||||
char hex_oid[41];
|
||||
char hex_oid[42];
|
||||
|
||||
git_oid_fmt(hex_oid, oid);
|
||||
hex_oid[40] = 0;
|
||||
git_oid_fmt(hex_oid + 1, oid);
|
||||
|
||||
return git__source_printf(src, "%s %s\n", header, hex_oid);
|
||||
hex_oid[0] = ' ';
|
||||
hex_oid[41] = '\n';
|
||||
|
||||
stream->write(stream, header, strlen(header));
|
||||
stream->write(stream, hex_oid, 42);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_oid_mkraw(git_oid *out, const unsigned char *raw)
|
||||
|
157
src/pqueue.c
Normal file
157
src/pqueue.c
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* BORING COPYRIGHT NOTICE:
|
||||
*
|
||||
* This file is a heavily modified version of the priority queue found
|
||||
* in the Apache project and the libpqueue library.
|
||||
*
|
||||
* https://github.com/vy/libpqueue
|
||||
*
|
||||
* These are the original authors:
|
||||
*
|
||||
* Copyright 2010 Volkan Yazıcı <volkan.yazici@gmail.com>
|
||||
* Copyright 2006-2010 The Apache Software Foundation
|
||||
*
|
||||
* This file is licensed under the Apache 2.0 license, which
|
||||
* supposedly makes it compatible with the GPLv2 that libgit2 uses.
|
||||
*
|
||||
* Check the Apache license at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* So much licensing trouble for a binary heap. Oh well.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "pqueue.h"
|
||||
|
||||
#define left(i) ((i) << 1)
|
||||
#define right(i) (((i) << 1) + 1)
|
||||
#define parent(i) ((i) >> 1)
|
||||
|
||||
int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri)
|
||||
{
|
||||
assert(q);
|
||||
|
||||
/* Need to allocate n+1 elements since element 0 isn't used. */
|
||||
if ((q->d = malloc((n + 1) * sizeof(void *))) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
q->size = 1;
|
||||
q->avail = q->step = (n + 1); /* see comment above about n+1 */
|
||||
q->cmppri = cmppri;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void git_pqueue_free(git_pqueue *q)
|
||||
{
|
||||
free(q->d);
|
||||
q->d = NULL;
|
||||
}
|
||||
|
||||
void git_pqueue_clear(git_pqueue *q)
|
||||
{
|
||||
q->size = 1;
|
||||
}
|
||||
|
||||
size_t git_pqueue_size(git_pqueue *q)
|
||||
{
|
||||
/* queue element 0 exists but doesn't count since it isn't used. */
|
||||
return (q->size - 1);
|
||||
}
|
||||
|
||||
|
||||
static void bubble_up(git_pqueue *q, size_t i)
|
||||
{
|
||||
size_t parent_node;
|
||||
void *moving_node = q->d[i];
|
||||
|
||||
for (parent_node = parent(i);
|
||||
((i > 1) && q->cmppri(q->d[parent_node], moving_node));
|
||||
i = parent_node, parent_node = parent(i)) {
|
||||
q->d[i] = q->d[parent_node];
|
||||
}
|
||||
|
||||
q->d[i] = moving_node;
|
||||
}
|
||||
|
||||
|
||||
static size_t maxchild(git_pqueue *q, size_t i)
|
||||
{
|
||||
size_t child_node = left(i);
|
||||
|
||||
if (child_node >= q->size)
|
||||
return 0;
|
||||
|
||||
if ((child_node + 1) < q->size &&
|
||||
q->cmppri(q->d[child_node], q->d[child_node + 1]))
|
||||
child_node++; /* use right child instead of left */
|
||||
|
||||
return child_node;
|
||||
}
|
||||
|
||||
|
||||
static void percolate_down(git_pqueue *q, size_t i)
|
||||
{
|
||||
size_t child_node;
|
||||
void *moving_node = q->d[i];
|
||||
|
||||
while ((child_node = maxchild(q, i)) != 0 &&
|
||||
q->cmppri(moving_node, q->d[child_node])) {
|
||||
q->d[i] = q->d[child_node];
|
||||
i = child_node;
|
||||
}
|
||||
|
||||
q->d[i] = moving_node;
|
||||
}
|
||||
|
||||
|
||||
int git_pqueue_insert(git_pqueue *q, void *d)
|
||||
{
|
||||
void *tmp;
|
||||
size_t i;
|
||||
size_t newsize;
|
||||
|
||||
if (!q) return 1;
|
||||
|
||||
/* allocate more memory if necessary */
|
||||
if (q->size >= q->avail) {
|
||||
newsize = q->size + q->step;
|
||||
if ((tmp = realloc(q->d, sizeof(void *) * newsize)) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
q->d = tmp;
|
||||
q->avail = newsize;
|
||||
}
|
||||
|
||||
/* insert item */
|
||||
i = q->size++;
|
||||
q->d[i] = d;
|
||||
bubble_up(q, i);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void *git_pqueue_pop(git_pqueue *q)
|
||||
{
|
||||
void *head;
|
||||
|
||||
if (!q || q->size == 1)
|
||||
return NULL;
|
||||
|
||||
head = q->d[1];
|
||||
q->d[1] = q->d[--q->size];
|
||||
percolate_down(q, 1);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
void *git_pqueue_peek(git_pqueue *q)
|
||||
{
|
||||
if (!q || q->size == 1)
|
||||
return NULL;
|
||||
return q->d[1];
|
||||
}
|
97
src/pqueue.h
Normal file
97
src/pqueue.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* BORING COPYRIGHT NOTICE:
|
||||
*
|
||||
* This file is a heavily modified version of the priority queue found
|
||||
* in the Apache project and the libpqueue library.
|
||||
*
|
||||
* https://github.com/vy/libpqueue
|
||||
*
|
||||
* These are the original authors:
|
||||
*
|
||||
* Copyright 2010 Volkan Yazıcı <volkan.yazici@gmail.com>
|
||||
* Copyright 2006-2010 The Apache Software Foundation
|
||||
*
|
||||
* This file is licensed under the Apache 2.0 license, which
|
||||
* supposedly makes it compatible with the GPLv2 that libgit2 uses.
|
||||
*
|
||||
* Check the Apache license at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* So much licensing trouble for a binary heap. Oh well.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_pqueue_h__
|
||||
#define INCLUDE_pqueue_h__
|
||||
|
||||
/** callback functions to get/set/compare the priority of an element */
|
||||
typedef int (*git_pqueue_cmp)(void *a, void *b);
|
||||
|
||||
/** the priority queue handle */
|
||||
typedef struct {
|
||||
size_t size, avail, step;
|
||||
git_pqueue_cmp cmppri;
|
||||
void **d;
|
||||
} git_pqueue;
|
||||
|
||||
|
||||
/**
|
||||
* initialize the queue
|
||||
*
|
||||
* @param n the initial estimate of the number of queue items for which memory
|
||||
* should be preallocated
|
||||
* @param cmppri the callback function to compare two nodes of the queue
|
||||
*
|
||||
* @Return the handle or NULL for insufficent memory
|
||||
*/
|
||||
int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri);
|
||||
|
||||
|
||||
/**
|
||||
* free all memory used by the queue
|
||||
* @param q the queue
|
||||
*/
|
||||
void git_pqueue_free(git_pqueue *q);
|
||||
|
||||
/**
|
||||
* clear all the elements in the queue
|
||||
* @param q the queue
|
||||
*/
|
||||
void git_pqueue_clear(git_pqueue *q);
|
||||
|
||||
/**
|
||||
* return the size of the queue.
|
||||
* @param q the queue
|
||||
*/
|
||||
size_t git_pqueue_size(git_pqueue *q);
|
||||
|
||||
|
||||
/**
|
||||
* insert an item into the queue.
|
||||
* @param q the queue
|
||||
* @param d the item
|
||||
* @return 0 on success
|
||||
*/
|
||||
int git_pqueue_insert(git_pqueue *q, void *d);
|
||||
|
||||
|
||||
/**
|
||||
* pop the highest-ranking item from the queue.
|
||||
* @param p the queue
|
||||
* @param d where to copy the entry to
|
||||
* @return NULL on error, otherwise the entry
|
||||
*/
|
||||
void *git_pqueue_pop(git_pqueue *q);
|
||||
|
||||
|
||||
/**
|
||||
* access highest-ranking item without removing it.
|
||||
* @param q the queue
|
||||
* @param d the entry
|
||||
* @return NULL on error, otherwise the entry
|
||||
*/
|
||||
void *git_pqueue_peek(git_pqueue *q);
|
||||
|
||||
#endif /* PQUEUE_H */
|
||||
/** @} */
|
||||
|
764
src/refs.c
764
src/refs.c
@ -59,16 +59,16 @@ static uint32_t reftable_hash(const void *key, int hash_id)
|
||||
|
||||
static void reference_free(git_reference *reference);
|
||||
static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type);
|
||||
static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *repo_path, const char *ref_name);
|
||||
|
||||
/* loose refs */
|
||||
static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content);
|
||||
static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content);
|
||||
static int loose_read(gitfo_buf *file_content, const char *name, const char *repo_path);
|
||||
static int loose_lookup( git_reference **ref_out, git_repository *repo, const char *name, int skip_symbolic);
|
||||
static int loose_lookup(git_reference **ref_out, git_repository *repo, const char *name, int skip_symbolic);
|
||||
static int loose_write(git_reference *ref);
|
||||
static int loose_update(git_reference *ref);
|
||||
|
||||
/* packed refs */
|
||||
static int packed_readpack(gitfo_buf *packfile, const char *repo_path);
|
||||
static int packed_parse_peel(reference_oid *tag_ref, const char **buffer_out, const char *buffer_end);
|
||||
static int packed_parse_oid(reference_oid **ref_out, git_repository *repo, const char **buffer_out, const char *buffer_end);
|
||||
static int packed_load(git_repository *repo);
|
||||
@ -79,6 +79,11 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list);
|
||||
static int packed_sort(const void *a, const void *b);
|
||||
static int packed_write(git_repository *repo);
|
||||
|
||||
/* internal helpers */
|
||||
static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force);
|
||||
static int reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force);
|
||||
static int reference_rename(git_reference *ref, const char *new_name, int force);
|
||||
|
||||
/* name normalization */
|
||||
static int check_valid_ref_char(char ch);
|
||||
static int normalize_name(char *buffer_out, const char *name, int is_oid_ref);
|
||||
@ -146,12 +151,73 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *repo_path, const char *ref_name)
|
||||
{
|
||||
struct stat st;
|
||||
char path[GIT_PATH_MAX];
|
||||
|
||||
/* 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 (mtime)
|
||||
*mtime = st.st_mtime;
|
||||
|
||||
if (file_content)
|
||||
return gitfo_read_file(file_content, path);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Internal methods - Loose references
|
||||
*****************************************/
|
||||
static int loose_update(git_reference *ref)
|
||||
{
|
||||
int error;
|
||||
time_t ref_time;
|
||||
gitfo_buf ref_file = GITFO_BUF_INIT;
|
||||
|
||||
if (ref->type & GIT_REF_PACKED)
|
||||
return packed_load(ref->owner);
|
||||
|
||||
error = reference_read(NULL, &ref_time, ref->owner->path_repository, ref->name);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (ref_time == ref->mtime)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
error = reference_read(&ref_file, &ref->mtime, ref->owner->path_repository, ref->name);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (ref->type == GIT_REF_SYMBOLIC)
|
||||
error = loose_parse_symbolic(ref, &ref_file);
|
||||
else if (ref->type == GIT_REF_OID)
|
||||
error = loose_parse_oid(ref, &ref_file);
|
||||
else
|
||||
error = GIT_EINVALIDREFSTATE;
|
||||
|
||||
gitfo_free_buf(&ref_file);
|
||||
|
||||
cleanup:
|
||||
if (error != GIT_SUCCESS) {
|
||||
reference_free(ref);
|
||||
git_hashtable_remove(ref->owner->references.loose_cache, ref->name);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content)
|
||||
{
|
||||
const unsigned int header_len = strlen(GIT_SYMREF);
|
||||
@ -172,6 +238,7 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content)
|
||||
|
||||
refname_start += header_len;
|
||||
|
||||
free(ref_sym->target);
|
||||
ref_sym->target = git__strdup(refname_start);
|
||||
if (ref_sym->target == NULL)
|
||||
return GIT_ENOMEM;
|
||||
@ -213,26 +280,23 @@ static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int loose_read(gitfo_buf *file_content, const char *name, const char *repo_path)
|
||||
|
||||
static git_rtype loose_guess_rtype(const char *full_path)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
char ref_path[GIT_PATH_MAX];
|
||||
gitfo_buf ref_file = GITFO_BUF_INIT;
|
||||
git_rtype type;
|
||||
|
||||
/* Determine the full path of the ref */
|
||||
git__joinpath(ref_path, repo_path, name);
|
||||
type = GIT_REF_INVALID;
|
||||
|
||||
/* Does it even exist ? */
|
||||
if (gitfo_exists(ref_path) < GIT_SUCCESS)
|
||||
return GIT_ENOTFOUND;
|
||||
if (gitfo_read_file(&ref_file, full_path) == GIT_SUCCESS) {
|
||||
if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0)
|
||||
type = GIT_REF_SYMBOLIC;
|
||||
else
|
||||
type = GIT_REF_OID;
|
||||
}
|
||||
|
||||
/* A ref can not be a directory */
|
||||
if (!gitfo_isdir(ref_path))
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if (file_content != NULL)
|
||||
error = gitfo_read_file(file_content, ref_path);
|
||||
|
||||
return error;
|
||||
gitfo_free_buf(&ref_file);
|
||||
return type;
|
||||
}
|
||||
|
||||
static int loose_lookup(
|
||||
@ -244,10 +308,11 @@ static int loose_lookup(
|
||||
int error = GIT_SUCCESS;
|
||||
gitfo_buf ref_file = GITFO_BUF_INIT;
|
||||
git_reference *ref = NULL;
|
||||
time_t ref_time;
|
||||
|
||||
*ref_out = NULL;
|
||||
|
||||
error = loose_read(&ref_file, name, repo->path_repository);
|
||||
error = reference_read(&ref_file, &ref_time, repo->path_repository, name);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
@ -271,7 +336,9 @@ static int loose_lookup(
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
ref->mtime = ref_time;
|
||||
*ref_out = ref;
|
||||
gitfo_free_buf(&ref_file);
|
||||
return GIT_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
@ -286,6 +353,7 @@ static int loose_write(git_reference *ref)
|
||||
char ref_path[GIT_PATH_MAX];
|
||||
int error, contents_size;
|
||||
char *ref_contents = NULL;
|
||||
struct stat st;
|
||||
|
||||
assert((ref->type & GIT_REF_PACKED) == 0);
|
||||
|
||||
@ -331,6 +399,9 @@ static int loose_write(git_reference *ref)
|
||||
|
||||
error = git_filebuf_commit(&file);
|
||||
|
||||
if (gitfo_stat(ref_path, &st) == GIT_SUCCESS)
|
||||
ref->mtime = st.st_mtime;
|
||||
|
||||
free(ref_contents);
|
||||
return error;
|
||||
|
||||
@ -348,19 +419,6 @@ unlock:
|
||||
/*****************************************
|
||||
* Internal methods - Packed references
|
||||
*****************************************/
|
||||
static int packed_readpack(gitfo_buf *packfile, const char *repo_path)
|
||||
{
|
||||
char ref_path[GIT_PATH_MAX];
|
||||
|
||||
/* Determine the full path of the file */
|
||||
git__joinpath(ref_path, repo_path, GIT_PACKEDREFS_FILE);
|
||||
|
||||
/* Does it even exist ? */
|
||||
if (gitfo_exists(ref_path) < GIT_SUCCESS)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return gitfo_read_file(packfile, ref_path);
|
||||
}
|
||||
|
||||
static int packed_parse_peel(
|
||||
reference_oid *tag_ref,
|
||||
@ -465,19 +523,40 @@ static int packed_load(git_repository *repo)
|
||||
git_refcache *ref_cache = &repo->references;
|
||||
|
||||
/* already loaded */
|
||||
if (repo->references.packfile != NULL)
|
||||
return GIT_SUCCESS;
|
||||
if (repo->references.packfile != NULL) {
|
||||
time_t packed_time;
|
||||
|
||||
repo->references.packfile = git_hashtable_alloc(
|
||||
default_table_size,
|
||||
reftable_hash,
|
||||
(git_hash_keyeq_ptr)strcmp);
|
||||
/* check if we can read the time of the index;
|
||||
* if we can read it and it matches the time of the
|
||||
* index we had previously loaded, we don't need to do
|
||||
* anything else.
|
||||
*
|
||||
* if we cannot load the time (e.g. the packfile
|
||||
* has disappeared) or the time is different, we
|
||||
* have to reload the packfile */
|
||||
|
||||
if (repo->references.packfile == NULL)
|
||||
return GIT_ENOMEM;
|
||||
if (!reference_read(NULL, &packed_time, repo->path_repository, GIT_PACKEDREFS_FILE) &&
|
||||
packed_time == ref_cache->packfile_time)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
/* read the packfile from disk */
|
||||
error = packed_readpack(&packfile, repo->path_repository);
|
||||
git_hashtable_clear(repo->references.packfile);
|
||||
} else {
|
||||
ref_cache->packfile = git_hashtable_alloc(
|
||||
default_table_size,
|
||||
reftable_hash,
|
||||
(git_hash_keyeq_ptr)strcmp);
|
||||
|
||||
if (ref_cache->packfile == NULL)
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
/* read the packfile from disk;
|
||||
* store its modification time to check for future reloads */
|
||||
error = reference_read(
|
||||
&packfile,
|
||||
&ref_cache->packfile_time,
|
||||
repo->path_repository,
|
||||
GIT_PACKEDREFS_FILE);
|
||||
|
||||
/* there is no packfile on disk; that's ok */
|
||||
if (error == GIT_ENOTFOUND)
|
||||
@ -489,22 +568,14 @@ static int packed_load(git_repository *repo)
|
||||
buffer_start = (const char *)packfile.data;
|
||||
buffer_end = (const char *)(buffer_start) + packfile.len;
|
||||
|
||||
/* Does the header look like valid? */
|
||||
if (git__prefixcmp((const char *)(buffer_start), GIT_PACKEDREFS_HEADER)) {
|
||||
error = GIT_EPACKEDREFSCORRUPTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Let's skip the header */
|
||||
buffer_start += strlen(GIT_PACKEDREFS_HEADER);
|
||||
|
||||
if (*buffer_start == '\r')
|
||||
while (buffer_start < buffer_end && buffer_start[0] == '#') {
|
||||
buffer_start = strchr(buffer_start, '\n');
|
||||
if (buffer_start == NULL) {
|
||||
error = GIT_EPACKEDREFSCORRUPTED;
|
||||
goto cleanup;
|
||||
}
|
||||
buffer_start++;
|
||||
|
||||
if (*buffer_start != '\n')
|
||||
return GIT_EPACKEDREFSCORRUPTED;
|
||||
|
||||
buffer_start++;
|
||||
}
|
||||
|
||||
while (buffer_start < buffer_end) {
|
||||
reference_oid *ref = NULL;
|
||||
@ -526,11 +597,49 @@ static int packed_load(git_repository *repo)
|
||||
}
|
||||
}
|
||||
|
||||
gitfo_free_buf(&packfile);
|
||||
return GIT_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
git_hashtable_free(ref_cache->packfile);
|
||||
ref_cache->packfile = NULL;
|
||||
gitfo_free_buf(&packfile);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct dirent_list_data {
|
||||
git_repository *repo;
|
||||
size_t repo_path_len;
|
||||
unsigned int list_flags;
|
||||
|
||||
int (*callback)(const char *, void *);
|
||||
void *callback_payload;
|
||||
};
|
||||
|
||||
static int _dirent_loose_listall(void *_data, char *full_path)
|
||||
{
|
||||
struct dirent_list_data *data = (struct dirent_list_data *)_data;
|
||||
char *file_path = full_path + data->repo_path_len;
|
||||
|
||||
if (gitfo_isdir(full_path) == GIT_SUCCESS)
|
||||
return gitfo_dirent(full_path, GIT_PATH_MAX, _dirent_loose_listall, _data);
|
||||
|
||||
/* do not add twice a reference that exists already in the packfile */
|
||||
if ((data->list_flags & GIT_REF_PACKED) != 0 &&
|
||||
git_hashtable_lookup(data->repo->references.packfile, file_path) != NULL)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if (data->list_flags != GIT_REF_LISTALL) {
|
||||
if ((data->list_flags & loose_guess_rtype(full_path)) == 0)
|
||||
return GIT_SUCCESS; /* we are filtering out this reference */
|
||||
}
|
||||
|
||||
return data->callback(file_path, data->callback_payload);
|
||||
}
|
||||
|
||||
static int _dirent_loose_load(void *data, char *full_path)
|
||||
{
|
||||
git_repository *repository = (git_repository *)data;
|
||||
@ -638,7 +747,6 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file)
|
||||
static int packed_find_peel(reference_oid *ref)
|
||||
{
|
||||
git_tag *tag;
|
||||
const git_object *peeled_target;
|
||||
int error;
|
||||
|
||||
if (ref->ref.type & GIT_REF_HAS_PEEL)
|
||||
@ -663,11 +771,7 @@ static int packed_find_peel(reference_oid *ref)
|
||||
/*
|
||||
* Find the object pointed at by this tag
|
||||
*/
|
||||
peeled_target = git_tag_target(tag);
|
||||
if (peeled_target == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
git_oid_cpy(&ref->peel_target, git_object_id(peeled_target));
|
||||
git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag));
|
||||
ref->ref.type |= GIT_REF_HAS_PEEL;
|
||||
|
||||
/*
|
||||
@ -772,7 +876,9 @@ static int packed_write(git_repository *repo)
|
||||
if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Packfiles have a header! */
|
||||
/* Packfiles have a header... apparently
|
||||
* This is in fact not required, but we might as well print it
|
||||
* just for kicks */
|
||||
if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -798,8 +904,14 @@ cleanup:
|
||||
|
||||
/* when and only when the packfile has been properly written,
|
||||
* we can go ahead and remove the loose refs */
|
||||
if (error == GIT_SUCCESS)
|
||||
if (error == GIT_SUCCESS) {
|
||||
struct stat st;
|
||||
|
||||
error = packed_remove_loose(repo, &packing_list);
|
||||
|
||||
if (gitfo_stat(pack_file_path, &st) == GIT_SUCCESS)
|
||||
repo->references.packfile_time = st.st_mtime;
|
||||
}
|
||||
}
|
||||
else git_filebuf_cleanup(&pack_file);
|
||||
|
||||
@ -808,8 +920,240 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Internal methods - reference creation
|
||||
*****************************************/
|
||||
|
||||
static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force)
|
||||
{
|
||||
char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
|
||||
int error = GIT_SUCCESS, updated = 0;
|
||||
git_reference *ref = NULL, *old_ref = NULL;
|
||||
|
||||
if (git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
|
||||
return GIT_EEXISTS;
|
||||
|
||||
/*
|
||||
* If they old ref was of the same type, then we can just update
|
||||
* it (once we've checked that the target is valid). Otherwise we
|
||||
* need a new reference because we can't make a symbolic ref out
|
||||
* of an oid one.
|
||||
* If if didn't exist, then we need to create a new one anyway.
|
||||
*/
|
||||
if (ref && ref->type & GIT_REF_SYMBOLIC){
|
||||
updated = 1;
|
||||
} else {
|
||||
ref = NULL;
|
||||
error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* The target can aither be the name of an object id reference or the name of another symbolic reference */
|
||||
error = normalize_name(normalized, target, 0);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* set the target; this will write the reference on disk */
|
||||
error = git_reference_set_target(ref, normalized);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* If we didn't update the ref, then we need to insert or replace
|
||||
* it in the loose cache. If we replaced a ref, free it.
|
||||
*/
|
||||
if (!updated){
|
||||
error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if(old_ref)
|
||||
reference_free(old_ref);
|
||||
}
|
||||
|
||||
*ref_out = ref;
|
||||
|
||||
return error;
|
||||
|
||||
cleanup:
|
||||
reference_free(ref);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force)
|
||||
{
|
||||
int error = GIT_SUCCESS, updated = 0;
|
||||
git_reference *ref = NULL, *old_ref = NULL;
|
||||
|
||||
if(git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
|
||||
return GIT_EEXISTS;
|
||||
|
||||
/*
|
||||
* If they old ref was of the same type, then we can just update
|
||||
* it (once we've checked that the target is valid). Otherwise we
|
||||
* need a new reference because we can't make a symbolic ref out
|
||||
* of an oid one.
|
||||
* If if didn't exist, then we need to create a new one anyway.
|
||||
*/
|
||||
if (ref && ref-> type & GIT_REF_OID){
|
||||
updated = 1;
|
||||
} else {
|
||||
ref = NULL;
|
||||
error = reference_create(&ref, repo, name, GIT_REF_OID);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set the oid; this will write the reference on disk */
|
||||
error = git_reference_set_oid(ref, id);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if(!updated){
|
||||
error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if(old_ref)
|
||||
reference_free(old_ref);
|
||||
}
|
||||
|
||||
*ref_out = ref;
|
||||
|
||||
return error;
|
||||
|
||||
cleanup:
|
||||
reference_free(ref);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename a reference
|
||||
*
|
||||
* If the reference is packed, we need to rewrite the
|
||||
* packfile to remove the reference from it and create
|
||||
* the reference back as a loose one.
|
||||
*
|
||||
* If the reference is loose, we just rename it on
|
||||
* the filesystem.
|
||||
*
|
||||
* We also need to re-insert the reference on its corresponding
|
||||
* in-memory cache, since the caches are indexed by refname.
|
||||
*/
|
||||
static int reference_rename(git_reference *ref, const char *new_name, int force)
|
||||
{
|
||||
int error;
|
||||
char *old_name;
|
||||
char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
|
||||
git_reference *looked_up_ref, *old_ref = NULL;
|
||||
|
||||
assert(ref);
|
||||
|
||||
/* Ensure the name is valid */
|
||||
error = normalize_name(normalized_name, new_name, ref->type & GIT_REF_OID);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Ensure we're not going to overwrite an existing reference
|
||||
unless the user has allowed us */
|
||||
error = git_reference_lookup(&looked_up_ref, ref->owner, new_name);
|
||||
if (error == GIT_SUCCESS && !force)
|
||||
return GIT_EEXISTS;
|
||||
|
||||
if (error < GIT_SUCCESS &&
|
||||
error != GIT_ENOTFOUND)
|
||||
return error;
|
||||
|
||||
|
||||
old_name = ref->name;
|
||||
ref->name = git__strdup(new_name);
|
||||
|
||||
if (ref->name == NULL) {
|
||||
ref->name = old_name;
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if (ref->type & GIT_REF_PACKED) {
|
||||
/* write the packfile to disk; note
|
||||
* that the state of the in-memory cache is not
|
||||
* consistent, because the reference is indexed
|
||||
* by its old name but it already has the new one.
|
||||
* This doesn't affect writing, though, and allows
|
||||
* us to rollback if writing fails
|
||||
*/
|
||||
|
||||
ref->type &= ~GIT_REF_PACKED;
|
||||
|
||||
/* Create the loose ref under its new name */
|
||||
error = loose_write(ref);
|
||||
if (error < GIT_SUCCESS) {
|
||||
ref->type |= GIT_REF_PACKED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Remove from the packfile cache in order to avoid packing it back
|
||||
* Note : we do not rely on git_reference_delete() because this would
|
||||
* invalidate the reference.
|
||||
*/
|
||||
git_hashtable_remove(ref->owner->references.packfile, old_name);
|
||||
|
||||
/* Recreate the packed-refs file without the reference */
|
||||
error = packed_write(ref->owner);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto rename_loose_to_old_name;
|
||||
|
||||
} else {
|
||||
git__joinpath(old_path, ref->owner->path_repository, old_name);
|
||||
git__joinpath(new_path, ref->owner->path_repository, ref->name);
|
||||
|
||||
error = gitfo_mv_force(old_path, new_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* Once succesfully renamed, remove from the cache the reference known by its old name*/
|
||||
git_hashtable_remove(ref->owner->references.loose_cache, old_name);
|
||||
}
|
||||
|
||||
/* Store the renamed reference into the loose ref cache */
|
||||
error = git_hashtable_insert2(ref->owner->references.loose_cache, ref->name, ref, (void **) &old_ref);
|
||||
|
||||
/* If we force-replaced, we need to free the old reference */
|
||||
if(old_ref)
|
||||
reference_free(old_ref);
|
||||
|
||||
free(old_name);
|
||||
return error;
|
||||
|
||||
cleanup:
|
||||
/* restore the old name if this failed */
|
||||
free(ref->name);
|
||||
ref->name = old_name;
|
||||
return error;
|
||||
|
||||
rename_loose_to_old_name:
|
||||
/* If we hit this point. Something *bad* happened! Think "Ghostbusters
|
||||
* crossing the streams" definition of bad.
|
||||
* Either the packed-refs has been correctly generated and something else
|
||||
* has gone wrong, or the writing of the new packed-refs has failed, and
|
||||
* we're stuck with the old one. As a loose ref always takes priority over
|
||||
* a packed ref, we'll eventually try and rename the generated loose ref to
|
||||
* its former name. It even that fails, well... we might have lost the reference
|
||||
* for good. :-/
|
||||
*/
|
||||
|
||||
git__joinpath(old_path, ref->owner->path_repository, ref->name);
|
||||
git__joinpath(new_path, ref->owner->path_repository, old_name);
|
||||
|
||||
/* No error checking. We'll return the initial error */
|
||||
gitfo_mv_force(old_path, new_path);
|
||||
|
||||
/* restore the old name */
|
||||
free(ref->name);
|
||||
ref->name = old_name;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* External Library API
|
||||
@ -834,7 +1178,7 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch
|
||||
/* First, check has been previously loaded and cached */
|
||||
*ref_out = git_hashtable_lookup(repo->references.loose_cache, normalized_name);
|
||||
if (*ref_out != NULL)
|
||||
return GIT_SUCCESS;
|
||||
return loose_update(*ref_out);
|
||||
|
||||
/* Then check if there is a loose file for that reference.*/
|
||||
error = loose_lookup(ref_out, repo, normalized_name, 0);
|
||||
@ -852,12 +1196,10 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch
|
||||
* If we cannot find a loose reference, we look into the packfile
|
||||
* Load the packfile first if it hasn't been loaded
|
||||
*/
|
||||
if (!repo->references.packfile) {
|
||||
/* load all the packed references */
|
||||
error = packed_load(repo);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
/* load all the packed references */
|
||||
error = packed_load(repo);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Look up on the packfile */
|
||||
*ref_out = git_hashtable_lookup(repo->references.packfile, normalized_name);
|
||||
@ -870,64 +1212,23 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch
|
||||
|
||||
int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target)
|
||||
{
|
||||
char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
|
||||
int error = GIT_SUCCESS;
|
||||
git_reference *ref = NULL;
|
||||
return reference_create_symbolic(ref_out, repo, name, target, 0);
|
||||
}
|
||||
|
||||
error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* The target can aither be the name of an object id reference or the name of another symbolic reference */
|
||||
error = normalize_name(normalized, target, 0);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* set the target; this will write the reference on disk */
|
||||
error = git_reference_set_target(ref, normalized);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
error = git_hashtable_insert(repo->references.loose_cache, ref->name, ref);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
*ref_out = ref;
|
||||
|
||||
return error;
|
||||
|
||||
cleanup:
|
||||
reference_free(ref);
|
||||
return error;
|
||||
int git_reference_create_symbolic_f(git_reference **ref_out, git_repository *repo, const char *name, const char *target)
|
||||
{
|
||||
return reference_create_symbolic(ref_out, repo, name, target, 1);
|
||||
}
|
||||
|
||||
int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
git_reference *ref = NULL;
|
||||
|
||||
error = reference_create(&ref, repo, name, GIT_REF_OID);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* set the oid; this will write the reference on disk */
|
||||
error = git_reference_set_oid(ref, id);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
error = git_hashtable_insert(repo->references.loose_cache, ref->name, ref);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
*ref_out = ref;
|
||||
|
||||
return error;
|
||||
|
||||
cleanup:
|
||||
reference_free(ref);
|
||||
return error;
|
||||
return reference_create_oid(ref_out, repo, name, id, 0);
|
||||
}
|
||||
|
||||
int git_reference_create_oid_f(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id)
|
||||
{
|
||||
return reference_create_oid(ref_out, repo, name, id, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getters
|
||||
@ -964,6 +1265,9 @@ const git_oid *git_reference_oid(git_reference *ref)
|
||||
if ((ref->type & GIT_REF_OID) == 0)
|
||||
return NULL;
|
||||
|
||||
if (loose_update(ref) < GIT_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
return &((reference_oid *)ref)->oid;
|
||||
}
|
||||
|
||||
@ -974,6 +1278,9 @@ const char *git_reference_target(git_reference *ref)
|
||||
if ((ref->type & GIT_REF_SYMBOLIC) == 0)
|
||||
return NULL;
|
||||
|
||||
if (loose_update(ref) < GIT_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
return ((reference_symbolic *)ref)->target;
|
||||
}
|
||||
|
||||
@ -1012,6 +1319,13 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id)
|
||||
|
||||
ref_oid = (reference_oid *)ref;
|
||||
|
||||
assert(ref->owner);
|
||||
|
||||
/* Don't let the user create references to OIDs that
|
||||
* don't exist in the ODB */
|
||||
if (!git_odb_exists(git_repository_database(ref->owner), id))
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
/* duplicate the reference;
|
||||
* this copy will stay on the packfile cache */
|
||||
if (ref->type & GIT_REF_PACKED) {
|
||||
@ -1129,125 +1443,14 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename a reference
|
||||
*
|
||||
* If the reference is packed, we need to rewrite the
|
||||
* packfile to remove the reference from it and create
|
||||
* the reference back as a loose one.
|
||||
*
|
||||
* If the reference is loose, we just rename it on
|
||||
* the filesystem.
|
||||
*
|
||||
* We also need to re-insert the reference on its corresponding
|
||||
* in-memory cache, since the caches are indexed by refname.
|
||||
*/
|
||||
int git_reference_rename(git_reference *ref, const char *new_name)
|
||||
{
|
||||
int error;
|
||||
char *old_name;
|
||||
char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
|
||||
git_reference *looked_up_ref;
|
||||
return reference_rename(ref, new_name, 0);
|
||||
}
|
||||
|
||||
assert(ref);
|
||||
|
||||
/* Ensure the name is valid */
|
||||
error = normalize_name(normalized_name, new_name, ref->type & GIT_REF_OID);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Ensure we're not going to overwrite an existing reference */
|
||||
error = git_reference_lookup(&looked_up_ref, ref->owner, new_name);
|
||||
if (error == GIT_SUCCESS)
|
||||
return GIT_EINVALIDREFNAME;
|
||||
|
||||
if (error != GIT_ENOTFOUND)
|
||||
return error;
|
||||
|
||||
|
||||
old_name = ref->name;
|
||||
ref->name = git__strdup(new_name);
|
||||
|
||||
if (ref->name == NULL) {
|
||||
ref->name = old_name;
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if (ref->type & GIT_REF_PACKED) {
|
||||
/* write the packfile to disk; note
|
||||
* that the state of the in-memory cache is not
|
||||
* consistent, because the reference is indexed
|
||||
* by its old name but it already has the new one.
|
||||
* This doesn't affect writing, though, and allows
|
||||
* us to rollback if writing fails
|
||||
*/
|
||||
|
||||
ref->type &= ~GIT_REF_PACKED;
|
||||
|
||||
/* Create the loose ref under its new name */
|
||||
error = loose_write(ref);
|
||||
if (error < GIT_SUCCESS) {
|
||||
ref->type |= GIT_REF_PACKED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Remove from the packfile cache in order to avoid packing it back
|
||||
* Note : we do not rely on git_reference_delete() because this would
|
||||
* invalidate the reference.
|
||||
*/
|
||||
git_hashtable_remove(ref->owner->references.packfile, old_name);
|
||||
|
||||
/* Recreate the packed-refs file without the reference */
|
||||
error = packed_write(ref->owner);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto rename_loose_to_old_name;
|
||||
|
||||
} else {
|
||||
git__joinpath(old_path, ref->owner->path_repository, old_name);
|
||||
git__joinpath(new_path, ref->owner->path_repository, ref->name);
|
||||
|
||||
error = gitfo_mv_force(old_path, new_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* Once succesfully renamed, remove from the cache the reference known by its old name*/
|
||||
git_hashtable_remove(ref->owner->references.loose_cache, old_name);
|
||||
}
|
||||
|
||||
/* Store the renamed reference into the loose ref cache */
|
||||
error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref);
|
||||
|
||||
free(old_name);
|
||||
return error;
|
||||
|
||||
cleanup:
|
||||
/* restore the old name if this failed */
|
||||
free(ref->name);
|
||||
ref->name = old_name;
|
||||
return error;
|
||||
|
||||
rename_loose_to_old_name:
|
||||
/* If we hit this point. Something *bad* happened! Think "Ghostbusters
|
||||
* crossing the streams" definition of bad.
|
||||
* Either the packed-refs has been correctly generated and something else
|
||||
* has gone wrong, or the writing of the new packed-refs has failed, and
|
||||
* we're stuck with the old one. As a loose ref always takes priority over
|
||||
* a packed ref, we'll eventually try and rename the generated loose ref to
|
||||
* its former name. It even that fails, well... we might have lost the reference
|
||||
* for good. :-/
|
||||
*/
|
||||
|
||||
git__joinpath(old_path, ref->owner->path_repository, ref->name);
|
||||
git__joinpath(new_path, ref->owner->path_repository, old_name);
|
||||
|
||||
/* No error checking. We'll return the initial error */
|
||||
gitfo_mv_force(old_path, new_path);
|
||||
|
||||
/* restore the old name */
|
||||
free(ref->name);
|
||||
ref->name = old_name;
|
||||
|
||||
return error;
|
||||
int git_reference_rename_f(git_reference *ref, const char *new_name)
|
||||
{
|
||||
return reference_rename(ref, new_name, 1);
|
||||
}
|
||||
|
||||
int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)
|
||||
@ -1257,6 +1460,9 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)
|
||||
|
||||
assert(resolved_ref && ref);
|
||||
*resolved_ref = NULL;
|
||||
|
||||
if ((error = loose_update(ref)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
repo = ref->owner;
|
||||
|
||||
@ -1292,6 +1498,69 @@ int git_reference_packall(git_repository *repo)
|
||||
return packed_write(repo);
|
||||
}
|
||||
|
||||
int git_reference_listcb(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload)
|
||||
{
|
||||
int error;
|
||||
struct dirent_list_data data;
|
||||
char refs_path[GIT_PATH_MAX];
|
||||
|
||||
/* list all the packed references first */
|
||||
if (list_flags & GIT_REF_PACKED) {
|
||||
const char *ref_name;
|
||||
void *_unused;
|
||||
|
||||
if ((error = packed_load(repo)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
GIT_HASHTABLE_FOREACH(repo->references.packfile, ref_name, _unused,
|
||||
if ((error = callback(ref_name, payload)) < GIT_SUCCESS)
|
||||
return error;
|
||||
);
|
||||
}
|
||||
|
||||
/* now list the loose references, trying not to
|
||||
* duplicate the ref names already in the packed-refs file */
|
||||
|
||||
data.repo_path_len = strlen(repo->path_repository);
|
||||
data.list_flags = list_flags;
|
||||
data.repo = repo;
|
||||
data.callback = callback;
|
||||
data.callback_payload = payload;
|
||||
|
||||
|
||||
git__joinpath(refs_path, repo->path_repository, GIT_REFS_DIR);
|
||||
return gitfo_dirent(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data);
|
||||
}
|
||||
|
||||
int cb__reflist_add(const char *ref, void *data)
|
||||
{
|
||||
return git_vector_insert((git_vector *)data, git__strdup(ref));
|
||||
}
|
||||
|
||||
int git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags)
|
||||
{
|
||||
int error;
|
||||
git_vector ref_list;
|
||||
|
||||
assert(array && repo);
|
||||
|
||||
array->strings = NULL;
|
||||
array->count = 0;
|
||||
|
||||
if (git_vector_init(&ref_list, 8, NULL) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
error = git_reference_listcb(repo, list_flags, &cb__reflist_add, (void *)&ref_list);
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_vector_free(&ref_list);
|
||||
return error;
|
||||
}
|
||||
|
||||
array->strings = (char **)ref_list.contents;
|
||||
array->count = ref_list.length;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1411,8 +1680,9 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
|
||||
*buffer_out++ = *current++;
|
||||
}
|
||||
|
||||
/* Object id refname have to contain at least one slash */
|
||||
if (is_oid_ref && !contains_a_slash)
|
||||
/* 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))
|
||||
return GIT_EINVALIDREFNAME;
|
||||
|
||||
/* A refname can not end with ".lock" */
|
||||
@ -1421,9 +1691,13 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
|
||||
|
||||
*buffer_out = '\0';
|
||||
|
||||
/* For object id references, name has to start with refs/(heads|tags|remotes) */
|
||||
if (is_oid_ref && !(!git__prefixcmp(buffer_out_start, GIT_REFS_HEADS_DIR) ||
|
||||
!git__prefixcmp(buffer_out_start, GIT_REFS_TAGS_DIR) || !git__prefixcmp(buffer_out_start, GIT_REFS_REMOTES_DIR)))
|
||||
/*
|
||||
* For object id references, name has to start with refs/. Again,
|
||||
* we need to allow HEAD to be in a detached state.
|
||||
*/
|
||||
if (is_oid_ref &&
|
||||
!(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) ||
|
||||
strcmp(buffer_out_start, GIT_HEAD_FILE)))
|
||||
return GIT_EINVALIDREFNAME;
|
||||
|
||||
return error;
|
||||
|
@ -23,11 +23,13 @@ struct git_reference {
|
||||
git_repository *owner;
|
||||
char *name;
|
||||
unsigned int type;
|
||||
time_t mtime;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
git_hashtable *packfile;
|
||||
git_hashtable *loose_cache;
|
||||
time_t packfile_time;
|
||||
} git_refcache;
|
||||
|
||||
|
||||
|
107
src/repository.c
107
src/repository.c
@ -40,29 +40,11 @@
|
||||
|
||||
#define GIT_BRANCH_MASTER "master"
|
||||
|
||||
static const int OBJECT_TABLE_SIZE = 32;
|
||||
|
||||
typedef struct {
|
||||
char *path_repository;
|
||||
unsigned is_bare:1, has_been_reinit:1;
|
||||
} repo_init;
|
||||
|
||||
/*
|
||||
* Hash table methods
|
||||
*
|
||||
* Callbacks for the ODB cache, implemented
|
||||
* as a hash table
|
||||
*/
|
||||
uint32_t object_table_hash(const void *key, int hash_id)
|
||||
{
|
||||
uint32_t r;
|
||||
git_oid *id;
|
||||
|
||||
id = (git_oid *)key;
|
||||
memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Git repository open methods
|
||||
*
|
||||
@ -84,7 +66,7 @@ static int assign_repository_dirs(
|
||||
if (git_dir == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
error = gitfo_prettify_dir_path(path_aux, git_dir);
|
||||
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_dir);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -99,7 +81,7 @@ static int assign_repository_dirs(
|
||||
if (git_object_directory == NULL)
|
||||
git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
|
||||
else {
|
||||
error = gitfo_prettify_dir_path(path_aux, git_object_directory);
|
||||
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_object_directory);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
@ -113,7 +95,7 @@ static int assign_repository_dirs(
|
||||
if (git_work_tree == NULL)
|
||||
repo->is_bare = 1;
|
||||
else {
|
||||
error = gitfo_prettify_dir_path(path_aux, git_work_tree);
|
||||
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_work_tree);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -126,7 +108,7 @@ static int assign_repository_dirs(
|
||||
if (git_index_file == NULL)
|
||||
git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);
|
||||
else {
|
||||
error = gitfo_prettify_file_path(path_aux, git_index_file);
|
||||
error = gitfo_prettify_file_path(path_aux, sizeof(path_aux), git_index_file);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
@ -186,30 +168,13 @@ static git_repository *repository_alloc()
|
||||
|
||||
memset(repo, 0x0, sizeof(git_repository));
|
||||
|
||||
repo->objects = git_hashtable_alloc(
|
||||
OBJECT_TABLE_SIZE,
|
||||
object_table_hash,
|
||||
(git_hash_keyeq_ptr)git_oid_cmp);
|
||||
|
||||
if (repo->objects == NULL) {
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
|
||||
|
||||
if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
|
||||
git_hashtable_free(repo->objects);
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (git_vector_init(&repo->memory_objects, 16, NULL) < GIT_SUCCESS) {
|
||||
git_hashtable_free(repo->objects);
|
||||
git_repository__refcache_free(&repo->references);
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
repo->gc_enabled = 1;
|
||||
return repo;
|
||||
}
|
||||
|
||||
@ -331,20 +296,19 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void repository_free(git_repository *repo)
|
||||
void git_repository_free(git_repository *repo)
|
||||
{
|
||||
assert(repo);
|
||||
if (repo == NULL)
|
||||
return;
|
||||
|
||||
git_cache_free(&repo->objects);
|
||||
git_repository__refcache_free(&repo->references);
|
||||
|
||||
free(repo->path_workdir);
|
||||
free(repo->path_index);
|
||||
free(repo->path_repository);
|
||||
free(repo->path_odb);
|
||||
|
||||
git_hashtable_free(repo->objects);
|
||||
git_vector_free(&repo->memory_objects);
|
||||
|
||||
git_repository__refcache_free(&repo->references);
|
||||
|
||||
if (repo->db != NULL)
|
||||
git_odb_close(repo->db);
|
||||
|
||||
@ -354,53 +318,6 @@ static void repository_free(git_repository *repo)
|
||||
free(repo);
|
||||
}
|
||||
|
||||
void git_repository_free__no_gc(git_repository *repo)
|
||||
{
|
||||
git_object *object;
|
||||
const void *_unused;
|
||||
unsigned int i;
|
||||
|
||||
if (repo == NULL)
|
||||
return;
|
||||
|
||||
GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
|
||||
object->repo = NULL;
|
||||
object->refcount = 0;
|
||||
);
|
||||
|
||||
for (i = 0; i < repo->memory_objects.length; ++i) {
|
||||
object = git_vector_get(&repo->memory_objects, i);
|
||||
object->repo = NULL;
|
||||
object->refcount = 0;
|
||||
}
|
||||
|
||||
repository_free(repo);
|
||||
}
|
||||
|
||||
void git_repository_free(git_repository *repo)
|
||||
{
|
||||
git_object *object;
|
||||
const void *_unused;
|
||||
unsigned int i;
|
||||
|
||||
if (repo == NULL)
|
||||
return;
|
||||
|
||||
repo->gc_enabled = 0;
|
||||
|
||||
/* force free all the objects */
|
||||
GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
|
||||
git_object__free(object);
|
||||
);
|
||||
|
||||
for (i = 0; i < repo->memory_objects.length; ++i) {
|
||||
object = git_vector_get(&repo->memory_objects, i);
|
||||
git_object__free(object);
|
||||
}
|
||||
|
||||
repository_free(repo);
|
||||
}
|
||||
|
||||
int git_repository_index(git_index **index_out, git_repository *repo)
|
||||
{
|
||||
int error;
|
||||
@ -486,7 +403,7 @@ static int repo_init_find_dir(repo_init *results, const char* path)
|
||||
char temp_path[GIT_PATH_MAX];
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
error = gitfo_prettify_dir_path(temp_path, path);
|
||||
error = gitfo_prettify_dir_path(temp_path, sizeof(temp_path), path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "hashtable.h"
|
||||
#include "index.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
|
||||
#define DOT_GIT ".git"
|
||||
@ -16,28 +17,17 @@
|
||||
#define GIT_OBJECTS_DIR "objects/"
|
||||
#define GIT_INDEX_FILE "index"
|
||||
|
||||
typedef struct {
|
||||
git_rawobj raw;
|
||||
void *write_ptr;
|
||||
size_t written_bytes;
|
||||
int open:1;
|
||||
} git_odb_source;
|
||||
|
||||
struct git_object {
|
||||
git_oid id;
|
||||
git_cached_obj cached;
|
||||
git_repository *repo;
|
||||
git_odb_source source;
|
||||
unsigned short refcount;
|
||||
unsigned char in_memory, modified;
|
||||
git_otype type;
|
||||
};
|
||||
|
||||
struct git_repository {
|
||||
git_odb *db;
|
||||
git_index *index;
|
||||
|
||||
git_hashtable *objects;
|
||||
git_vector memory_objects;
|
||||
|
||||
git_cache objects;
|
||||
git_refcache references;
|
||||
|
||||
char *path_repository;
|
||||
@ -45,35 +35,15 @@ struct git_repository {
|
||||
char *path_odb;
|
||||
char *path_workdir;
|
||||
|
||||
unsigned is_bare:1, gc_enabled:1;
|
||||
unsigned is_bare:1;
|
||||
unsigned int lru_counter;
|
||||
};
|
||||
|
||||
int git_object__source_open(git_object *object);
|
||||
void git_object__source_close(git_object *object);
|
||||
|
||||
/* fully free the object; internal method, do not
|
||||
* export */
|
||||
void git_object__free(git_object *object);
|
||||
|
||||
int git__source_printf(git_odb_source *source, const char *format, ...);
|
||||
int git__source_write(git_odb_source *source, const void *bytes, size_t len);
|
||||
void git_object__free(void *object);
|
||||
|
||||
int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
|
||||
int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid);
|
||||
|
||||
#define GIT_OBJECT_INCREF(repo, ob) git_object__incref((repo), (git_object *)(ob))
|
||||
#define GIT_OBJECT_DECREF(repo, ob) git_object__decref((repo), (git_object *)(ob))
|
||||
|
||||
GIT_INLINE(void) git_object__incref(git_repository *repo, struct git_object *object)
|
||||
{
|
||||
if (repo && repo->gc_enabled && object)
|
||||
object->refcount++;
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_object__decref(git_repository *repo, struct git_object *object)
|
||||
{
|
||||
if (repo && repo->gc_enabled && object)
|
||||
git_object_close(object);
|
||||
}
|
||||
int git__write_oid(git_odb_stream *src, const char *header, const git_oid *oid);
|
||||
|
||||
#endif
|
||||
|
846
src/revwalk.c
846
src/revwalk.c
@ -25,26 +25,428 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "commit.h"
|
||||
#include "revwalk.h"
|
||||
#include "odb.h"
|
||||
#include "hashtable.h"
|
||||
#include "pqueue.h"
|
||||
|
||||
uint32_t git_revwalk__commit_hash(const void *key, int hash_id)
|
||||
#include "git2/revwalk.h"
|
||||
|
||||
typedef struct commit_object {
|
||||
git_oid oid;
|
||||
uint32_t time;
|
||||
unsigned int seen:1,
|
||||
uninteresting:1,
|
||||
topo_delay:1,
|
||||
parsed:1;
|
||||
|
||||
unsigned short in_degree;
|
||||
unsigned short out_degree;
|
||||
|
||||
struct commit_object **parents;
|
||||
} commit_object;
|
||||
|
||||
typedef struct commit_list {
|
||||
commit_object *item;
|
||||
struct commit_list *next;
|
||||
} commit_list;
|
||||
|
||||
struct git_revwalk {
|
||||
git_repository *repo;
|
||||
|
||||
git_hashtable *commits;
|
||||
|
||||
commit_list *iterator_topo;
|
||||
commit_list *iterator_rand;
|
||||
commit_list *iterator_reverse;
|
||||
git_pqueue iterator_time;
|
||||
|
||||
int (*get_next)(commit_object **, git_revwalk *);
|
||||
int (*enqueue)(git_revwalk *, commit_object *);
|
||||
|
||||
git_vector memory_alloc;
|
||||
size_t chunk_size;
|
||||
|
||||
unsigned walking:1;
|
||||
unsigned int sorting;
|
||||
};
|
||||
|
||||
commit_list *commit_list_insert(commit_object *item, commit_list **list_p)
|
||||
{
|
||||
commit_list *new_list = git__malloc(sizeof(commit_list));
|
||||
new_list->item = item;
|
||||
new_list->next = *list_p;
|
||||
*list_p = new_list;
|
||||
return new_list;
|
||||
}
|
||||
|
||||
void commit_list_free(commit_list **list_p)
|
||||
{
|
||||
commit_list *list = *list_p;
|
||||
|
||||
while (list) {
|
||||
commit_list *temp = list;
|
||||
list = temp->next;
|
||||
free(temp);
|
||||
}
|
||||
|
||||
*list_p = NULL;
|
||||
}
|
||||
|
||||
commit_object *commit_list_pop(commit_list **stack)
|
||||
{
|
||||
commit_list *top = *stack;
|
||||
commit_object *item = top ? top->item : NULL;
|
||||
|
||||
if (top) {
|
||||
*stack = top->next;
|
||||
free(top);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static int commit_time_cmp(void *a, void *b)
|
||||
{
|
||||
commit_object *commit_a = (commit_object *)a;
|
||||
commit_object *commit_b = (commit_object *)b;
|
||||
|
||||
return (commit_a->time < commit_b->time);
|
||||
}
|
||||
|
||||
static uint32_t object_table_hash(const void *key, int hash_id)
|
||||
{
|
||||
uint32_t r;
|
||||
git_commit *commit;
|
||||
git_oid *id;
|
||||
|
||||
commit = (git_commit *)key;
|
||||
memcpy(&r, commit->object.id.id + (hash_id * sizeof(uint32_t)), sizeof(r));
|
||||
id = (git_oid *)key;
|
||||
memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
int git_revwalk__commit_keycmp(const void *key_a, const void *key_b)
|
||||
#define COMMITS_PER_CHUNK 128
|
||||
#define CHUNK_STEP 64
|
||||
#define PARENTS_PER_COMMIT ((CHUNK_STEP - sizeof(commit_object)) / sizeof(commit_object *))
|
||||
|
||||
static int alloc_chunk(git_revwalk *walk)
|
||||
{
|
||||
git_commit *a = (git_commit *)key_a;
|
||||
git_commit *b = (git_commit *)key_b;
|
||||
return git_oid_cmp(&a->object.id, &b->object.id);
|
||||
void *chunk;
|
||||
|
||||
chunk = git__calloc(COMMITS_PER_CHUNK, CHUNK_STEP);
|
||||
if (chunk == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
walk->chunk_size = 0;
|
||||
return git_vector_insert(&walk->memory_alloc, chunk);
|
||||
}
|
||||
|
||||
static commit_object *alloc_commit(git_revwalk *walk)
|
||||
{
|
||||
unsigned char *chunk;
|
||||
|
||||
if (walk->chunk_size == COMMITS_PER_CHUNK)
|
||||
alloc_chunk(walk);
|
||||
|
||||
chunk = git_vector_get(&walk->memory_alloc, walk->memory_alloc.length - 1);
|
||||
chunk += (walk->chunk_size * CHUNK_STEP);
|
||||
walk->chunk_size++;
|
||||
|
||||
return (commit_object *)chunk;
|
||||
}
|
||||
|
||||
static commit_object **alloc_parents(commit_object *commit, size_t n_parents)
|
||||
{
|
||||
if (n_parents <= PARENTS_PER_COMMIT)
|
||||
return (commit_object **)((unsigned char *)commit + sizeof(commit_object));
|
||||
|
||||
return git__malloc(n_parents * sizeof(commit_object *));
|
||||
}
|
||||
|
||||
|
||||
static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid)
|
||||
{
|
||||
commit_object *commit;
|
||||
|
||||
if ((commit = git_hashtable_lookup(walk->commits, oid)) != NULL)
|
||||
return commit;
|
||||
|
||||
commit = alloc_commit(walk);
|
||||
if (commit == NULL)
|
||||
return NULL;
|
||||
|
||||
git_oid_cpy(&commit->oid, oid);
|
||||
|
||||
if (git_hashtable_insert(walk->commits, &commit->oid, commit) < GIT_SUCCESS) {
|
||||
free(commit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return commit;
|
||||
}
|
||||
|
||||
static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawobj *raw)
|
||||
{
|
||||
const int parent_len = STRLEN("parent ") + GIT_OID_HEXSZ + 1;
|
||||
|
||||
unsigned char *buffer = raw->data;
|
||||
unsigned char *buffer_end = buffer + raw->len;
|
||||
unsigned char *parents_start;
|
||||
|
||||
int i, parents = 0;
|
||||
|
||||
buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1;
|
||||
|
||||
parents_start = buffer;
|
||||
while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", STRLEN("parent ")) == 0) {
|
||||
parents++;
|
||||
buffer += parent_len;
|
||||
}
|
||||
|
||||
commit->parents = alloc_parents(commit, parents);
|
||||
if (commit->parents == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
buffer = parents_start;
|
||||
for (i = 0; i < parents; ++i) {
|
||||
git_oid oid;
|
||||
|
||||
if (git_oid_mkstr(&oid, (char *)buffer + STRLEN("parent ")) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
commit->parents[i] = commit_lookup(walk, &oid);
|
||||
if (commit->parents[i] == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
buffer += parent_len;
|
||||
}
|
||||
|
||||
commit->out_degree = (unsigned short)parents;
|
||||
|
||||
if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
buffer = memchr(buffer, '>', buffer_end - buffer);
|
||||
if (buffer == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
commit->time = strtol((char *)buffer + 2, NULL, 10);
|
||||
if (commit->time == 0)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
commit->parsed = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int commit_parse(git_revwalk *walk, commit_object *commit)
|
||||
{
|
||||
git_odb_object *obj;
|
||||
int error;
|
||||
|
||||
if (commit->parsed)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (obj->raw.type != GIT_OBJ_COMMIT) {
|
||||
git_odb_object_close(obj);
|
||||
return GIT_EOBJTYPE;
|
||||
}
|
||||
|
||||
error = commit_quick_parse(walk, commit, &obj->raw);
|
||||
git_odb_object_close(obj);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void mark_uninteresting(commit_object *commit)
|
||||
{
|
||||
unsigned short i;
|
||||
assert(commit);
|
||||
|
||||
commit->uninteresting = 1;
|
||||
|
||||
for (i = 0; i < commit->out_degree; ++i)
|
||||
if (!commit->parents[i]->uninteresting)
|
||||
mark_uninteresting(commit->parents[i]);
|
||||
}
|
||||
|
||||
static int process_commit(git_revwalk *walk, commit_object *commit)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (commit->seen)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
commit->seen = 1;
|
||||
|
||||
if ((error = commit_parse(walk, commit)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (commit->uninteresting)
|
||||
mark_uninteresting(commit);
|
||||
|
||||
return walk->enqueue(walk, commit);
|
||||
}
|
||||
|
||||
static int process_commit_parents(git_revwalk *walk, commit_object *commit)
|
||||
{
|
||||
unsigned short i;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
for (i = 0; i < commit->out_degree && error == GIT_SUCCESS; ++i) {
|
||||
error = process_commit(walk, commit->parents[i]);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
|
||||
{
|
||||
commit_object *commit;
|
||||
|
||||
commit = commit_lookup(walk, oid);
|
||||
if (commit == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
commit->uninteresting = uninteresting;
|
||||
|
||||
return process_commit(walk, commit);
|
||||
}
|
||||
|
||||
int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
|
||||
{
|
||||
assert(walk && oid);
|
||||
return push_commit(walk, oid, 0);
|
||||
}
|
||||
|
||||
int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
|
||||
{
|
||||
assert(walk && oid);
|
||||
return push_commit(walk, oid, 1);
|
||||
}
|
||||
|
||||
static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit)
|
||||
{
|
||||
return git_pqueue_insert(&walk->iterator_time, commit);
|
||||
}
|
||||
|
||||
static int revwalk_enqueue_unsorted(git_revwalk *walk, commit_object *commit)
|
||||
{
|
||||
return commit_list_insert(commit, &walk->iterator_rand) ? GIT_SUCCESS : GIT_ENOMEM;
|
||||
}
|
||||
|
||||
static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk)
|
||||
{
|
||||
int error;
|
||||
commit_object *next;
|
||||
|
||||
while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {
|
||||
if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (!next->uninteresting) {
|
||||
*object_out = next;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return GIT_EREVWALKOVER;
|
||||
}
|
||||
|
||||
static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk)
|
||||
{
|
||||
int error;
|
||||
commit_object *next;
|
||||
|
||||
while ((next = commit_list_pop(&walk->iterator_rand)) != NULL) {
|
||||
if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (!next->uninteresting) {
|
||||
*object_out = next;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return GIT_EREVWALKOVER;
|
||||
}
|
||||
|
||||
static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
|
||||
{
|
||||
commit_object *next;
|
||||
unsigned short i;
|
||||
|
||||
for (;;) {
|
||||
next = commit_list_pop(&walk->iterator_topo);
|
||||
if (next == NULL)
|
||||
return GIT_EREVWALKOVER;
|
||||
|
||||
if (next->in_degree > 0) {
|
||||
next->topo_delay = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < next->out_degree; ++i) {
|
||||
commit_object *parent = next->parents[i];
|
||||
|
||||
if (--parent->in_degree == 0 && parent->topo_delay) {
|
||||
parent->topo_delay = 0;
|
||||
commit_list_insert(parent, &walk->iterator_topo);
|
||||
}
|
||||
}
|
||||
|
||||
*object_out = next;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk)
|
||||
{
|
||||
*object_out = commit_list_pop(&walk->iterator_reverse);
|
||||
return *object_out ? GIT_SUCCESS : GIT_EREVWALKOVER;
|
||||
}
|
||||
|
||||
|
||||
static int prepare_walk(git_revwalk *walk)
|
||||
{
|
||||
int error;
|
||||
commit_object *next;
|
||||
|
||||
if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
|
||||
unsigned short i;
|
||||
|
||||
while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS) {
|
||||
for (i = 0; i < next->out_degree; ++i) {
|
||||
commit_object *parent = next->parents[i];
|
||||
parent->in_degree++;
|
||||
}
|
||||
|
||||
commit_list_insert(next, &walk->iterator_topo);
|
||||
}
|
||||
|
||||
if (error != GIT_EREVWALKOVER)
|
||||
return error;
|
||||
|
||||
walk->get_next = &revwalk_next_toposort;
|
||||
}
|
||||
|
||||
if (walk->sorting & GIT_SORT_REVERSE) {
|
||||
|
||||
while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS)
|
||||
commit_list_insert(next, &walk->iterator_reverse);
|
||||
|
||||
if (error != GIT_EREVWALKOVER)
|
||||
return error;
|
||||
|
||||
walk->get_next = &revwalk_next_reverse;
|
||||
}
|
||||
|
||||
walk->walking = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
|
||||
{
|
||||
git_revwalk *walk;
|
||||
@ -56,14 +458,21 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
|
||||
memset(walk, 0x0, sizeof(git_revwalk));
|
||||
|
||||
walk->commits = git_hashtable_alloc(64,
|
||||
git_revwalk__commit_hash,
|
||||
git_revwalk__commit_keycmp);
|
||||
object_table_hash,
|
||||
(git_hash_keyeq_ptr)git_oid_cmp);
|
||||
|
||||
if (walk->commits == NULL) {
|
||||
free(walk);
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
git_pqueue_init(&walk->iterator_time, 8, commit_time_cmp);
|
||||
git_vector_init(&walk->memory_alloc, 8, NULL);
|
||||
alloc_chunk(walk);
|
||||
|
||||
walk->get_next = &revwalk_next_unsorted;
|
||||
walk->enqueue = &revwalk_enqueue_unsorted;
|
||||
|
||||
walk->repo = repo;
|
||||
|
||||
*revwalk_out = walk;
|
||||
@ -72,11 +481,30 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
|
||||
|
||||
void git_revwalk_free(git_revwalk *walk)
|
||||
{
|
||||
unsigned int i;
|
||||
const void *_unused;
|
||||
commit_object *commit;
|
||||
|
||||
if (walk == NULL)
|
||||
return;
|
||||
|
||||
git_revwalk_reset(walk);
|
||||
|
||||
/* if the parent has more than PARENTS_PER_COMMIT parents,
|
||||
* we had to allocate a separate array for those parents.
|
||||
* make sure it's being free'd */
|
||||
GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, {
|
||||
if (commit->out_degree > PARENTS_PER_COMMIT)
|
||||
free(commit->parents);
|
||||
});
|
||||
|
||||
git_hashtable_free(walk->commits);
|
||||
git_pqueue_free(&walk->iterator_time);
|
||||
|
||||
for (i = 0; i < walk->memory_alloc.length; ++i)
|
||||
free(git_vector_get(&walk->memory_alloc, i));
|
||||
|
||||
git_vector_free(&walk->memory_alloc);
|
||||
free(walk);
|
||||
}
|
||||
|
||||
@ -86,376 +514,64 @@ git_repository *git_revwalk_repository(git_revwalk *walk)
|
||||
return walk->repo;
|
||||
}
|
||||
|
||||
int git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
|
||||
void git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
|
||||
{
|
||||
assert(walk);
|
||||
|
||||
if (walk->walking)
|
||||
return GIT_EBUSY;
|
||||
git_revwalk_reset(walk);
|
||||
|
||||
walk->sorting = sort_mode;
|
||||
git_revwalk_reset(walk);
|
||||
|
||||
if (walk->sorting & GIT_SORT_TIME) {
|
||||
walk->get_next = &revwalk_next_timesort;
|
||||
walk->enqueue = &revwalk_enqueue_timesort;
|
||||
} else {
|
||||
walk->get_next = &revwalk_next_unsorted;
|
||||
walk->enqueue = &revwalk_enqueue_unsorted;
|
||||
}
|
||||
}
|
||||
|
||||
int git_revwalk_next(git_oid *oid, git_revwalk *walk)
|
||||
{
|
||||
int error;
|
||||
commit_object *next;
|
||||
|
||||
assert(walk && oid);
|
||||
|
||||
if (!walk->walking) {
|
||||
if ((error = prepare_walk(walk)) < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = walk->get_next(&next, walk);
|
||||
if (error < GIT_SUCCESS) {
|
||||
if (error == GIT_EREVWALKOVER)
|
||||
git_revwalk_reset(walk);
|
||||
return error;
|
||||
}
|
||||
|
||||
git_oid_cpy(oid, &next->oid);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static git_revwalk_commit *commit_to_walkcommit(git_revwalk *walk, git_commit *commit_object)
|
||||
{
|
||||
git_revwalk_commit *commit;
|
||||
|
||||
commit = (git_revwalk_commit *)git_hashtable_lookup(walk->commits, commit_object);
|
||||
|
||||
if (commit != NULL)
|
||||
return commit;
|
||||
|
||||
commit = git__malloc(sizeof(git_revwalk_commit));
|
||||
if (commit == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(commit, 0x0, sizeof(git_revwalk_commit));
|
||||
|
||||
commit->commit_object = commit_object;
|
||||
GIT_OBJECT_INCREF(walk->repo, commit_object);
|
||||
|
||||
git_hashtable_insert(walk->commits, commit_object, commit);
|
||||
|
||||
return commit;
|
||||
}
|
||||
|
||||
static git_revwalk_commit *insert_commit(git_revwalk *walk, git_commit *commit_object)
|
||||
{
|
||||
git_revwalk_commit *commit;
|
||||
unsigned int i;
|
||||
|
||||
assert(walk && commit_object);
|
||||
|
||||
if (commit_object->object.repo != walk->repo || walk->walking)
|
||||
return NULL;
|
||||
|
||||
commit = commit_to_walkcommit(walk, commit_object);
|
||||
if (commit == NULL)
|
||||
return NULL;
|
||||
|
||||
if (commit->seen)
|
||||
return commit;
|
||||
|
||||
commit->seen = 1;
|
||||
|
||||
for (i = 0; i < commit->commit_object->parents.length; ++i) {
|
||||
git_commit *parent_object;
|
||||
git_revwalk_commit *parent;
|
||||
|
||||
parent_object = git_vector_get(&commit->commit_object->parents, i);
|
||||
|
||||
if ((parent = commit_to_walkcommit(walk, parent_object)) == NULL)
|
||||
return NULL;
|
||||
|
||||
parent = insert_commit(walk, parent_object);
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
|
||||
parent->in_degree++;
|
||||
|
||||
git_revwalk_list_push_back(&commit->parents, parent);
|
||||
}
|
||||
|
||||
if (git_revwalk_list_push_back(&walk->iterator, commit))
|
||||
return NULL;
|
||||
|
||||
return commit;
|
||||
}
|
||||
|
||||
int git_revwalk_push(git_revwalk *walk, git_commit *commit)
|
||||
{
|
||||
assert(walk && commit);
|
||||
return insert_commit(walk, commit) ? GIT_SUCCESS : GIT_ENOMEM;
|
||||
}
|
||||
|
||||
static void mark_uninteresting(git_revwalk_commit *commit)
|
||||
{
|
||||
git_revwalk_listnode *parent;
|
||||
|
||||
assert(commit);
|
||||
|
||||
commit->uninteresting = 1;
|
||||
parent = commit->parents.head;
|
||||
|
||||
while (parent) {
|
||||
mark_uninteresting(parent->walk_commit);
|
||||
parent = parent->next;
|
||||
}
|
||||
}
|
||||
|
||||
int git_revwalk_hide(git_revwalk *walk, git_commit *commit)
|
||||
{
|
||||
git_revwalk_commit *hide;
|
||||
|
||||
assert(walk && commit);
|
||||
|
||||
hide = insert_commit(walk, commit);
|
||||
if (hide == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
mark_uninteresting(hide);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void prepare_walk(git_revwalk *walk)
|
||||
{
|
||||
if (walk->sorting & GIT_SORT_TIME)
|
||||
git_revwalk_list_timesort(&walk->iterator);
|
||||
|
||||
if (walk->sorting & GIT_SORT_TOPOLOGICAL)
|
||||
git_revwalk_list_toposort(&walk->iterator);
|
||||
|
||||
if (walk->sorting & GIT_SORT_REVERSE)
|
||||
walk->next = &git_revwalk_list_pop_back;
|
||||
else
|
||||
walk->next = &git_revwalk_list_pop_front;
|
||||
|
||||
walk->walking = 1;
|
||||
}
|
||||
|
||||
int git_revwalk_next(git_commit **commit, git_revwalk *walk)
|
||||
{
|
||||
git_revwalk_commit *next;
|
||||
|
||||
assert(walk && commit);
|
||||
|
||||
if (!walk->walking)
|
||||
prepare_walk(walk);
|
||||
|
||||
*commit = NULL;
|
||||
|
||||
while ((next = walk->next(&walk->iterator)) != NULL) {
|
||||
if (!next->uninteresting) {
|
||||
*commit = next->commit_object;
|
||||
GIT_OBJECT_INCREF(walk->repo, *commit);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* No commits left to iterate */
|
||||
git_revwalk_reset(walk);
|
||||
return GIT_EREVWALKOVER;
|
||||
}
|
||||
|
||||
void git_revwalk_reset(git_revwalk *walk)
|
||||
{
|
||||
const void *_unused;
|
||||
git_revwalk_commit *commit;
|
||||
commit_object *commit;
|
||||
|
||||
assert(walk);
|
||||
|
||||
GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, {
|
||||
GIT_OBJECT_DECREF(walk->repo, commit->commit_object);
|
||||
git_revwalk_list_clear(&commit->parents);
|
||||
free(commit);
|
||||
});
|
||||
GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit,
|
||||
commit->seen = 0;
|
||||
commit->in_degree = 0;
|
||||
commit->topo_delay = 0;
|
||||
);
|
||||
|
||||
git_hashtable_clear(walk->commits);
|
||||
git_revwalk_list_clear(&walk->iterator);
|
||||
git_pqueue_clear(&walk->iterator_time);
|
||||
commit_list_free(&walk->iterator_topo);
|
||||
commit_list_free(&walk->iterator_rand);
|
||||
commit_list_free(&walk->iterator_reverse);
|
||||
walk->walking = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int git_revwalk_list_push_back(git_revwalk_list *list, git_revwalk_commit *commit)
|
||||
{
|
||||
git_revwalk_listnode *node = NULL;
|
||||
|
||||
node = git__malloc(sizeof(git_revwalk_listnode));
|
||||
|
||||
if (node == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
node->walk_commit = commit;
|
||||
node->next = NULL;
|
||||
node->prev = list->tail;
|
||||
|
||||
if (list->tail == NULL) {
|
||||
list->head = list->tail = node;
|
||||
} else {
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
list->size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_revwalk_list_push_front(git_revwalk_list *list, git_revwalk_commit *commit)
|
||||
{
|
||||
git_revwalk_listnode *node = NULL;
|
||||
|
||||
node = git__malloc(sizeof(git_revwalk_listnode));
|
||||
|
||||
if (node == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
node->walk_commit = commit;
|
||||
node->next = list->head;
|
||||
node->prev = NULL;
|
||||
|
||||
if (list->head == NULL) {
|
||||
list->head = list->tail = node;
|
||||
} else {
|
||||
list->head->prev = node;
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
list->size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
git_revwalk_commit *git_revwalk_list_pop_back(git_revwalk_list *list)
|
||||
{
|
||||
git_revwalk_listnode *node;
|
||||
git_revwalk_commit *commit;
|
||||
|
||||
if (list->tail == NULL)
|
||||
return NULL;
|
||||
|
||||
node = list->tail;
|
||||
list->tail = list->tail->prev;
|
||||
if (list->tail == NULL)
|
||||
list->head = NULL;
|
||||
else
|
||||
list->tail->next = NULL;
|
||||
|
||||
commit = node->walk_commit;
|
||||
free(node);
|
||||
|
||||
list->size--;
|
||||
|
||||
return commit;
|
||||
}
|
||||
|
||||
git_revwalk_commit *git_revwalk_list_pop_front(git_revwalk_list *list)
|
||||
{
|
||||
git_revwalk_listnode *node;
|
||||
git_revwalk_commit *commit;
|
||||
|
||||
if (list->head == NULL)
|
||||
return NULL;
|
||||
|
||||
node = list->head;
|
||||
list->head = list->head->next;
|
||||
if (list->head == NULL)
|
||||
list->tail = NULL;
|
||||
else
|
||||
list->head->prev = NULL;
|
||||
|
||||
commit = node->walk_commit;
|
||||
free(node);
|
||||
|
||||
list->size--;
|
||||
|
||||
return commit;
|
||||
}
|
||||
|
||||
void git_revwalk_list_clear(git_revwalk_list *list)
|
||||
{
|
||||
git_revwalk_listnode *node, *next_node;
|
||||
|
||||
node = list->head;
|
||||
while (node) {
|
||||
next_node = node->next;
|
||||
free(node);
|
||||
node = next_node;
|
||||
}
|
||||
|
||||
list->head = list->tail = NULL;
|
||||
list->size = 0;
|
||||
}
|
||||
|
||||
void git_revwalk_list_timesort(git_revwalk_list *list)
|
||||
{
|
||||
git_revwalk_listnode *p, *q, *e;
|
||||
int in_size, p_size, q_size, merge_count, i;
|
||||
|
||||
if (list->head == NULL)
|
||||
return;
|
||||
|
||||
in_size = 1;
|
||||
|
||||
do {
|
||||
p = list->head;
|
||||
list->tail = NULL;
|
||||
merge_count = 0;
|
||||
|
||||
while (p != NULL) {
|
||||
merge_count++;
|
||||
q = p;
|
||||
p_size = 0;
|
||||
q_size = in_size;
|
||||
|
||||
for (i = 0; i < in_size && q; ++i, q = q->next)
|
||||
p_size++;
|
||||
|
||||
while (p_size > 0 || (q_size > 0 && q)) {
|
||||
|
||||
if (p_size == 0)
|
||||
e = q, q = q->next, q_size--;
|
||||
|
||||
else if (q_size == 0 || q == NULL ||
|
||||
p->walk_commit->commit_object->committer->when.time >=
|
||||
q->walk_commit->commit_object->committer->when.time)
|
||||
e = p, p = p->next, p_size--;
|
||||
|
||||
else
|
||||
e = q, q = q->next, q_size--;
|
||||
|
||||
if (list->tail != NULL)
|
||||
list->tail->next = e;
|
||||
else
|
||||
list->head = e;
|
||||
|
||||
e->prev = list->tail;
|
||||
list->tail = e;
|
||||
}
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
list->tail->next = NULL;
|
||||
in_size *= 2;
|
||||
|
||||
} while (merge_count > 1);
|
||||
}
|
||||
|
||||
void git_revwalk_list_toposort(git_revwalk_list *list)
|
||||
{
|
||||
git_revwalk_commit *commit;
|
||||
git_revwalk_list topo;
|
||||
memset(&topo, 0x0, sizeof(git_revwalk_list));
|
||||
|
||||
while ((commit = git_revwalk_list_pop_back(list)) != NULL) {
|
||||
git_revwalk_listnode *p;
|
||||
|
||||
if (commit->in_degree > 0) {
|
||||
commit->topo_delay = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (p = commit->parents.head; p != NULL; p = p->next) {
|
||||
p->walk_commit->in_degree--;
|
||||
|
||||
if (p->walk_commit->in_degree == 0 && p->walk_commit->topo_delay) {
|
||||
p->walk_commit->topo_delay = 0;
|
||||
git_revwalk_list_push_back(list, p->walk_commit);
|
||||
}
|
||||
}
|
||||
|
||||
git_revwalk_list_push_back(&topo, commit);
|
||||
}
|
||||
|
||||
list->head = topo.head;
|
||||
list->tail = topo.tail;
|
||||
list->size = topo.size;
|
||||
}
|
||||
|
||||
|
@ -1,67 +0,0 @@
|
||||
#ifndef INCLUDE_revwalk_h__
|
||||
#define INCLUDE_revwalk_h__
|
||||
|
||||
#include "git2/common.h"
|
||||
#include "git2/revwalk.h"
|
||||
|
||||
#include "commit.h"
|
||||
#include "repository.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
struct git_revwalk_commit;
|
||||
|
||||
typedef struct git_revwalk_listnode {
|
||||
struct git_revwalk_commit *walk_commit;
|
||||
struct git_revwalk_listnode *next;
|
||||
struct git_revwalk_listnode *prev;
|
||||
} git_revwalk_listnode;
|
||||
|
||||
typedef struct git_revwalk_list {
|
||||
struct git_revwalk_listnode *head;
|
||||
struct git_revwalk_listnode *tail;
|
||||
size_t size;
|
||||
} git_revwalk_list;
|
||||
|
||||
|
||||
struct git_revwalk_commit {
|
||||
|
||||
git_commit *commit_object;
|
||||
git_revwalk_list parents;
|
||||
|
||||
unsigned short in_degree;
|
||||
unsigned seen:1,
|
||||
uninteresting:1,
|
||||
topo_delay:1,
|
||||
flags:25;
|
||||
};
|
||||
|
||||
typedef struct git_revwalk_commit git_revwalk_commit;
|
||||
|
||||
struct git_revwalk {
|
||||
git_repository *repo;
|
||||
|
||||
git_hashtable *commits;
|
||||
git_revwalk_list iterator;
|
||||
|
||||
git_revwalk_commit *(*next)(git_revwalk_list *);
|
||||
|
||||
unsigned walking:1;
|
||||
unsigned int sorting;
|
||||
};
|
||||
|
||||
|
||||
void git_revwalk__prepare_walk(git_revwalk *walk);
|
||||
int git_revwalk__enroot(git_revwalk *walk, git_commit *commit);
|
||||
|
||||
int git_revwalk_list_push_back(git_revwalk_list *list, git_revwalk_commit *commit);
|
||||
int git_revwalk_list_push_front(git_revwalk_list *list, git_revwalk_commit *obj);
|
||||
|
||||
git_revwalk_commit *git_revwalk_list_pop_back(git_revwalk_list *list);
|
||||
git_revwalk_commit *git_revwalk_list_pop_front(git_revwalk_list *list);
|
||||
|
||||
void git_revwalk_list_clear(git_revwalk_list *list);
|
||||
|
||||
void git_revwalk_list_timesort(git_revwalk_list *list);
|
||||
void git_revwalk_list_toposort(git_revwalk_list *list);
|
||||
|
||||
#endif /* INCLUDE_revwalk_h__ */
|
@ -38,7 +38,7 @@ void git_signature_free(git_signature *sig)
|
||||
free(sig);
|
||||
}
|
||||
|
||||
git_signature *git_signature_new(const char *name, const char *email, time_t time, int offset)
|
||||
git_signature *git_signature_new(const char *name, const char *email, git_time_t time, int offset)
|
||||
{
|
||||
git_signature *p = NULL;
|
||||
|
||||
@ -46,13 +46,7 @@ git_signature *git_signature_new(const char *name, const char *email, time_t tim
|
||||
goto cleanup;
|
||||
|
||||
p->name = git__strdup(name);
|
||||
if (p->name == NULL)
|
||||
goto cleanup;
|
||||
|
||||
p->email = git__strdup(email);
|
||||
if (p->email == NULL)
|
||||
goto cleanup;
|
||||
|
||||
p->when.time = time;
|
||||
p->when.offset = offset;
|
||||
|
||||
@ -179,10 +173,12 @@ int git_signature__parse(git_signature *sig, char **buffer_out,
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig)
|
||||
int git_signature__write(char **signature, const char *header, const git_signature *sig)
|
||||
{
|
||||
char sign;
|
||||
int offset, hours, mins;
|
||||
char sig_buffer[2048];
|
||||
int sig_buffer_len;
|
||||
char sign;
|
||||
|
||||
offset = sig->when.offset;
|
||||
sign = (sig->when.offset < 0) ? '-' : '+';
|
||||
@ -193,7 +189,16 @@ int git_signature__write(git_odb_source *src, const char *header, const git_sign
|
||||
hours = offset / 60;
|
||||
mins = offset % 60;
|
||||
|
||||
return git__source_printf(src, "%s %s <%s> %u %c%02d%02d\n", header, sig->name, sig->email, (unsigned)sig->when.time, sign, hours, mins);
|
||||
sig_buffer_len = snprintf(sig_buffer, sizeof(sig_buffer),
|
||||
"%s %s <%s> %u %c%02d%02d\n",
|
||||
header, sig->name, sig->email,
|
||||
(unsigned)sig->when.time, sign, hours, mins);
|
||||
|
||||
if (sig_buffer_len < 0 || (size_t)sig_buffer_len > sizeof(sig_buffer))
|
||||
return GIT_ENOMEM;
|
||||
|
||||
*signature = git__strdup(sig_buffer);
|
||||
return sig_buffer_len;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,6 +7,6 @@
|
||||
#include <time.h>
|
||||
|
||||
int git_signature__parse(git_signature *sig, char **buffer_out, const char *buffer_end, const char *header);
|
||||
int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig);
|
||||
int git_signature__write(char **signature, const char *header, const git_signature *sig);
|
||||
|
||||
#endif
|
||||
|
157
src/tag.c
157
src/tag.c
@ -27,7 +27,6 @@
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
#include "signature.h"
|
||||
#include "revwalk.h"
|
||||
#include "git2/object.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/signature.h"
|
||||
@ -35,7 +34,6 @@
|
||||
void git_tag__free(git_tag *tag)
|
||||
{
|
||||
git_signature_free(tag->tagger);
|
||||
GIT_OBJECT_DECREF(tag->object.repo, tag->target);
|
||||
free(tag->message);
|
||||
free(tag->tag_name);
|
||||
free(tag);
|
||||
@ -46,23 +44,16 @@ const git_oid *git_tag_id(git_tag *c)
|
||||
return git_object_id((git_object *)c);
|
||||
}
|
||||
|
||||
const git_object *git_tag_target(git_tag *t)
|
||||
int git_tag_target(git_object **target, git_tag *t)
|
||||
{
|
||||
assert(t);
|
||||
GIT_OBJECT_INCREF(t->object.repo, t->target);
|
||||
return t->target;
|
||||
return git_object_lookup(target, t->object.repo, &t->target, t->type);
|
||||
}
|
||||
|
||||
void git_tag_set_target(git_tag *tag, git_object *target)
|
||||
const git_oid *git_tag_target_oid(git_tag *t)
|
||||
{
|
||||
assert(tag && target);
|
||||
|
||||
GIT_OBJECT_DECREF(tag->object.repo, tag->target);
|
||||
GIT_OBJECT_INCREF(tag->object.repo, target);
|
||||
|
||||
tag->object.modified = 1;
|
||||
tag->target = target;
|
||||
tag->type = git_object_type(target);
|
||||
assert(t);
|
||||
return &t->target;
|
||||
}
|
||||
|
||||
git_otype git_tag_type(git_tag *t)
|
||||
@ -77,63 +68,28 @@ const char *git_tag_name(git_tag *t)
|
||||
return t->tag_name;
|
||||
}
|
||||
|
||||
void git_tag_set_name(git_tag *tag, const char *name)
|
||||
{
|
||||
assert(tag && name);
|
||||
|
||||
/* TODO: sanity check? no newlines in message */
|
||||
tag->object.modified = 1;
|
||||
|
||||
if (tag->tag_name)
|
||||
free(tag->tag_name);
|
||||
|
||||
tag->tag_name = git__strdup(name);
|
||||
}
|
||||
|
||||
const git_signature *git_tag_tagger(git_tag *t)
|
||||
{
|
||||
return t->tagger;
|
||||
}
|
||||
|
||||
void git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig)
|
||||
{
|
||||
assert(tag && tagger_sig);
|
||||
tag->object.modified = 1;
|
||||
|
||||
git_signature_free(tag->tagger);
|
||||
tag->tagger = git_signature_dup(tagger_sig);
|
||||
}
|
||||
|
||||
const char *git_tag_message(git_tag *t)
|
||||
{
|
||||
assert(t);
|
||||
return t->message;
|
||||
}
|
||||
|
||||
void git_tag_set_message(git_tag *tag, const char *message)
|
||||
{
|
||||
assert(tag && message);
|
||||
|
||||
tag->object.modified = 1;
|
||||
|
||||
if (tag->message)
|
||||
free(tag->message);
|
||||
|
||||
tag->message = git__strdup(message);
|
||||
}
|
||||
|
||||
static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
{
|
||||
static const char *tag_types[] = {
|
||||
NULL, "commit\n", "tree\n", "blob\n", "tag\n"
|
||||
};
|
||||
|
||||
git_oid target_oid;
|
||||
unsigned int i, text_len;
|
||||
char *search;
|
||||
int error;
|
||||
|
||||
if ((error = git__parse_oid(&target_oid, &buffer, buffer_end, "object ")) < 0)
|
||||
if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0)
|
||||
return error;
|
||||
|
||||
if (buffer + 5 >= buffer_end)
|
||||
@ -161,11 +117,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
if (tag->type == GIT_OBJ_BAD)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
git_object_close(tag->target);
|
||||
error = git_object_lookup(&tag->target, tag->object.repo, &target_oid, tag->type);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
if (buffer + 4 >= buffer_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
@ -188,9 +139,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
|
||||
buffer = search + 1;
|
||||
|
||||
if (tag->tagger != NULL)
|
||||
git_signature_free(tag->tagger);
|
||||
|
||||
tag->tagger = git__malloc(sizeof(git_signature));
|
||||
|
||||
if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0)
|
||||
@ -198,9 +146,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
|
||||
text_len = buffer_end - ++buffer;
|
||||
|
||||
if (tag->message != NULL)
|
||||
free(tag->message);
|
||||
|
||||
tag->message = git__malloc(text_len + 1);
|
||||
memcpy(tag->message, buffer, text_len);
|
||||
tag->message[text_len] = '\0';
|
||||
@ -208,26 +153,90 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_tag__writeback(git_tag *tag, git_odb_source *src)
|
||||
int git_tag_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_object *target,
|
||||
const git_signature *tagger,
|
||||
const char *message)
|
||||
{
|
||||
if (tag->target == NULL || tag->tag_name == NULL || tag->tagger == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
return git_tag_create(
|
||||
oid, repo, tag_name,
|
||||
git_object_id(target),
|
||||
git_object_type(target),
|
||||
tagger, message);
|
||||
}
|
||||
|
||||
git__write_oid(src, "object", git_object_id(tag->target));
|
||||
git__source_printf(src, "type %s\n", git_object_type2string(tag->type));
|
||||
git__source_printf(src, "tag %s\n", tag->tag_name);
|
||||
git_signature__write(src, "tagger", tag->tagger);
|
||||
int git_tag_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_oid *target,
|
||||
git_otype target_type,
|
||||
const git_signature *tagger,
|
||||
const char *message)
|
||||
{
|
||||
size_t final_size = 0;
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (tag->message != NULL)
|
||||
git__source_printf(src, "\n%s", tag->message);
|
||||
const char *type_str;
|
||||
char *tagger_str;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
int type_str_len, tag_name_len, tagger_str_len, message_len;
|
||||
int error;
|
||||
|
||||
|
||||
type_str = git_object_type2string(target_type);
|
||||
|
||||
tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
|
||||
|
||||
type_str_len = strlen(type_str);
|
||||
tag_name_len = strlen(tag_name);
|
||||
message_len = strlen(message);
|
||||
|
||||
final_size += GIT_OID_LINE_LENGTH("object");
|
||||
final_size += STRLEN("type ") + type_str_len + 1;
|
||||
final_size += STRLEN("tag ") + tag_name_len + 1;
|
||||
final_size += tagger_str_len;
|
||||
final_size += 1 + message_len;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_TAG)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
git__write_oid(stream, "object", target);
|
||||
|
||||
stream->write(stream, "type ", STRLEN("type "));
|
||||
stream->write(stream, type_str, type_str_len);
|
||||
|
||||
stream->write(stream, "\ntag ", STRLEN("\ntag "));
|
||||
stream->write(stream, tag_name, tag_name_len);
|
||||
stream->write(stream, "\n", 1);
|
||||
|
||||
stream->write(stream, tagger_str, tagger_str_len);
|
||||
free(tagger_str);
|
||||
|
||||
stream->write(stream, "\n", 1);
|
||||
stream->write(stream, message, message_len);
|
||||
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
if (error == GIT_SUCCESS) {
|
||||
char ref_name[512];
|
||||
git_reference *new_ref;
|
||||
git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
|
||||
error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int git_tag__parse(git_tag *tag)
|
||||
int git_tag__parse(git_tag *tag, git_odb_object *obj)
|
||||
{
|
||||
assert(tag && tag->object.source.open);
|
||||
return parse_tag_buffer(tag, tag->object.source.raw.data, (char *)tag->object.source.raw.data + tag->object.source.raw.len);
|
||||
assert(tag);
|
||||
return parse_tag_buffer(tag, obj->raw.data, (char *)obj->raw.data + obj->raw.len);
|
||||
}
|
||||
|
||||
|
@ -3,19 +3,20 @@
|
||||
|
||||
#include "git2/tag.h"
|
||||
#include "repository.h"
|
||||
#include "odb.h"
|
||||
|
||||
struct git_tag {
|
||||
git_object object;
|
||||
|
||||
git_object *target;
|
||||
git_oid target;
|
||||
git_otype type;
|
||||
|
||||
char *tag_name;
|
||||
git_signature *tagger;
|
||||
char *message;
|
||||
};
|
||||
|
||||
void git_tag__free(git_tag *tag);
|
||||
int git_tag__parse(git_tag *tag);
|
||||
int git_tag__writeback(git_tag *tag, git_odb_source *src);
|
||||
int git_tag__parse(git_tag *tag, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
@ -1,107 +1,100 @@
|
||||
#ifndef INCLUDE_thread_utils_h__
|
||||
#define INCLUDE_thread_utils_h__
|
||||
|
||||
#if defined(GIT_HAS_PTHREAD)
|
||||
typedef pthread_t git_thread;
|
||||
# define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg)
|
||||
# define git_thread_kill(thread) pthread_cancel(thread)
|
||||
# define git_thread_exit(status) pthread_exit(status)
|
||||
# define git_thread_join(id, status) pthread_join(id, status)
|
||||
|
||||
/* Pthreads Mutex */
|
||||
typedef pthread_mutex_t git_lck;
|
||||
# define GITLCK_INIT PTHREAD_MUTEX_INITIALIZER
|
||||
# define gitlck_init(a) pthread_mutex_init(a, NULL)
|
||||
# define gitlck_lock(a) pthread_mutex_lock(a)
|
||||
# define gitlck_unlock(a) pthread_mutex_unlock(a)
|
||||
# define gitlck_free(a) pthread_mutex_destroy(a)
|
||||
|
||||
/* Pthreads condition vars */
|
||||
typedef pthread_cond_t git_cnd;
|
||||
# define GITCND_INIT PTHREAD_COND_INITIALIZER
|
||||
# define gitcnd_init(c, a) pthread_cond_init(c, a)
|
||||
# define gitcnd_free(c) pthread_cond_destroy(c)
|
||||
# define gitcnd_wait(c, l) pthread_cond_wait(c, l)
|
||||
# define gitcnd_signal(c) pthread_cond_signal(c)
|
||||
# define gitcnd_broadcast(c) pthread_cond_broadcast(c)
|
||||
/* Common operations even if threading has been disabled */
|
||||
typedef struct {
|
||||
#if defined(_MSC_VER)
|
||||
volatile long val;
|
||||
#else
|
||||
volatile int val;
|
||||
#endif
|
||||
} git_atomic;
|
||||
|
||||
# if defined(GIT_HAS_ASM_ATOMIC)
|
||||
# include <asm/atomic.h>
|
||||
typedef atomic_t git_refcnt;
|
||||
# define gitrc_init(a, v) atomic_set(a, v)
|
||||
# define gitrc_inc(a) atomic_inc_return(a)
|
||||
# define gitrc_dec(a) atomic_dec_and_test(a)
|
||||
# define gitrc_free(a) (void)0
|
||||
# elif defined(GIT_WIN32)
|
||||
typedef long git_refcnt;
|
||||
# define gitrc_init(a, v) (*a = v)
|
||||
# define gitrc_inc(a) (InterlockedIncrement(a))
|
||||
# define gitrc_dec(a) (!InterlockedDecrement(a))
|
||||
# define gitrc_free(a) (void)0
|
||||
# else
|
||||
typedef struct { git_lck lock; int counter; } git_refcnt;
|
||||
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
|
||||
{
|
||||
a->val = val;
|
||||
}
|
||||
|
||||
/** Initialize to 0. No memory barrier is issued. */
|
||||
GIT_INLINE(void) gitrc_init(git_refcnt *p, int value)
|
||||
{
|
||||
gitlck_init(&p->lock);
|
||||
p->counter = value;
|
||||
}
|
||||
#ifdef GIT_THREADS
|
||||
|
||||
/**
|
||||
* Increment.
|
||||
*
|
||||
* Atomically increments @p by 1. A memory barrier is also
|
||||
* issued before and after the operation.
|
||||
*
|
||||
* @param p pointer of type git_refcnt
|
||||
*/
|
||||
GIT_INLINE(void) gitrc_inc(git_refcnt *p)
|
||||
{
|
||||
gitlck_lock(&p->lock);
|
||||
p->counter++;
|
||||
gitlck_unlock(&p->lock);
|
||||
}
|
||||
#define git_thread pthread_t
|
||||
#define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg)
|
||||
#define git_thread_kill(thread) pthread_cancel(thread)
|
||||
#define git_thread_exit(status) pthread_exit(status)
|
||||
#define git_thread_join(id, status) pthread_join(id, status)
|
||||
|
||||
/**
|
||||
* Decrement and test.
|
||||
*
|
||||
* Atomically decrements @p by 1 and returns true if the
|
||||
* result is 0, or false for all other cases. A memory
|
||||
* barrier is also issued before and after the operation.
|
||||
*
|
||||
* @param p pointer of type git_refcnt
|
||||
*/
|
||||
GIT_INLINE(int) gitrc_dec(git_refcnt *p)
|
||||
{
|
||||
int c;
|
||||
gitlck_lock(&p->lock);
|
||||
c = --p->counter;
|
||||
gitlck_unlock(&p->lock);
|
||||
return !c;
|
||||
}
|
||||
/* Pthreads Mutex */
|
||||
#define git_mutex pthread_mutex_t
|
||||
#define git_mutex_init(a) pthread_mutex_init(a, NULL)
|
||||
#define git_mutex_lock(a) pthread_mutex_lock(a)
|
||||
#define git_mutex_unlock(a) pthread_mutex_unlock(a)
|
||||
#define git_mutex_free(a) pthread_mutex_destroy(a)
|
||||
|
||||
/** Free any resources associated with the counter. */
|
||||
# define gitrc_free(p) gitlck_free(&(p)->lock)
|
||||
# endif
|
||||
/* Pthreads condition vars -- disabled by now */
|
||||
#define git_cond unsigned int //pthread_cond_t
|
||||
#define git_cond_init(c, a) (void)0 //pthread_cond_init(c, a)
|
||||
#define git_cond_free(c) (void)0 //pthread_cond_destroy(c)
|
||||
#define git_cond_wait(c, l) (void)0 //pthread_cond_wait(c, l)
|
||||
#define git_cond_signal(c) (void)0 //pthread_cond_signal(c)
|
||||
#define git_cond_broadcast(c) (void)0 //pthread_cond_broadcast(c)
|
||||
|
||||
#elif defined(GIT_THREADS)
|
||||
# error GIT_THREADS but no git_lck implementation
|
||||
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __sync_add_and_fetch(&a->val, 1);
|
||||
#elif defined(_MSC_VER)
|
||||
return InterlockedIncrement(&a->val);
|
||||
#else
|
||||
# error "Unsupported architecture for atomic operations"
|
||||
#endif
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __sync_sub_and_fetch(&a->val, 1);
|
||||
#elif defined(_MSC_VER)
|
||||
return InterlockedDecrement(&a->val);
|
||||
#else
|
||||
# error "Unsupported architecture for atomic operations"
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
/* no threads support */
|
||||
typedef struct { int dummy; } git_lck;
|
||||
# define GIT_MUTEX_INIT {}
|
||||
# define gitlck_init(a) (void)0
|
||||
# define gitlck_lock(a) (void)0
|
||||
# define gitlck_unlock(a) (void)0
|
||||
# define gitlck_free(a) (void)0
|
||||
|
||||
typedef struct { int counter; } git_refcnt;
|
||||
# define gitrc_init(a,v) ((a)->counter = v)
|
||||
# define gitrc_inc(a) ((a)->counter++)
|
||||
# define gitrc_dec(a) (--(a)->counter == 0)
|
||||
# define gitrc_free(a) (void)0
|
||||
#define git_thread unsigned int
|
||||
#define git_thread_create(thread, attr, start_routine, arg) (void)0
|
||||
#define git_thread_kill(thread) (void)0
|
||||
#define git_thread_exit(status) (void)0
|
||||
#define git_thread_join(id, status) (void)0
|
||||
|
||||
/* Pthreads Mutex */
|
||||
#define git_mutex unsigned int
|
||||
#define git_mutex_init(a) (void)0
|
||||
#define git_mutex_lock(a) (void)0
|
||||
#define git_mutex_unlock(a) (void)0
|
||||
#define git_mutex_free(a) (void)0
|
||||
|
||||
/* Pthreads condition vars */
|
||||
#define git_cond unsigned int
|
||||
#define git_cond_init(c, a) (void)0
|
||||
#define git_cond_free(c) (void)0
|
||||
#define git_cond_wait(c, l) (void)0
|
||||
#define git_cond_signal(c) (void)0
|
||||
#define git_cond_broadcast(c) (void)0
|
||||
|
||||
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
|
||||
{
|
||||
return ++a->val;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
|
||||
{
|
||||
return --a->val;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern int git_online_cpus(void);
|
||||
|
192
src/tree.c
192
src/tree.c
@ -25,7 +25,6 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "commit.h"
|
||||
#include "revwalk.h"
|
||||
#include "tree.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/object.h"
|
||||
@ -42,9 +41,11 @@ int entry_search_cmp(const void *key, const void *array_member)
|
||||
return strcmp(filename, entry->filename);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int valid_attributes(const int attributes) {
|
||||
return attributes >= 0 && attributes <= MAX_FILEMODE;
|
||||
}
|
||||
#endif
|
||||
|
||||
int entry_sort_cmp(const void *a, const void *b)
|
||||
{
|
||||
@ -57,13 +58,10 @@ int entry_sort_cmp(const void *a, const void *b)
|
||||
entry_b->attr & 040000);
|
||||
}
|
||||
|
||||
void git_tree_clear_entries(git_tree *tree)
|
||||
void git_tree__free(git_tree *tree)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (tree == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < tree->entries.length; ++i) {
|
||||
git_tree_entry *e;
|
||||
e = git_vector_get(&tree->entries, i);
|
||||
@ -72,32 +70,6 @@ void git_tree_clear_entries(git_tree *tree)
|
||||
free(e);
|
||||
}
|
||||
|
||||
git_vector_clear(&tree->entries);
|
||||
tree->object.modified = 1;
|
||||
}
|
||||
|
||||
|
||||
git_tree *git_tree__new(void)
|
||||
{
|
||||
git_tree *tree;
|
||||
|
||||
tree = git__malloc(sizeof(struct git_tree));
|
||||
if (tree == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(tree, 0x0, sizeof(struct git_tree));
|
||||
|
||||
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) {
|
||||
free(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void git_tree__free(git_tree *tree)
|
||||
{
|
||||
git_tree_clear_entries(tree);
|
||||
git_vector_free(&tree->entries);
|
||||
free(tree);
|
||||
}
|
||||
@ -107,37 +79,6 @@ const git_oid *git_tree_id(git_tree *c)
|
||||
return git_object_id((git_object *)c);
|
||||
}
|
||||
|
||||
int git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr)
|
||||
{
|
||||
assert(entry && entry->owner);
|
||||
|
||||
if (!valid_attributes(attr)) {
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
entry->attr = attr;
|
||||
entry->owner->object.modified = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_tree_entry_set_name(git_tree_entry *entry, const char *name)
|
||||
{
|
||||
assert(entry && entry->owner);
|
||||
|
||||
free(entry->filename);
|
||||
entry->filename = git__strdup(name);
|
||||
git_vector_sort(&entry->owner->entries);
|
||||
entry->owner->object.modified = 1;
|
||||
}
|
||||
|
||||
void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid)
|
||||
{
|
||||
assert(entry && entry->owner);
|
||||
|
||||
git_oid_cpy(&entry->oid, oid);
|
||||
entry->owner->object.modified = 1;
|
||||
}
|
||||
|
||||
unsigned int git_tree_entry_attributes(git_tree_entry *entry)
|
||||
{
|
||||
return entry->attr;
|
||||
@ -155,15 +96,10 @@ const git_oid *git_tree_entry_id(git_tree_entry *entry)
|
||||
return &entry->oid;
|
||||
}
|
||||
|
||||
int git_tree_entry_2object(git_object **object_out, git_tree_entry *entry)
|
||||
int git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry)
|
||||
{
|
||||
assert(entry && object_out);
|
||||
return git_object_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);
|
||||
}
|
||||
|
||||
static void sort_entries(git_tree *tree)
|
||||
{
|
||||
git_vector_sort(&tree->entries);
|
||||
return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY);
|
||||
}
|
||||
|
||||
git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||
@ -172,8 +108,6 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||
|
||||
assert(tree && filename);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
|
||||
if (idx == GIT_ENOTFOUND)
|
||||
return NULL;
|
||||
@ -184,9 +118,6 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||
git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
|
||||
{
|
||||
assert(tree);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
return git_vector_get(&tree->entries, (unsigned int)idx);
|
||||
}
|
||||
|
||||
@ -196,107 +127,12 @@ size_t git_tree_entrycount(git_tree *tree)
|
||||
return tree->entries.length;
|
||||
}
|
||||
|
||||
int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)
|
||||
{
|
||||
git_tree_entry *entry;
|
||||
|
||||
assert(tree && id && filename);
|
||||
if (!valid_attributes(attributes)) {
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memset(entry, 0x0, sizeof(git_tree_entry));
|
||||
|
||||
entry->filename = git__strdup(filename);
|
||||
git_oid_cpy(&entry->oid, id);
|
||||
entry->attr = attributes;
|
||||
entry->owner = tree;
|
||||
|
||||
if (git_vector_insert(&tree->entries, entry) < 0)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
if (entry_out != NULL)
|
||||
*entry_out = entry;
|
||||
|
||||
tree->object.modified = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_tree_remove_entry_byindex(git_tree *tree, int idx)
|
||||
{
|
||||
git_tree_entry *remove_ptr;
|
||||
|
||||
assert(tree);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
remove_ptr = git_vector_get(&tree->entries, (unsigned int)idx);
|
||||
if (remove_ptr == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
free(remove_ptr->filename);
|
||||
free(remove_ptr);
|
||||
|
||||
tree->object.modified = 1;
|
||||
|
||||
return git_vector_remove(&tree->entries, (unsigned int)idx);
|
||||
}
|
||||
|
||||
int git_tree_remove_entry_byname(git_tree *tree, const char *filename)
|
||||
{
|
||||
int idx;
|
||||
|
||||
assert(tree && filename);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
|
||||
if (idx == GIT_ENOTFOUND)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return git_tree_remove_entry_byindex(tree, idx);
|
||||
}
|
||||
|
||||
int git_tree__writeback(git_tree *tree, git_odb_source *src)
|
||||
{
|
||||
size_t i;
|
||||
char filemode[MAX_FILEMODE_BYTES + 1 + 1];
|
||||
|
||||
assert(tree && src);
|
||||
|
||||
if (tree->entries.length == 0)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
for (i = 0; i < tree->entries.length; ++i) {
|
||||
git_tree_entry *entry;
|
||||
|
||||
entry = git_vector_get(&tree->entries, i);
|
||||
|
||||
snprintf(filemode, sizeof(filemode), "%o ", entry->attr);
|
||||
|
||||
git__source_write(src, filemode, strlen(filemode));
|
||||
git__source_write(src, entry->filename, strlen(entry->filename) + 1);
|
||||
git__source_write(src, entry->oid.id, GIT_OID_RAWSZ);
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
|
||||
{
|
||||
static const size_t avg_entry_size = 40;
|
||||
unsigned int expected_size;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
expected_size = (tree->object.source.raw.len / avg_entry_size) + 1;
|
||||
|
||||
git_tree_clear_entries(tree);
|
||||
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
while (buffer < buffer_end) {
|
||||
git_tree_entry *entry;
|
||||
@ -310,7 +146,6 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
|
||||
if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
entry->owner = tree;
|
||||
entry->attr = strtol(buffer, &buffer, 8);
|
||||
|
||||
if (*buffer++ != ' ') {
|
||||
@ -337,16 +172,9 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_tree__parse(git_tree *tree)
|
||||
int git_tree__parse(git_tree *tree, git_odb_object *obj)
|
||||
{
|
||||
char *buffer, *buffer_end;
|
||||
|
||||
assert(tree && tree->object.source.open);
|
||||
assert(!tree->object.in_memory);
|
||||
|
||||
buffer = tree->object.source.raw.data;
|
||||
buffer_end = buffer + tree->object.source.raw.len;
|
||||
|
||||
return tree_parse_buffer(tree, buffer, buffer_end);
|
||||
assert(tree);
|
||||
return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,13 @@
|
||||
|
||||
#include "git2/tree.h"
|
||||
#include "repository.h"
|
||||
#include "odb.h"
|
||||
#include "vector.h"
|
||||
|
||||
struct git_tree_entry {
|
||||
unsigned int attr;
|
||||
char *filename;
|
||||
git_oid oid;
|
||||
|
||||
git_tree *owner;
|
||||
};
|
||||
|
||||
struct git_tree {
|
||||
@ -19,8 +18,6 @@ struct git_tree {
|
||||
};
|
||||
|
||||
void git_tree__free(git_tree *tree);
|
||||
git_tree *git_tree__new(void);
|
||||
int git_tree__parse(git_tree *tree);
|
||||
int git_tree__writeback(git_tree *tree, git_odb_source *src);
|
||||
int git_tree__parse(git_tree *tree, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
12
src/util.c
12
src/util.c
@ -3,6 +3,15 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void git_strarray_free(git_strarray *array)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < array->count; ++i)
|
||||
free(array->strings[i]);
|
||||
|
||||
free(array->strings);
|
||||
}
|
||||
|
||||
int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
@ -214,6 +223,9 @@ void git__joinpath_n(char *buffer_out, int count, ...)
|
||||
int len;
|
||||
|
||||
path = va_arg(ap, const char *);
|
||||
|
||||
assert((i == 0) || path != buffer_start);
|
||||
|
||||
if (i > 0 && *path == '/' && buffer_out > buffer_start && buffer_out[-1] == '/')
|
||||
path++;
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define INCLUDE_util_h__
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
|
||||
#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))
|
||||
|
||||
/*
|
||||
* Don't wrap malloc/calloc.
|
||||
@ -93,6 +95,10 @@ 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);
|
||||
|
||||
#define STRLEN(str) (sizeof(str) - 1)
|
||||
|
||||
#define GIT_OID_LINE_LENGTH(header) (STRLEN(header) + 1 + GIT_OID_HEXSZ + 1)
|
||||
|
||||
/*
|
||||
* Realloc the buffer pointed at by variable 'x' so that it can hold
|
||||
* at least 'nr' entries; the number of entries currently allocated
|
||||
|
86
src/win32/pthread.c
Normal file
86
src/win32/pthread.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Original code by Ramiro Polla (Public Domain)
|
||||
*/
|
||||
|
||||
#include "pthread.h"
|
||||
|
||||
int pthread_create(pthread_t *GIT_RESTRICT thread,
|
||||
const pthread_attr_t *GIT_RESTRICT GIT_UNUSED(attr),
|
||||
void *(*start_routine)(void*), void *GIT_RESTRICT arg)
|
||||
{
|
||||
GIT_UNUSED_ARG(attr);
|
||||
*thread = (pthread_t) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
|
||||
return *thread ? GIT_SUCCESS : GIT_EOSERR;
|
||||
}
|
||||
|
||||
int pthread_join(pthread_t thread, void **value_ptr)
|
||||
{
|
||||
int ret;
|
||||
ret = WaitForSingleObject(thread, INFINITE);
|
||||
if (ret && value_ptr)
|
||||
GetExitCodeThread(thread, (void*) value_ptr);
|
||||
return -(!!ret);
|
||||
}
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex,
|
||||
const pthread_mutexattr_t *GIT_RESTRICT GIT_UNUSED(mutexattr))
|
||||
{
|
||||
GIT_UNUSED_ARG(mutexattr);
|
||||
InitializeCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
int ret;
|
||||
ret = CloseHandle(mutex);
|
||||
return -(!ret);
|
||||
}
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
EnterCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
LeaveCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_num_processors_np(void)
|
||||
{
|
||||
DWORD_PTR p, s;
|
||||
int n = 0;
|
||||
|
||||
if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s))
|
||||
for (; p; p >>= 1)
|
||||
n += p&1;
|
||||
|
||||
return n ? n : 1;
|
||||
}
|
||||
|
60
src/win32/pthread.h
Normal file
60
src/win32/pthread.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Original code by Ramiro Polla (Public Domain)
|
||||
*/
|
||||
|
||||
#ifndef GIT_PTHREAD_H
|
||||
#define GIT_PTHREAD_H
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
# define GIT_RESTRICT __restrict
|
||||
#else
|
||||
# define GIT_RESTRICT __restrict__
|
||||
#endif
|
||||
|
||||
typedef int pthread_mutexattr_t;
|
||||
typedef int pthread_condattr_t;
|
||||
typedef int pthread_attr_t;
|
||||
typedef CRITICAL_SECTION pthread_mutex_t;
|
||||
typedef HANDLE pthread_t;
|
||||
|
||||
#define PTHREAD_MUTEX_INITIALIZER {(void*)-1};
|
||||
|
||||
int pthread_create(pthread_t *GIT_RESTRICT,
|
||||
const pthread_attr_t *GIT_RESTRICT,
|
||||
void *(*start_routine)(void*), void *__restrict);
|
||||
|
||||
int pthread_join(pthread_t, void **);
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT);
|
||||
int pthread_mutex_destroy(pthread_mutex_t *);
|
||||
int pthread_mutex_lock(pthread_mutex_t *);
|
||||
int pthread_mutex_unlock(pthread_mutex_t *);
|
||||
|
||||
int pthread_num_processors_np(void);
|
||||
|
||||
#endif
|
BIN
tests/resources/empty_bare.git/HEAD
Normal file
BIN
tests/resources/empty_bare.git/HEAD
Normal file
Binary file not shown.
BIN
tests/resources/empty_bare.git/config
Normal file
BIN
tests/resources/empty_bare.git/config
Normal file
Binary file not shown.
BIN
tests/resources/empty_bare.git/description
Normal file
BIN
tests/resources/empty_bare.git/description
Normal file
Binary file not shown.
BIN
tests/resources/empty_bare.git/info/exclude
Normal file
BIN
tests/resources/empty_bare.git/info/exclude
Normal file
Binary file not shown.
BIN
tests/resources/empty_standard_repo/.gitted/HEAD
Normal file
BIN
tests/resources/empty_standard_repo/.gitted/HEAD
Normal file
Binary file not shown.
BIN
tests/resources/empty_standard_repo/.gitted/config
Normal file
BIN
tests/resources/empty_standard_repo/.gitted/config
Normal file
Binary file not shown.
BIN
tests/resources/empty_standard_repo/.gitted/description
Normal file
BIN
tests/resources/empty_standard_repo/.gitted/description
Normal file
Binary file not shown.
BIN
tests/resources/empty_standard_repo/.gitted/info/exclude
Normal file
BIN
tests/resources/empty_standard_repo/.gitted/info/exclude
Normal file
Binary file not shown.
370
tests/t00-core.c
370
tests/t00-core.c
@ -27,17 +27,6 @@
|
||||
#include "vector.h"
|
||||
#include "fileops.h"
|
||||
|
||||
BEGIN_TEST(refcnt0, "increment refcount twice, decrement twice")
|
||||
git_refcnt p;
|
||||
|
||||
gitrc_init(&p, 0);
|
||||
gitrc_inc(&p);
|
||||
gitrc_inc(&p);
|
||||
must_be_true(!gitrc_dec(&p));
|
||||
must_be_true(gitrc_dec(&p));
|
||||
gitrc_free(&p);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(string0, "compare prefixes")
|
||||
must_be_true(git__prefixcmp("", "") == 0);
|
||||
must_be_true(git__prefixcmp("a", "") == 0);
|
||||
@ -162,187 +151,204 @@ BEGIN_TEST(path2, "get the latest component in a path")
|
||||
#undef TOPDIR_TEST
|
||||
END_TEST
|
||||
|
||||
typedef int (normalize_path)(char *, const char *);
|
||||
typedef int (normalize_path)(char *, size_t, const char *);
|
||||
|
||||
static int ensure_normalized(const char *input_path, const char *expected_path, normalize_path normalizer)
|
||||
/* Assert flags */
|
||||
#define CWD_AS_PREFIX 1
|
||||
#define PATH_AS_SUFFIX 2
|
||||
#define ROOTED_PATH 4
|
||||
|
||||
static int ensure_normalized(const char *input_path, const char *expected_path, normalize_path normalizer, int assert_flags)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
char buffer_out[GIT_PATH_MAX];
|
||||
char current_workdir[GIT_PATH_MAX];
|
||||
|
||||
error = normalizer(buffer_out, input_path);
|
||||
error = gitfo_getcwd(current_workdir, sizeof(current_workdir));
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
error = normalizer(buffer_out, sizeof(buffer_out), input_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (expected_path == NULL)
|
||||
return error;
|
||||
|
||||
if (strcmp(buffer_out, expected_path))
|
||||
error = GIT_ERROR;
|
||||
if ((assert_flags & PATH_AS_SUFFIX) != 0)
|
||||
if (git__suffixcmp(buffer_out, expected_path))
|
||||
return GIT_ERROR;
|
||||
|
||||
if ((assert_flags & CWD_AS_PREFIX) != 0)
|
||||
if (git__prefixcmp(buffer_out, current_workdir))
|
||||
return GIT_ERROR;
|
||||
|
||||
if ((assert_flags & ROOTED_PATH) != 0) {
|
||||
error = strcmp(expected_path, buffer_out);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ensure_dir_path_normalized(const char *input_path, const char *expected_path)
|
||||
static int ensure_dir_path_normalized(const char *input_path, const char *expected_path, int assert_flags)
|
||||
{
|
||||
return ensure_normalized(input_path, expected_path, gitfo_prettify_dir_path);
|
||||
return ensure_normalized(input_path, expected_path, gitfo_prettify_dir_path, assert_flags);
|
||||
}
|
||||
|
||||
static int ensure_file_path_normalized(const char *input_path, const char *expected_path)
|
||||
static int ensure_file_path_normalized(const char *input_path, const char *expected_path, int assert_flags)
|
||||
{
|
||||
return ensure_normalized(input_path, expected_path, gitfo_prettify_file_path);
|
||||
return ensure_normalized(input_path, expected_path, gitfo_prettify_file_path, assert_flags);
|
||||
}
|
||||
|
||||
BEGIN_TEST(path3, "prettify and validate a path to a file")
|
||||
must_pass(ensure_file_path_normalized("a", "a"));
|
||||
must_pass(ensure_file_path_normalized("./testrepo.git", "testrepo.git"));
|
||||
must_pass(ensure_file_path_normalized("./.git", ".git"));
|
||||
must_pass(ensure_file_path_normalized("./git.", "git."));
|
||||
must_fail(ensure_file_path_normalized("git./", NULL));
|
||||
must_fail(ensure_file_path_normalized("", NULL));
|
||||
must_fail(ensure_file_path_normalized(".", NULL));
|
||||
must_fail(ensure_file_path_normalized("./", NULL));
|
||||
must_fail(ensure_file_path_normalized("./.", NULL));
|
||||
must_fail(ensure_file_path_normalized("./..", NULL));
|
||||
must_fail(ensure_file_path_normalized("../.", NULL));
|
||||
must_fail(ensure_file_path_normalized("./.././/", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/..", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../..", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/..///..", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub///../..", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub///..///..", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../../..", NULL));
|
||||
must_pass(ensure_file_path_normalized("dir", "dir"));
|
||||
must_fail(ensure_file_path_normalized("dir//", NULL));
|
||||
must_pass(ensure_file_path_normalized("./dir", "dir"));
|
||||
must_fail(ensure_file_path_normalized("dir/.", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir///./", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/..", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir//sub/..",NULL));
|
||||
must_fail(ensure_file_path_normalized("dir//sub/../", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../.", NULL));
|
||||
must_fail(ensure_file_path_normalized("dir/s1/../s2/", NULL));
|
||||
must_fail(ensure_file_path_normalized("d1/s1///s2/..//../s3/", NULL));
|
||||
must_pass(ensure_file_path_normalized("d1/s1//../s2/../../d2", "d2"));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../", NULL));
|
||||
must_fail(ensure_file_path_normalized("....", NULL));
|
||||
must_fail(ensure_file_path_normalized("...", NULL));
|
||||
must_fail(ensure_file_path_normalized("./...", NULL));
|
||||
must_fail(ensure_file_path_normalized("d1/...", NULL));
|
||||
must_fail(ensure_file_path_normalized("d1/.../", NULL));
|
||||
must_fail(ensure_file_path_normalized("d1/.../d2", NULL));
|
||||
must_pass(ensure_file_path_normalized("a", "a", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_file_path_normalized("./testrepo.git", "testrepo.git", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_file_path_normalized("./.git", ".git", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_file_path_normalized("./git.", "git.", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_fail(ensure_file_path_normalized("git./", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized(".", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("./", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("./.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("./..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("../.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("./.././/", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/..///..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub///../..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub///..///..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../../..", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("dir", "dir", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_fail(ensure_file_path_normalized("dir//", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("./dir", "dir", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_fail(ensure_file_path_normalized("dir/.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir///./", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir//sub/..",NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir//sub/../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("dir/s1/../s2/", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("d1/s1///s2/..//../s3/", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("d1/s1//../s2/../../d2", "d2", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_fail(ensure_file_path_normalized("dir/sub/../", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("../../a/../../b/c/d/../../e", "b/e", PATH_AS_SUFFIX));
|
||||
must_fail(ensure_file_path_normalized("....", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("...", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("./...", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("d1/...", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("d1/.../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("d1/.../d2", NULL, 0));
|
||||
|
||||
must_pass(ensure_file_path_normalized("/a", "/a"));
|
||||
must_pass(ensure_file_path_normalized("/./testrepo.git", "/testrepo.git"));
|
||||
must_pass(ensure_file_path_normalized("/./.git", "/.git"));
|
||||
must_pass(ensure_file_path_normalized("/./git.", "/git."));
|
||||
must_fail(ensure_file_path_normalized("/git./", NULL));
|
||||
must_fail(ensure_file_path_normalized("/", NULL));
|
||||
must_fail(ensure_file_path_normalized("/.", NULL));
|
||||
must_fail(ensure_file_path_normalized("/./", NULL));
|
||||
must_fail(ensure_file_path_normalized("/./.", NULL));
|
||||
must_fail(ensure_file_path_normalized("/./..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/../.", NULL));
|
||||
must_fail(ensure_file_path_normalized("/./.././/", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/..///..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub///../..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub///..///..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../../..", NULL));
|
||||
must_pass(ensure_file_path_normalized("/dir", "/dir"));
|
||||
must_fail(ensure_file_path_normalized("/dir//", NULL));
|
||||
must_pass(ensure_file_path_normalized("/./dir", "/dir"));
|
||||
must_fail(ensure_file_path_normalized("/dir/.", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir///./", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/..", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir//sub/..",NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir//sub/../", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../.", NULL));
|
||||
must_fail(ensure_file_path_normalized("/dir/s1/../s2/", NULL));
|
||||
must_fail(ensure_file_path_normalized("/d1/s1///s2/..//../s3/", NULL));
|
||||
must_pass(ensure_file_path_normalized("/d1/s1//../s2/../../d2", "/d2"));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../", NULL));
|
||||
must_fail(ensure_file_path_normalized("/....", NULL));
|
||||
must_fail(ensure_file_path_normalized("/...", NULL));
|
||||
must_fail(ensure_file_path_normalized("/./...", NULL));
|
||||
must_fail(ensure_file_path_normalized("/d1/...", NULL));
|
||||
must_fail(ensure_file_path_normalized("/d1/.../", NULL));
|
||||
must_fail(ensure_file_path_normalized("/d1/.../d2", NULL));
|
||||
must_pass(ensure_file_path_normalized("/a", "/a", ROOTED_PATH));
|
||||
must_pass(ensure_file_path_normalized("/./testrepo.git", "/testrepo.git", ROOTED_PATH));
|
||||
must_pass(ensure_file_path_normalized("/./.git", "/.git", ROOTED_PATH));
|
||||
must_pass(ensure_file_path_normalized("/./git.", "/git.", ROOTED_PATH));
|
||||
must_fail(ensure_file_path_normalized("/git./", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/./", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/./.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/./..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/../.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/./.././/", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/..///..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub///../..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub///..///..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../../..", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("/dir", "/dir", 0));
|
||||
must_fail(ensure_file_path_normalized("/dir//", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("/./dir", "/dir", 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir///./", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/..", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir//sub/..",NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir//sub/../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../.", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/s1/../s2/", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/d1/s1///s2/..//../s3/", NULL, 0));
|
||||
must_pass(ensure_file_path_normalized("/d1/s1//../s2/../../d2", "/d2", 0));
|
||||
must_fail(ensure_file_path_normalized("/dir/sub/../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/....", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/...", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/./...", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/d1/...", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/d1/.../", NULL, 0));
|
||||
must_fail(ensure_file_path_normalized("/d1/.../d2", NULL, 0));
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(path4, "validate and prettify a path to a folder")
|
||||
must_pass(ensure_dir_path_normalized("./testrepo.git", "testrepo.git/"));
|
||||
must_pass(ensure_dir_path_normalized("./.git", ".git/"));
|
||||
must_pass(ensure_dir_path_normalized("./git.", "git./"));
|
||||
must_pass(ensure_dir_path_normalized("git./", "git./"));
|
||||
must_pass(ensure_dir_path_normalized("", ""));
|
||||
must_pass(ensure_dir_path_normalized(".", ""));
|
||||
must_pass(ensure_dir_path_normalized("./", ""));
|
||||
must_pass(ensure_dir_path_normalized("./.", ""));
|
||||
must_fail(ensure_dir_path_normalized("./..", NULL));
|
||||
must_fail(ensure_dir_path_normalized("../.", NULL));
|
||||
must_fail(ensure_dir_path_normalized("./.././/", NULL));
|
||||
must_pass(ensure_dir_path_normalized("dir/..", ""));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../..", ""));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/..///..", ""));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub///../..", ""));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub///..///..", ""));
|
||||
must_fail(ensure_dir_path_normalized("dir/sub/../../..", NULL));
|
||||
must_pass(ensure_dir_path_normalized("dir", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir//", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("./dir", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir/.", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir///./", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/..", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir//sub/..", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir//sub/../", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../.", "dir/"));
|
||||
must_pass(ensure_dir_path_normalized("dir/s1/../s2/", "dir/s2/"));
|
||||
must_pass(ensure_dir_path_normalized("d1/s1///s2/..//../s3/", "d1/s3/"));
|
||||
must_pass(ensure_dir_path_normalized("d1/s1//../s2/../../d2", "d2/"));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/"));
|
||||
must_fail(ensure_dir_path_normalized("....", NULL));
|
||||
must_fail(ensure_dir_path_normalized("...", NULL));
|
||||
must_fail(ensure_dir_path_normalized("./...", NULL));
|
||||
must_fail(ensure_dir_path_normalized("d1/...", NULL));
|
||||
must_fail(ensure_dir_path_normalized("d1/.../", NULL));
|
||||
must_fail(ensure_dir_path_normalized("d1/.../d2", NULL));
|
||||
must_pass(ensure_dir_path_normalized("./testrepo.git", "testrepo.git/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("./.git", ".git/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("./git.", "git./", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("git./", "git./", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized(".", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("./", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("./.", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/..", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../..", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/..///..", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub///../..", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub///..///..", "", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir//", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("./dir", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/.", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir///./", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/..", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir//sub/..", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir//sub/../", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../.", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/s1/../s2/", "dir/s2/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("d1/s1///s2/..//../s3/", "d1/s3/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("d1/s1//../s2/../../d2", "d2/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||
must_pass(ensure_dir_path_normalized("../../a/../../b/c/d/../../e", "b/e/", PATH_AS_SUFFIX));
|
||||
must_fail(ensure_dir_path_normalized("....", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("...", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("./...", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("d1/...", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("d1/.../", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("d1/.../d2", NULL, 0));
|
||||
|
||||
must_pass(ensure_dir_path_normalized("/./testrepo.git", "/testrepo.git/"));
|
||||
must_pass(ensure_dir_path_normalized("/./.git", "/.git/"));
|
||||
must_pass(ensure_dir_path_normalized("/./git.", "/git./"));
|
||||
must_pass(ensure_dir_path_normalized("/git./", "/git./"));
|
||||
must_pass(ensure_dir_path_normalized("/", "/"));
|
||||
must_pass(ensure_dir_path_normalized("//", "/"));
|
||||
must_pass(ensure_dir_path_normalized("///", "/"));
|
||||
must_pass(ensure_dir_path_normalized("/.", "/"));
|
||||
must_pass(ensure_dir_path_normalized("/./", "/"));
|
||||
must_fail(ensure_dir_path_normalized("/./..", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/../.", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/./.././/", NULL));
|
||||
must_pass(ensure_dir_path_normalized("/dir/..", "/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir/sub/../..", "/"));
|
||||
must_fail(ensure_dir_path_normalized("/dir/sub/../../..", NULL));
|
||||
must_pass(ensure_dir_path_normalized("/dir", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir//", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/./dir", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir/.", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir///./", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir//sub/..", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir/sub/../", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("//dir/sub/../.", "/dir/"));
|
||||
must_pass(ensure_dir_path_normalized("/dir/s1/../s2/", "/dir/s2/"));
|
||||
must_pass(ensure_dir_path_normalized("/d1/s1///s2/..//../s3/", "/d1/s3/"));
|
||||
must_pass(ensure_dir_path_normalized("/d1/s1//../s2/../../d2", "/d2/"));
|
||||
must_fail(ensure_dir_path_normalized("/....", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/...", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/./...", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/d1/...", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/d1/.../", NULL));
|
||||
must_fail(ensure_dir_path_normalized("/d1/.../d2", NULL));
|
||||
must_pass(ensure_dir_path_normalized("/./testrepo.git", "/testrepo.git/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/./.git", "/.git/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/./git.", "/git./", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/git./", "/git./", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/", "/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("//", "/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("///", "/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/.", "/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/./", "/", ROOTED_PATH));
|
||||
must_fail(ensure_dir_path_normalized("/./..", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/../.", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/./.././/", NULL, 0));
|
||||
must_pass(ensure_dir_path_normalized("/dir/..", "/", 0));
|
||||
must_pass(ensure_dir_path_normalized("/dir/sub/../..", "/", 0));
|
||||
must_fail(ensure_dir_path_normalized("/dir/sub/../../..", NULL, 0));
|
||||
must_pass(ensure_dir_path_normalized("/dir", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/dir//", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/./dir", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/dir/.", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/dir///./", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/dir//sub/..", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/dir/sub/../", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("//dir/sub/../.", "/dir/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/dir/s1/../s2/", "/dir/s2/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/d1/s1///s2/..//../s3/", "/d1/s3/", ROOTED_PATH));
|
||||
must_pass(ensure_dir_path_normalized("/d1/s1//../s2/../../d2", "/d2/", ROOTED_PATH));
|
||||
must_fail(ensure_dir_path_normalized("/....", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/...", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/./...", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/d1/...", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/d1/.../", NULL, 0));
|
||||
must_fail(ensure_dir_path_normalized("/d1/.../d2", NULL, 0));
|
||||
END_TEST
|
||||
|
||||
static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path)
|
||||
@ -383,6 +389,37 @@ BEGIN_TEST(path6, "properly join path components for more than one path")
|
||||
must_pass(ensure_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"));
|
||||
END_TEST
|
||||
|
||||
static int count_number_of_path_segments(const char *path)
|
||||
{
|
||||
int number = 0;
|
||||
char *current = (char *)path;
|
||||
|
||||
while (*current)
|
||||
{
|
||||
if (*current++ == '/')
|
||||
number++;
|
||||
}
|
||||
|
||||
assert (number > 0);
|
||||
|
||||
return --number;
|
||||
}
|
||||
|
||||
BEGIN_TEST(path7, "prevent a path which escapes the root directory from being prettified")
|
||||
char current_workdir[GIT_PATH_MAX];
|
||||
char prettified[GIT_PATH_MAX];
|
||||
int i = 0, number_to_escape;
|
||||
|
||||
must_pass(gitfo_getcwd(current_workdir, sizeof(current_workdir)));
|
||||
|
||||
number_to_escape = count_number_of_path_segments(current_workdir);
|
||||
|
||||
for (i = 0; i < number_to_escape + 1; i++)
|
||||
git__joinpath(current_workdir, current_workdir, "../");
|
||||
|
||||
must_fail(gitfo_prettify_dir_path(prettified, sizeof(prettified), current_workdir));
|
||||
END_TEST
|
||||
|
||||
typedef struct name_data {
|
||||
int count; /* return count */
|
||||
char *name; /* filename */
|
||||
@ -626,8 +663,6 @@ END_TEST
|
||||
|
||||
|
||||
BEGIN_SUITE(core)
|
||||
ADD_TEST(refcnt0);
|
||||
|
||||
ADD_TEST(string0);
|
||||
ADD_TEST(string1);
|
||||
|
||||
@ -641,6 +676,7 @@ BEGIN_SUITE(core)
|
||||
ADD_TEST(path4);
|
||||
ADD_TEST(path5);
|
||||
ADD_TEST(path6);
|
||||
ADD_TEST(path7);
|
||||
|
||||
ADD_TEST(dirent0);
|
||||
ADD_TEST(dirent1);
|
||||
|
@ -23,9 +23,16 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
|
||||
#include "odb.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "t01-data.h"
|
||||
|
||||
#include "hash.h"
|
||||
static int hash_object(git_oid *oid, git_rawobj *obj)
|
||||
{
|
||||
return git_odb_hash(oid, obj->data, obj->len, obj->type);
|
||||
}
|
||||
|
||||
BEGIN_TEST(oid0, "validate size of oid objects")
|
||||
git_oid out;
|
||||
@ -329,7 +336,7 @@ BEGIN_TEST(oid17, "stress test for the git_oid_shorten object")
|
||||
git_oid oid;
|
||||
size_t i, j;
|
||||
|
||||
int min_len, found_collision;
|
||||
int min_len = 0, found_collision;
|
||||
|
||||
os = git_oid_shorten_new(0);
|
||||
must_be_true(os != NULL);
|
||||
@ -497,28 +504,28 @@ BEGIN_TEST(objhash0, "hash junk data")
|
||||
|
||||
/* invalid types: */
|
||||
junk_obj.data = some_data;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ__EXT1;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ__EXT2;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ_OFS_DELTA;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ_REF_DELTA;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
/* data can be NULL only if len is zero: */
|
||||
junk_obj.type = GIT_OBJ_BLOB;
|
||||
junk_obj.data = NULL;
|
||||
must_pass(git_rawobj_hash(&id, &junk_obj));
|
||||
must_pass(hash_object(&id, &junk_obj));
|
||||
must_be_true(git_oid_cmp(&id, &id_zero) == 0);
|
||||
|
||||
junk_obj.len = 1;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(objhash1, "hash a commit object")
|
||||
@ -526,7 +533,7 @@ BEGIN_TEST(objhash1, "hash a commit object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, commit_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &commit_obj));
|
||||
must_pass(hash_object(&id2, &commit_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -536,7 +543,7 @@ BEGIN_TEST(objhash2, "hash a tree object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, tree_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &tree_obj));
|
||||
must_pass(hash_object(&id2, &tree_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -546,7 +553,7 @@ BEGIN_TEST(objhash3, "hash a tag object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, tag_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &tag_obj));
|
||||
must_pass(hash_object(&id2, &tag_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -556,7 +563,7 @@ BEGIN_TEST(objhash4, "hash a zero-length object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, zero_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &zero_obj));
|
||||
must_pass(hash_object(&id2, &zero_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -566,7 +573,7 @@ BEGIN_TEST(objhash5, "hash an one-byte long object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, one_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &one_obj));
|
||||
must_pass(hash_object(&id2, &one_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -576,7 +583,7 @@ BEGIN_TEST(objhash6, "hash a two-byte long object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, two_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &two_obj));
|
||||
must_pass(hash_object(&id2, &two_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -586,7 +593,7 @@ BEGIN_TEST(objhash7, "hash an object several bytes long")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, some_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &some_obj));
|
||||
must_pass(hash_object(&id2, &some_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
#include "test_helpers.h"
|
||||
#include "odb.h"
|
||||
|
||||
#include "t02-data.h"
|
||||
#include "t02-oids.h"
|
||||
@ -50,16 +51,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose0, "read a loose commit")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &commit));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, commit.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &commit));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &commit));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &commit));
|
||||
END_TEST
|
||||
@ -67,16 +68,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose1, "read a loose tree")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &tree));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, tree.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &tree));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &tree));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &tree));
|
||||
END_TEST
|
||||
@ -84,16 +85,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose2, "read a loose tag")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &tag));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, tag.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &tag));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &tag));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &tag));
|
||||
END_TEST
|
||||
@ -101,16 +102,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose3, "read a loose zero-bytes object")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &zero));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, zero.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &zero));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &zero));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &zero));
|
||||
END_TEST
|
||||
@ -118,16 +119,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose4, "read a one-byte long loose object")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &one));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, one.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &one));
|
||||
must_pass(cmp_objects(&obj->raw, &one));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &one));
|
||||
END_TEST
|
||||
@ -135,16 +136,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose5, "read a two-bytes long loose object")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &two));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, two.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &two));
|
||||
must_pass(cmp_objects(&obj->raw, &two));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &two));
|
||||
END_TEST
|
||||
@ -152,16 +153,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose6, "read a loose object which is several bytes long")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &some));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, some.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &some));
|
||||
must_pass(cmp_objects(&obj->raw, &some));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &some));
|
||||
END_TEST
|
||||
@ -174,13 +175,13 @@ BEGIN_TEST(readpack0, "read several packed objects")
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) {
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(git_oid_mkstr(&id, packed_objects[i]));
|
||||
must_be_true(git_odb_exists(db, &id) == 1);
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
}
|
||||
|
||||
git_odb_close(db);
|
||||
@ -194,17 +195,19 @@ BEGIN_TEST(readheader0, "read only the header of several packed objects")
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) {
|
||||
git_oid id;
|
||||
git_rawobj obj, header;
|
||||
git_odb_object *obj;
|
||||
size_t len;
|
||||
git_otype type;
|
||||
|
||||
must_pass(git_oid_mkstr(&id, packed_objects[i]));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(git_odb_read_header(&header, db, &id));
|
||||
must_pass(git_odb_read_header(&len, &type, db, &id));
|
||||
|
||||
must_be_true(obj.len == header.len);
|
||||
must_be_true(obj.type == header.type);
|
||||
must_be_true(obj->raw.len == len);
|
||||
must_be_true(obj->raw.type == type);
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
}
|
||||
|
||||
git_odb_close(db);
|
||||
@ -218,19 +221,21 @@ BEGIN_TEST(readheader1, "read only the header of several loose objects")
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(loose_objects); ++i) {
|
||||
git_oid id;
|
||||
git_rawobj obj, header;
|
||||
git_odb_object *obj;
|
||||
size_t len;
|
||||
git_otype type;
|
||||
|
||||
must_pass(git_oid_mkstr(&id, loose_objects[i]));
|
||||
|
||||
must_be_true(git_odb_exists(db, &id) == 1);
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(git_odb_read_header(&header, db, &id));
|
||||
must_pass(git_odb_read_header(&len, &type, db, &id));
|
||||
|
||||
must_be_true(obj.len == header.len);
|
||||
must_be_true(obj.type == header.type);
|
||||
must_be_true(obj->raw.len == len);
|
||||
must_be_true(obj->raw.type == type);
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
}
|
||||
|
||||
git_odb_close(db);
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
#include "fileops.h"
|
||||
#include "odb.h"
|
||||
|
||||
static char *odb_dir = "test-objects";
|
||||
#include "t03-data.h"
|
||||
@ -80,23 +81,39 @@ static int remove_object_files(object_data *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int streaming_write(git_oid *oid, git_odb *odb, git_rawobj *raw)
|
||||
{
|
||||
git_odb_stream *stream;
|
||||
int error;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, odb, raw->len, raw->type)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
stream->write(stream, raw->data, raw->len);
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
BEGIN_TEST(write0, "write loose commit object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, commit.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &commit_obj));
|
||||
must_pass(streaming_write(&id2, db, &commit_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&commit));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &commit_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &commit_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&commit));
|
||||
END_TEST
|
||||
@ -104,20 +121,20 @@ END_TEST
|
||||
BEGIN_TEST(write1, "write loose tree object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, tree.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &tree_obj));
|
||||
must_pass(streaming_write(&id2, db, &tree_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&tree));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &tree_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &tree_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&tree));
|
||||
END_TEST
|
||||
@ -125,20 +142,20 @@ END_TEST
|
||||
BEGIN_TEST(write2, "write loose tag object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, tag.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &tag_obj));
|
||||
must_pass(streaming_write(&id2, db, &tag_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&tag));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &tag_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &tag_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&tag));
|
||||
END_TEST
|
||||
@ -146,20 +163,20 @@ END_TEST
|
||||
BEGIN_TEST(write3, "write zero-length object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, zero.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &zero_obj));
|
||||
must_pass(streaming_write(&id2, db, &zero_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&zero));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &zero_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &zero_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&zero));
|
||||
END_TEST
|
||||
@ -167,20 +184,20 @@ END_TEST
|
||||
BEGIN_TEST(write4, "write one-byte long object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, one.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &one_obj));
|
||||
must_pass(streaming_write(&id2, db, &one_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&one));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &one_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &one_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&one));
|
||||
END_TEST
|
||||
@ -188,20 +205,20 @@ END_TEST
|
||||
BEGIN_TEST(write5, "write two-byte long object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, two.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &two_obj));
|
||||
must_pass(streaming_write(&id2, db, &two_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&two));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &two_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &two_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&two));
|
||||
END_TEST
|
||||
@ -209,20 +226,20 @@ END_TEST
|
||||
BEGIN_TEST(write6, "write an object which is several bytes long")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, some.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &some_obj));
|
||||
must_pass(streaming_write(&id2, db, &some_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&some));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &some_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &some_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&some));
|
||||
END_TEST
|
||||
|
@ -366,7 +366,7 @@ BEGIN_TEST(details0, "query the details on a parsed commit")
|
||||
|
||||
const git_signature *author, *committer;
|
||||
const char *message, *message_short;
|
||||
time_t commit_time;
|
||||
git_time_t commit_time;
|
||||
unsigned int parents, p;
|
||||
git_commit *parent;
|
||||
|
||||
@ -390,11 +390,11 @@ 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++) {
|
||||
parent = git_commit_parent(commit, p);
|
||||
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?
|
||||
}
|
||||
must_be_true(git_commit_parent(commit, parents) == NULL);
|
||||
must_fail(git_commit_parent(&parent, commit, parents));
|
||||
}
|
||||
|
||||
git_repository_free(repo);
|
||||
@ -407,39 +407,42 @@ This is a commit created in memory and it will be written back to disk\n"
|
||||
|
||||
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
|
||||
|
||||
|
||||
BEGIN_TEST(write0, "write a new commit object from memory to disk")
|
||||
git_repository *repo;
|
||||
git_commit *commit, *parent;
|
||||
git_tree *tree;
|
||||
git_oid id;
|
||||
git_commit *commit;
|
||||
git_oid tree_id, parent_id, commit_id;
|
||||
const git_signature *author, *committer;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
/* Create commit in memory */
|
||||
must_pass(git_commit_new(&commit, repo));
|
||||
|
||||
/* Add new parent */
|
||||
git_oid_mkstr(&id, commit_ids[4]);
|
||||
must_pass(git_commit_lookup(&parent, repo, &id));
|
||||
git_oid_mkstr(&tree_id, tree_oid);
|
||||
git_oid_mkstr(&parent_id, commit_ids[4]);
|
||||
|
||||
git_commit_add_parent(commit, parent);
|
||||
|
||||
/* Set other attributes */
|
||||
/* 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);
|
||||
|
||||
git_commit_set_committer(commit, committer);
|
||||
git_commit_set_author(commit, author);
|
||||
git_commit_set_message(commit, COMMIT_MESSAGE);
|
||||
must_pass(git_commit_create_v(
|
||||
&commit_id, /* out id */
|
||||
repo,
|
||||
NULL, /* do not update the HEAD */
|
||||
author,
|
||||
committer,
|
||||
COMMIT_MESSAGE,
|
||||
&tree_id,
|
||||
1, &parent_id));
|
||||
|
||||
git_signature_free((git_signature *)committer);
|
||||
git_signature_free((git_signature *)author);
|
||||
|
||||
must_pass(git_commit_lookup(&commit, repo, &commit_id));
|
||||
|
||||
/* Check attributes were set correctly */
|
||||
author = git_commit_author(commit);
|
||||
must_be_true(author != NULL);
|
||||
@ -457,47 +460,6 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk")
|
||||
|
||||
must_be_true(strcmp(git_commit_message(commit), COMMIT_MESSAGE) == 0);
|
||||
|
||||
/* add new tree */
|
||||
git_oid_mkstr(&id, tree_oid);
|
||||
must_pass(git_tree_lookup(&tree, repo, &id));
|
||||
|
||||
git_commit_set_tree(commit, tree);
|
||||
|
||||
/* Test it has no OID */
|
||||
must_be_true(git_commit_id(commit) == NULL);
|
||||
|
||||
/* Write to disk */
|
||||
must_pass(git_object_write((git_object *)commit));
|
||||
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
|
||||
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write1, "load a commit object, modify it and write it back")
|
||||
git_repository *repo;
|
||||
git_oid id;
|
||||
git_commit *commit, *parent;
|
||||
const char *message;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git_oid_mkstr(&id, commit_ids[0]);
|
||||
|
||||
must_pass(git_commit_lookup(&commit, repo, &id));
|
||||
|
||||
message = git_commit_message(commit);
|
||||
|
||||
git_commit_set_message(commit, "This is a new test message. Cool!\n");
|
||||
|
||||
git_oid_mkstr(&id, commit_ids[4]);
|
||||
must_pass(git_commit_lookup(&parent, repo, &id));
|
||||
|
||||
git_commit_add_parent(commit, parent);
|
||||
|
||||
must_pass(git_object_write((git_object *)commit));
|
||||
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
|
||||
|
||||
git_repository_free(repo);
|
||||
@ -509,6 +471,7 @@ BEGIN_SUITE(commit)
|
||||
ADD_TEST(parse1);
|
||||
ADD_TEST(parse2);
|
||||
ADD_TEST(details0);
|
||||
|
||||
ADD_TEST(write0);
|
||||
ADD_TEST(write1);
|
||||
//ADD_TEST(write1);
|
||||
END_SUITE
|
||||
|
@ -25,8 +25,6 @@
|
||||
#include "test_lib.h"
|
||||
#include "test_helpers.h"
|
||||
|
||||
#include "revwalk.h"
|
||||
|
||||
/*
|
||||
$ git log --oneline --graph --decorate
|
||||
* a4a7dce (HEAD, br2) Merge branch 'master' into br2
|
||||
@ -70,12 +68,12 @@ static const int commit_sorting_time_reverse[][6] = {
|
||||
static const int result_bytes = 24;
|
||||
|
||||
|
||||
static int get_commit_index(git_commit *commit)
|
||||
static int get_commit_index(git_oid *raw_oid)
|
||||
{
|
||||
int i;
|
||||
char oid[40];
|
||||
|
||||
git_oid_fmt(oid, &commit->object.id);
|
||||
git_oid_fmt(oid, raw_oid);
|
||||
|
||||
for (i = 0; i < commit_count; ++i)
|
||||
if (memcmp(oid, commit_ids[i], 40) == 0)
|
||||
@ -84,23 +82,31 @@ static int get_commit_index(git_commit *commit)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int test_walk(git_revwalk *walk, git_commit *start_from,
|
||||
static int test_walk(git_revwalk *walk, const git_oid *root,
|
||||
int flags, const int possible_results[][6], int results_count)
|
||||
{
|
||||
git_commit *commit = NULL;
|
||||
git_oid oid;
|
||||
|
||||
int i;
|
||||
int result_array[commit_count];
|
||||
|
||||
git_revwalk_sorting(walk, flags);
|
||||
git_revwalk_push(walk, start_from);
|
||||
git_revwalk_push(walk, root);
|
||||
|
||||
for (i = 0; i < commit_count; ++i)
|
||||
result_array[i] = -1;
|
||||
|
||||
i = 0;
|
||||
while (git_revwalk_next(&commit, walk) == GIT_SUCCESS)
|
||||
result_array[i++] = get_commit_index(commit);
|
||||
|
||||
while (git_revwalk_next(&oid, walk) == GIT_SUCCESS) {
|
||||
result_array[i++] = get_commit_index(&oid);
|
||||
/*{
|
||||
char str[41];
|
||||
git_oid_fmt(str, &oid);
|
||||
str[40] = 0;
|
||||
printf(" %d) %s\n", i, str);
|
||||
}*/
|
||||
}
|
||||
|
||||
for (i = 0; i < results_count; ++i)
|
||||
if (memcmp(possible_results[i],
|
||||
@ -114,103 +120,21 @@ BEGIN_TEST(walk0, "do a simple walk on a repo with different sorting modes")
|
||||
git_oid id;
|
||||
git_repository *repo;
|
||||
git_revwalk *walk;
|
||||
git_commit *head = NULL;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
must_pass(git_revwalk_new(&walk, repo));
|
||||
|
||||
git_oid_mkstr(&id, commit_head);
|
||||
|
||||
must_pass(git_commit_lookup(&head, repo, &id));
|
||||
|
||||
must_pass(test_walk(walk, head,
|
||||
GIT_SORT_TIME,
|
||||
commit_sorting_time, 1));
|
||||
|
||||
must_pass(test_walk(walk, head,
|
||||
GIT_SORT_TOPOLOGICAL,
|
||||
commit_sorting_topo, 2));
|
||||
|
||||
must_pass(test_walk(walk, head,
|
||||
GIT_SORT_TIME | GIT_SORT_REVERSE,
|
||||
commit_sorting_time_reverse, 1));
|
||||
|
||||
must_pass(test_walk(walk, head,
|
||||
GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE,
|
||||
commit_sorting_topo_reverse, 2));
|
||||
|
||||
must_pass(test_walk(walk, &id, GIT_SORT_TIME, commit_sorting_time, 1));
|
||||
must_pass(test_walk(walk, &id, GIT_SORT_TOPOLOGICAL, commit_sorting_topo, 2));
|
||||
must_pass(test_walk(walk, &id, GIT_SORT_TIME | GIT_SORT_REVERSE, commit_sorting_time_reverse, 1));
|
||||
must_pass(test_walk(walk, &id, GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE, commit_sorting_topo_reverse, 2));
|
||||
|
||||
git_revwalk_free(walk);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(list0, "check that a commit list is properly sorted by time")
|
||||
|
||||
git_revwalk_list list;
|
||||
git_revwalk_listnode *n;
|
||||
int i, t;
|
||||
time_t previous_time;
|
||||
|
||||
#define TEST_SORTED() \
|
||||
previous_time = INT_MAX;\
|
||||
for (n = list.head; n != NULL; n = n->next) {\
|
||||
must_be_true(n->walk_commit->commit_object->committer->when.time <= previous_time);\
|
||||
previous_time = n->walk_commit->commit_object->committer->when.time;\
|
||||
}
|
||||
|
||||
#define CLEAR_LIST() \
|
||||
for (n = list.head; n != NULL; n = n->next) {\
|
||||
git_signature_free(n->walk_commit->commit_object->committer);\
|
||||
free(n->walk_commit->commit_object);\
|
||||
free(n->walk_commit);\
|
||||
}\
|
||||
git_revwalk_list_clear(&list);
|
||||
|
||||
memset(&list, 0x0, sizeof(git_revwalk_list));
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
for (t = 0; t < 20; ++t) {
|
||||
const int test_size = rand() % 500 + 500;
|
||||
|
||||
/* Purely random sorting test */
|
||||
for (i = 0; i < test_size; ++i) {
|
||||
git_commit *c = git__malloc(sizeof(git_commit));
|
||||
git_revwalk_commit *rc = git__malloc(sizeof(git_revwalk_commit));
|
||||
|
||||
c->committer = git_signature_new("", "", (time_t)rand(), 0);
|
||||
rc->commit_object = c;
|
||||
|
||||
git_revwalk_list_push_back(&list, rc);
|
||||
}
|
||||
|
||||
git_revwalk_list_timesort(&list);
|
||||
TEST_SORTED();
|
||||
CLEAR_LIST();
|
||||
}
|
||||
|
||||
/* Try to sort list with all dates equal. */
|
||||
for (i = 0; i < 200; ++i) {
|
||||
git_commit *c = git__malloc(sizeof(git_commit));
|
||||
git_revwalk_commit *rc = git__malloc(sizeof(git_revwalk_commit));
|
||||
|
||||
c->committer = git_signature_new("", "", 0, 0);
|
||||
rc->commit_object = c;
|
||||
|
||||
git_revwalk_list_push_back(&list, rc);
|
||||
}
|
||||
|
||||
git_revwalk_list_timesort(&list);
|
||||
TEST_SORTED();
|
||||
CLEAR_LIST();
|
||||
|
||||
/* Try to sort empty list */
|
||||
git_revwalk_list_timesort(&list);
|
||||
TEST_SORTED();
|
||||
|
||||
END_TEST
|
||||
|
||||
BEGIN_SUITE(revwalk)
|
||||
ADD_TEST(walk0);
|
||||
ADD_TEST(list0);
|
||||
END_SUITE
|
||||
|
@ -34,7 +34,7 @@ struct test_entry {
|
||||
unsigned int index;
|
||||
char path[128];
|
||||
git_off_t file_size;
|
||||
time_t mtime;
|
||||
git_time_t mtime;
|
||||
};
|
||||
|
||||
struct test_entry TEST_ENTRIES[] = {
|
||||
|
@ -48,12 +48,12 @@ BEGIN_TEST(read0, "read and parse a tag from the repository")
|
||||
must_be_true(strcmp(git_tag_name(tag1), "test") == 0);
|
||||
must_be_true(git_tag_type(tag1) == GIT_OBJ_TAG);
|
||||
|
||||
tag2 = (git_tag *)git_tag_target(tag1);
|
||||
must_pass(git_tag_target((git_object **)&tag2, tag1));
|
||||
must_be_true(tag2 != NULL);
|
||||
|
||||
must_be_true(git_oid_cmp(&id2, git_tag_id(tag2)) == 0);
|
||||
|
||||
commit = (git_commit *)git_tag_target(tag2);
|
||||
must_pass(git_tag_target((git_object **)&commit, tag2));
|
||||
must_be_true(commit != NULL);
|
||||
|
||||
must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0);
|
||||
@ -61,27 +61,62 @@ BEGIN_TEST(read0, "read and parse a tag from the repository")
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write0, "write back a tag to the repository")
|
||||
git_oid id;
|
||||
|
||||
#define TAGGER_NAME "Vicent Marti"
|
||||
#define TAGGER_EMAIL "vicent@github.com"
|
||||
#define TAGGER_MESSAGE "This is my tag.\n\nThere are many tags, but this one is mine\n"
|
||||
|
||||
BEGIN_TEST(write0, "write a tag to the repository and read it again")
|
||||
git_repository *repo;
|
||||
git_tag *tag;
|
||||
git_oid target_id, tag_id;
|
||||
const git_signature *tagger;
|
||||
git_reference *ref_tag;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git_oid_mkstr(&id, tag1_id);
|
||||
git_oid_mkstr(&target_id, tagged_commit);
|
||||
|
||||
must_pass(git_tag_lookup(&tag, repo, &id));
|
||||
/* create signatures */
|
||||
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
|
||||
must_be_true(tagger != NULL);
|
||||
|
||||
git_tag_set_name(tag, "This is a different tag LOL");
|
||||
must_pass(git_tag_create(
|
||||
&tag_id, /* out id */
|
||||
repo,
|
||||
"the-tag", /* do not update the HEAD */
|
||||
&target_id,
|
||||
GIT_OBJ_COMMIT,
|
||||
tagger,
|
||||
TAGGER_MESSAGE));
|
||||
|
||||
git_signature_free((git_signature *)tagger);
|
||||
|
||||
must_pass(git_tag_lookup(&tag, repo, &tag_id));
|
||||
|
||||
/* Check attributes were set correctly */
|
||||
tagger = git_tag_tagger(tag);
|
||||
must_be_true(tagger != NULL);
|
||||
must_be_true(strcmp(tagger->name, TAGGER_NAME) == 0);
|
||||
must_be_true(strcmp(tagger->email, TAGGER_EMAIL) == 0);
|
||||
must_be_true(tagger->when.time == 123456789);
|
||||
must_be_true(tagger->when.offset == 60);
|
||||
|
||||
must_be_true(strcmp(git_tag_message(tag), TAGGER_MESSAGE) == 0);
|
||||
|
||||
must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/the-tag"));
|
||||
must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0);
|
||||
must_pass(git_reference_delete(ref_tag));
|
||||
|
||||
must_pass(git_object_write((git_object *)tag));
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag));
|
||||
|
||||
git_repository_free(repo);
|
||||
|
||||
END_TEST
|
||||
|
||||
|
||||
BEGIN_SUITE(tag)
|
||||
ADD_TEST(read0);
|
||||
ADD_TEST(write0);
|
||||
ADD_TEST(write0);
|
||||
END_SUITE
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user