Merge upstream/development

Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
This commit is contained in:
Carlos Martín Nieto 2011-03-31 15:29:13 +02:00
commit f026f2b9ee
109 changed files with 13965 additions and 4030 deletions

View File

@ -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 ()

View File

@ -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

View File

@ -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
View 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

File diff suppressed because it is too large Load Diff

342
deps/zlib/deflate.h vendored Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

122
deps/zlib/inflate.h vendored Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

128
deps/zlib/trees.h vendored Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

318
deps/zlib/zutil.c vendored Normal file
View 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
View 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 */

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.
*

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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__ */

View File

@ -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

View File

@ -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;
/** @} */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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
View 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
View 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

View File

@ -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);
}

View File

@ -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

View File

@ -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"

View File

@ -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.
*

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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) {

View File

@ -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);

View File

@ -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
View File

@ -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;

View File

@ -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

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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
View 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 */
/** @} */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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
View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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++;

View File

@ -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
View 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
View 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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[] = {

View File

@ -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