Commit f026f2b9 by Carlos Martín Nieto

Merge upstream/development

Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
parents 11d0e705 a796d24c
...@@ -22,8 +22,7 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ...@@ -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}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}")
# Find required dependencies # Find required dependencies
FIND_PACKAGE(ZLIB REQUIRED) INCLUDE_DIRECTORIES(deps/zlib src include)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} src)
# Try finding openssl # Try finding openssl
FIND_PACKAGE(OpenSSL) FIND_PACKAGE(OpenSSL)
...@@ -63,25 +62,32 @@ SET(INSTALL_INC include CACHE PATH "Where to install headers to.") ...@@ -63,25 +62,32 @@ SET(INSTALL_INC include CACHE PATH "Where to install headers to.")
# Build options # Build options
OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
OPTION (BUILD_TESTS "Build Tests" ON) OPTION (BUILD_TESTS "Build Tests" ON)
OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF)
# Build Release by default # Build Release by default
IF (NOT CMAKE_BUILD_TYPE) IF (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
ENDIF () ENDIF ()
IF (THREADSAFE)
IF (NOT WIN32)
find_package(Threads REQUIRED)
ENDIF()
ADD_DEFINITIONS(-DGIT_THREADS)
ENDIF()
# Collect sourcefiles # Collect sourcefiles
FILE(GLOB SRC src/*.c src/backends/*.c) 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_SHA1 src/block-sha1/*.c)
FILE(GLOB SRC_PLAT src/unix/*.c) FILE(GLOB SRC_PLAT src/unix/*.c)
FILE(GLOB SRC_H include/git2/*.h) FILE(GLOB SRC_H include/git2/*.h)
# On Windows use specific platform sources # On Windows use specific platform sources
IF (WIN32 AND NOT CYGWIN) 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) FILE(GLOB SRC_PLAT src/win32/*.c)
IF (MINGW)
SET(PTHREAD_LIBRARY pthread)
ENDIF ()
ENDIF () ENDIF ()
# Specify sha1 implementation # Specify sha1 implementation
...@@ -96,9 +102,8 @@ ELSEIF (SHA1_TYPE STREQUAL "openssl") ...@@ -96,9 +102,8 @@ ELSEIF (SHA1_TYPE STREQUAL "openssl")
ENDIF () ENDIF ()
# Compile and link libgit2 # Compile and link libgit2
INCLUDE_DIRECTORIES(src include) ADD_LIBRARY(git2 ${SRC} ${SRC_PLAT} ${SRC_SHA1} ${SRC_ZLIB})
ADD_LIBRARY(git2 ${SRC} ${SRC_PLAT} ${SRC_SHA1}) TARGET_LINK_LIBRARIES(git2 ${LIB_SHA1} ${CMAKE_THREAD_LIBS_INIT} ${SQLITE3_LIBRARIES})
TARGET_LINK_LIBRARIES(git2 ${ZLIB_LIBRARY} ${LIB_SHA1} ${PTHREAD_LIBRARY} ${SQLITE3_LIBRARIES})
SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING}) SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR}) SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR})
...@@ -121,8 +126,8 @@ IF (BUILD_TESTS) ...@@ -121,8 +126,8 @@ IF (BUILD_TESTS)
FILE(GLOB SRC_TEST tests/t??-*.c) 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}) 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 ${ZLIB_LIBRARY} ${LIB_SHA1} ${PTHREAD_LIBRARY} ${SQLITE3_LIBRARIES}) TARGET_LINK_LIBRARIES(libgit2_test ${LIB_SHA1} ${CMAKE_THREAD_LIBS_INIT} ${SQLITE3_LIBRARIES})
ADD_TEST(libgit2_test libgit2_test) ADD_TEST(libgit2_test libgit2_test)
ENDIF () ENDIF ()
...@@ -5,6 +5,11 @@ libgit2 is a portable, pure C implementation of the Git core methods provided as ...@@ -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 re-entrant linkable library with a solid API, allowing you to write native
speed custom Git applications in any language with bindings. 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> * Website: <http://libgit2.github.com>
* API documentation: <http://libgit2.github.com/libgit2/modules.html> * API documentation: <http://libgit2.github.com/libgit2/modules.html>
* Usage guide: <http://libgit2.github.com/api.html> * Usage guide: <http://libgit2.github.com/api.html>
...@@ -14,30 +19,32 @@ What It Can Do ...@@ -14,30 +19,32 @@ What It Can Do
libgit2 is already very usable. libgit2 is already very usable.
* raw <-> hex SHA conversions * SHA conversions, formatting and shortening
* raw object reading (loose and packed) * object reading (loose and packed)
* raw object writing (loose) * object writing (loose)
* revlist walker * commit, tag, tree and blob parsing and write-back
* commit, tag and tree object parsing and write-back
* tree traversal * 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 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/> Additionally, he following libraries may be used as replacement for built-in functionality:
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/>
* LibSSL **(optional)** <http://www.openssl.org/> * 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. 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 Building libgit2 - Using waf
====================== ======================
...@@ -112,11 +119,17 @@ Language Bindings ...@@ -112,11 +119,17 @@ Language Bindings
Here are the bindings to libgit2 that are currently available: Here are the bindings to libgit2 that are currently available:
* Rugged (Ruby bindings) <https://github.com/libgit2/rugged> * 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> * pygit2 (Python bindings) <https://github.com/libgit2/pygit2>
* libgit2sharp (.NET bindings) <https://github.com/nulltoken/libgit2sharp> * libgit2sharp (.NET bindings) <https://github.com/libgit2/libgit2sharp>
* php-git (PHP bindings) <https://github.com/chobie/php-git> * php-git (PHP bindings) <https://github.com/libgit2/php-git>
* luagit2 (Lua bindings) <https://github.com/Neopallium/luagit2> * luagit2 (Lua bindings) <https://github.com/libgit2/luagit2>
* GitForDelphi (Delphi bindings) <https://github.com/jasonpenny/GitForDelphi> * 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> * Geef (Erlang bindings) <https://github.com/schacon/geef>
If you start another language binding to libgit2, please let us know so If you start another language binding to libgit2, please let us know so
......
PROJECT_NAME = libgit2 PROJECT_NAME = libgit2
INPUT = src/git2 INPUT = include/git2
QUIET = YES QUIET = YES
RECURSIVE = YES RECURSIVE = YES
FILE_PATTERNS = *.h FILE_PATTERNS = *.h
......
/* 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);
}
/* 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));
/* 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}
};
/* 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 */
};
/* 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));
/* 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
};
/* 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 */
/* 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 */
/* zutil.h -- internal interface and configuration of the compression library
* Copyright (C) 1995-2010 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* @(#) $Id$ */
#ifndef ZUTIL_H
#define ZUTIL_H
#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
#endif
#include "zlib.h"
#ifdef STDC
# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
# include <stddef.h>
# endif
# include <string.h>
# include <stdlib.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
typedef unsigned char uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long ulg;
extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */
#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
#define ERR_RETURN(strm,err) \
return (strm->msg = (char*)ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */
/* common constants */
#ifndef DEF_WBITS
# define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
/* default memLevel */
#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES 2
/* The three kinds of block type */
#define MIN_MATCH 3
#define MAX_MATCH 258
/* The minimum and maximum match lengths */
#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
/* target dependencies */
#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
# define OS_CODE 0x00
# if defined(__TURBOC__) || defined(__BORLANDC__)
# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
/* Allow compilation with ANSI keywords only enabled */
void _Cdecl farfree( void *block );
void *_Cdecl farmalloc( unsigned long nbytes );
# else
# include <alloc.h>
# endif
# else /* MSC or DJGPP */
# include <malloc.h>
# endif
#endif
#ifdef AMIGA
# define OS_CODE 0x01
#endif
#if defined(VAXC) || defined(VMS)
# define OS_CODE 0x02
# define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif
#if defined(ATARI) || defined(atarist)
# define OS_CODE 0x05
#endif
#ifdef OS2
# define OS_CODE 0x06
# ifdef M_I86
# include <malloc.h>
# endif
#endif
#if defined(MACOS) || defined(TARGET_OS_MAC)
# define OS_CODE 0x07
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fdopen */
# else
# ifndef fdopen
# define fdopen(fd,mode) NULL /* No fdopen() */
# endif
# endif
#endif
#ifdef TOPS20
# define OS_CODE 0x0a
#endif
#ifdef WIN32
# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
# define OS_CODE 0x0b
# endif
#endif
#ifdef __50SERIES /* Prime/PRIMOS */
# define OS_CODE 0x0f
#endif
#if defined(_BEOS_) || defined(RISCOS)
# define fdopen(fd,mode) NULL /* No fdopen() */
#endif
#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
# if defined(_WIN32_WCE)
# define fdopen(fd,mode) NULL /* No fdopen() */
# ifndef _PTRDIFF_T_DEFINED
typedef int ptrdiff_t;
# define _PTRDIFF_T_DEFINED
# endif
# else
# define fdopen(fd,type) _fdopen(fd,type)
# endif
#endif
#if defined(__BORLANDC__)
#pragma warn -8004
#pragma warn -8008
#pragma warn -8066
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
#endif
/* common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif
#ifndef F_OPEN
# define F_OPEN(name, mode) fopen((name), (mode))
#endif
/* functions */
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(__CYGWIN__)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#ifndef HAVE_VSNPRINTF
# ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */
# define NO_vsnprintf
# endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
# define vsnprintf _vsnprintf
# endif
# endif
# endif
# ifdef __SASC
# define NO_vsnprintf
# endif
#endif
#ifdef VMS
# define NO_vsnprintf
#endif
#if defined(pyr)
# define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
/* Use our own functions for small and medium model with MSC <= 5.0.
* You may have to use the same strategy for Borland C (untested).
* The __SC__ check is for Symantec.
*/
# define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
# define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
# define zmemcpy _fmemcpy
# define zmemcmp _fmemcmp
# define zmemzero(dest, len) _fmemset(dest, 0, len)
# else
# define zmemcpy memcpy
# define zmemcmp memcmp
# define zmemzero(dest, len) memset(dest, 0, len)
# endif
#else
void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
#endif
/* Diagnostic functions */
#ifdef DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error OF((char *m));
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
unsigned size));
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
#define ZALLOC(strm, items, size) \
(*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
#endif /* ZUTIL_H */
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
#ifndef INCLUDE_git_git_h__ #ifndef INCLUDE_git_git_h__
#define 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_MAJOR 0
#define LIBGIT2_VER_MINOR 8 #define LIBGIT2_VER_MINOR 10
#define LIBGIT2_VER_REVISION 0 #define LIBGIT2_VER_REVISION 0
#include "git2/common.h" #include "git2/common.h"
......
...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL ...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL
/** /**
* Lookup a blob object from a repository. * 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 blob pointer to the looked up blob
* @param repo the repo to use when locating the 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 ...@@ -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 * This is a wrapper around git_object_close()
* the 'set_rawcontent' methods before it can
* be written back to disk.
* *
* @param blob pointer to the new blob * IMPORTANT:
* @param repo The repository where the object will reside * It *is* necessary to call this method when you stop
* @return 0 on success; error code otherwise * 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. * 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 ...@@ -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; * A pointer to the raw content of a blob is returned;
* this pointer is owned internally by the object and shall * this pointer is owned internally by the object and shall
* not be free'd. The pointer may be invalidated at a later * 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 * @param blob pointer to the blob
* @return the pointer; NULL if the blob has no contents * @return the pointer; NULL if the blob has no contents
...@@ -114,14 +93,28 @@ GIT_EXTERN(int) git_blob_rawsize(git_blob *blob); ...@@ -114,14 +93,28 @@ GIT_EXTERN(int) git_blob_rawsize(git_blob *blob);
/** /**
* Read a file from the working folder of a repository * Read a file from the working folder of a repository
* and write it to the Object Database as a loose blob, * and write it to the Object Database as a loose blob
* if such doesn't exist yet. *
* @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_create_fromfile(git_oid *oid, git_repository *repo, const char *path);
/**
* Write an in-memory buffer to the ODB as a blob
* *
* @param written_id return the id of the written blob * @param oid return the oid of the written blob
* @param repo repository where the blob will be written * @param repo repository where to blob will be written
* @param path file from which the blob will be created * @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_writefile(git_oid *written_id, git_repository *repo, const char *path); GIT_EXTERN(int) git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL ...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL
/** /**
* Lookup a commit object from a repository. * 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 commit pointer to the looked up commit
* @param repo the repo to use when locating the 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 ...@@ -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 * This is a wrapper around git_object_close()
* setter methods before it can be written to its
* repository.
* *
* @param commit pointer to the new commit * IMPORTANT:
* @param repo The repository where the object will reside * It *is* necessary to call this method when you stop
* @return 0 on success; error code otherwise * 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. * Get the id of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return object identity for the commit. * @return object identity for the commit.
*/ */
...@@ -80,6 +80,7 @@ GIT_EXTERN(const git_oid *) git_commit_id(git_commit *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. * Get the short (one line) message of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the short message of a commit * @return the short message of a commit
*/ */
...@@ -87,6 +88,7 @@ GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit); ...@@ -87,6 +88,7 @@ GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit);
/** /**
* Get the full message of a commit. * Get the full message of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the message of a commit * @return the message of a commit
*/ */
...@@ -94,13 +96,15 @@ GIT_EXTERN(const char *) git_commit_message(git_commit *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. * Get the commit time (i.e. committer time) of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the time of a 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. * Get the commit timezone offset (i.e. committer's preferred timezone) of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return positive or negative timezone offset, in minutes from UTC * @return positive or negative timezone offset, in minutes from UTC
*/ */
...@@ -108,6 +112,7 @@ GIT_EXTERN(int) git_commit_time_offset(git_commit *commit); ...@@ -108,6 +112,7 @@ GIT_EXTERN(int) git_commit_time_offset(git_commit *commit);
/** /**
* Get the committer of a commit. * Get the committer of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the committer of a commit * @return the committer of a commit
*/ */
...@@ -115,6 +120,7 @@ GIT_EXTERN(const git_signature *) git_commit_committer(git_commit *commit); ...@@ -115,6 +120,7 @@ GIT_EXTERN(const git_signature *) git_commit_committer(git_commit *commit);
/** /**
* Get the author of a commit. * Get the author of a commit.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the author of a commit * @return the author of a commit
*/ */
...@@ -122,10 +128,12 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit); ...@@ -122,10 +128,12 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit);
/** /**
* Get the tree pointed to by a 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. * @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 * Get the number of parents of this commit
...@@ -137,47 +145,137 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit); ...@@ -137,47 +145,137 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit);
/** /**
* Get the specified parent of the commit. * Get the specified parent of the commit.
*
* @param parent Pointer where to store the parent commit
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @param n the position of the entry * @param n the position of the parent (from 0 to `parentcount`)
* @return a pointer to the commit; NULL if out of bounds * @return 0 on success; error code otherwise
*/ */
GIT_EXTERN(git_commit *) git_commit_parent(git_commit *commit, unsigned int n); GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n);
/** /**
* Add a new parent commit to an existing commit * Create a new commit in the repository
* @param commit the commit object *
* @param new_parent the new commit which will be a parent *
* @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 * @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(int) git_commit_add_parent(git_commit *commit, git_commit *new_parent); 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 message of a commit * Create a new commit in the repository using `git_object`
* @param commit the commit object * instances as parameters.
* @param message the new message *
* 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_message(git_commit *commit, const char *message); 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 committer of a commit * Create a new commit in the repository using `git_object`
* @param commit the commit object * instances and a variable argument list.
* @param author_sig signature of the committer *
* 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_committer(git_commit *commit, const git_signature *committer_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 author of a commit
* @param commit the commit object
* @param author_sig signature of the author
*/
GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const git_signature *author_sig);
/** /**
* Set the tree which is pointed to by a commit * Create a new commit in the repository using
* @param commit the commit object * a variable argument list.
* @param tree the new tree *
* 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 GIT_END_DECL
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "thread-utils.h" #include "thread-utils.h"
#include <time.h> #include <time.h>
#include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
# define GIT_BEGIN_DECL extern "C" { # define GIT_BEGIN_DECL extern "C" {
...@@ -118,13 +119,13 @@ ...@@ -118,13 +119,13 @@
/** The object or config variable type is invalid or doesn't match */ /** The object or config variable type is invalid or doesn't match */
#define GIT_EINVALIDTYPE (GIT_ERROR - 8) #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) #define GIT_EMISSINGOBJDATA (GIT_ERROR - 9)
/** The packfile for the ODB is corrupted */ /** The packfile for the ODB is corrupted */
#define GIT_EPACKCORRUPTED (GIT_ERROR - 10) #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) #define GIT_EFLOCKFAIL (GIT_ERROR - 11)
/** The Z library failed to inflate/deflate an object's data */ /** The Z library failed to inflate/deflate an object's data */
...@@ -145,7 +146,7 @@ ...@@ -145,7 +146,7 @@
/** The specified symbolic reference is too deeply nested */ /** The specified symbolic reference is too deeply nested */
#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17) #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) #define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18)
/** The path is invalid */ /** The path is invalid */
...@@ -157,7 +158,21 @@ ...@@ -157,7 +158,21 @@
/** The state of the reference is not valid */ /** The state of the reference is not valid */
#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21) #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 GIT_BEGIN_DECL
typedef struct {
char **strings;
size_t count;
} git_strarray;
GIT_EXTERN(void) git_strarray_free(git_strarray *array);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -91,8 +91,8 @@ GIT_EXTERN(int) git_index_open_bare(git_index **index, const char *index_path); ...@@ -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 * Open the Index inside the git repository pointed
* by 'repo'. * by 'repo'.
* *
* @param index the pointer for the new index
* @param repo the git repo which owns the 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 * @return 0 on success; error code otherwise
*/ */
GIT_EXTERN(int) git_index_open_inrepo(git_index **index, git_repository *repo); 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); ...@@ -132,7 +132,7 @@ GIT_EXTERN(int) git_index_read(git_index *index);
GIT_EXTERN(int) git_index_write(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. * path in the Git index.
* *
* @param index an existing index object * @param index an existing index object
......
...@@ -42,7 +42,8 @@ GIT_BEGIN_DECL ...@@ -42,7 +42,8 @@ GIT_BEGIN_DECL
* Lookup a reference to one of the objects in a repostory. * Lookup a reference to one of the objects in a repostory.
* *
* The generated reference is owned by the repository and * 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 * The 'type' parameter must match the type of the object
* in the odb; the method will fail otherwise. * in the odb; the method will fail otherwise.
...@@ -58,54 +59,8 @@ GIT_BEGIN_DECL ...@@ -58,54 +59,8 @@ GIT_BEGIN_DECL
GIT_EXTERN(int) git_object_lookup(git_object **object, git_repository *repo, const git_oid *id, git_otype type); 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 * 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 * @param obj the repository object
* @return the SHA1 id * @return the SHA1 id
*/ */
...@@ -131,20 +86,14 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj); ...@@ -131,20 +86,14 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj);
* Close an open object * Close an open object
* *
* This method instructs the library to close an existing * This method instructs the library to close an existing
* object; note that git_objects are owned by the repository * object; note that git_objects are owned and cached by the repository
* and are reference counted, so the object may or may not be * so the object may or may not be freed after this library call,
* freed after this library call, depending on whether any other * depending on how agressive is the caching mechanism used
* objects still depend on it. * by the repository.
* *
* IMPORTANT: * IMPORTANT:
* It is *not* necessary to call this method when you stop using * It *is* necessary to call this method when you stop using
* an object, since all object memory is automatically reclaimed * an object. Failure to do so will cause a memory leak.
* 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.
* *
* @param object the object to close * @param object the object to close
*/ */
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "common.h" #include "common.h"
#include "types.h" #include "types.h"
#include "oid.h" #include "oid.h"
#include "odb_backend.h"
/** /**
* @file git2/odb.h * @file git2/odb.h
...@@ -100,61 +101,49 @@ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, in ...@@ -100,61 +101,49 @@ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, in
/** /**
* Close an open object database. * Close an open object database.
*
* @param db database pointer to close. If NULL no action is taken. * @param db database pointer to close. If NULL no action is taken.
*/ */
GIT_EXTERN(void) git_odb_close(git_odb *db); 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. * 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 db database to search for the object in.
* @param id identity of the object to read. * @param id identity of the object to read.
* @return * @return
* - GIT_SUCCESS if the object was read; * - GIT_SUCCESS if the object was read;
* - GIT_ENOTFOUND if the object is not in the database. * - 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 * Read the header of an object from the database, without
* reading its full contents. * reading its full contents.
* *
* Only the 'type' and 'len' fields of the git_rawobj structure * The header includes the length and the type of an object.
* are filled. The 'data' pointer will always be NULL.
* *
* The raw object pointed by 'out' doesn't need to be manually * Note that most backends do not support reading only the header
* closed with git_rawobj_close(). * 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 db database to search for the object in.
* @param id identity of the object to read. * @param id identity of the object to read.
* @return * @return
* - GIT_SUCCESS if the object was read; * - GIT_SUCCESS if the object was read;
* - GIT_ENOTFOUND if the object is not in the database. * - 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); GIT_EXTERN(int) git_odb_read_header(size_t *len_p, git_otype *type_p, 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);
/** /**
* Determine if the given object can be found in the object database. * 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); ...@@ -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 db database to be searched for the given object.
* @param id the object to search for. * @param id the object to search for.
* @return * @return
* - true, if the object was found * - 1, if the object was found
* - false, otherwise * - 0, otherwise
*/ */
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id); 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);
/**
* Open a stream to write an object into the ODB
*
* 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 the given git_rawobj. * Determine the object-ID (sha1 hash) of a data buffer
* *
* The input obj must be a valid loose object type and the data * The resulting SHA-1 OID will the itentifier for the data
* pointer must not be NULL, unless the len field is also zero. * buffer as if the data buffer it were to written to the ODB.
* *
* @param id the resulting object-ID. * @param id the resulting object-ID.
* @param obj the object whose hash is to be determined. * @param data data to hash
* @return * @param len size of the data
* - GIT_SUCCESS if the object-ID was correctly determined. * @param type of the data to hash
* - GIT_ERROR if the given object is malformed. * @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type);
/**
* Close an ODB object
*
* This method must always be called once a `git_odb_object` is no
* longer needed, otherwise memory will leak.
*
* @param object object to close
*/
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(int) git_rawobj_hash(git_oid *id, git_rawobj *obj); GIT_EXTERN(const void *) git_odb_object_data(git_odb_object *object);
/** /**
* Release all memory used by the obj structure. * Return the size of an ODB object
* *
* As a result of this call, obj->data will be set to NULL. * This is the real size of the `data` buffer, not the
* actual size of the object.
* *
* If obj->data is already NULL, nothing happens. * @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 obj object descriptor to free. * @param object the object
* @return the type
*/ */
GIT_EXTERN(void) git_rawobj_close(git_rawobj *obj); GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include "common.h" #include "common.h"
#include "types.h" #include "types.h"
#include "oid.h" #include "oid.h"
#include "odb.h"
/** /**
* @file git2/backend.h * @file git2/backend.h
...@@ -39,24 +38,39 @@ ...@@ -39,24 +38,39 @@
*/ */
GIT_BEGIN_DECL GIT_BEGIN_DECL
struct git_odb_stream;
/** An instance for a custom backend */ /** An instance for a custom backend */
struct git_odb_backend { struct git_odb_backend {
git_odb *odb; git_odb *odb;
int (* read)( int (* read)(
git_rawobj *, void **, size_t *, git_otype *,
struct git_odb_backend *, struct git_odb_backend *,
const git_oid *); const git_oid *);
int (* read_header)( int (* read_header)(
git_rawobj *, size_t *, git_otype *,
struct git_odb_backend *, struct git_odb_backend *,
const git_oid *); const git_oid *);
int (* write)( int (* write)(
git_oid *id, git_oid *,
struct git_odb_backend *,
const void *,
size_t,
git_otype);
int (* writestream)(
struct git_odb_stream **,
struct git_odb_backend *, struct git_odb_backend *,
git_rawobj *obj); size_t,
git_otype);
int (* readstream)(
struct git_odb_stream **,
struct git_odb_backend *,
const git_oid *);
int (* exists)( int (* exists)(
struct git_odb_backend *, struct git_odb_backend *,
...@@ -65,12 +79,28 @@ struct git_odb_backend { ...@@ -65,12 +79,28 @@ struct git_odb_backend {
void (* free)(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_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); 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); GIT_EXTERN(int) git_odb_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db);
#endif
GIT_END_DECL GIT_END_DECL
......
...@@ -69,6 +69,27 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_reposito ...@@ -69,6 +69,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); 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. * Create a new object id reference.
* *
* The reference will be created in the repository and written * The reference will be created in the repository and written
...@@ -86,6 +107,27 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos ...@@ -86,6 +107,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); 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. * Get the OID pointed to by a reference.
* *
* Only available if the reference is direct (i.e. not symbolic) * Only available if the reference is direct (i.e. not symbolic)
...@@ -190,6 +232,20 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); ...@@ -190,6 +232,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); 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 * Delete an existing reference
* *
* This method works for both direct and symbolic references. * This method works for both direct and symbolic references.
...@@ -218,6 +274,52 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref); ...@@ -218,6 +274,52 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref);
*/ */
GIT_EXTERN(int) git_reference_packall(git_repository *repo); 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 GIT_END_DECL
#endif #endif
...@@ -154,13 +154,17 @@ GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo); ...@@ -154,13 +154,17 @@ GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo);
/** /**
* Free a previously allocated repository * 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. * @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(git_repository *repo);
GIT_EXTERN(void) git_repository_free__no_gc(git_repository *repo);
/** /**
* Creates a new Git repository in the given folder. * Creates a new Git repository in the given folder.
* *
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "common.h" #include "common.h"
#include "types.h" #include "types.h"
#include "oid.h"
/** /**
* @file git2/revwalk.h * @file git2/revwalk.h
...@@ -69,6 +70,17 @@ GIT_BEGIN_DECL ...@@ -69,6 +70,17 @@ GIT_BEGIN_DECL
/** /**
* Allocate a new revision walker to iterate through a repo. * 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 walker pointer to the new revision walker
* @param repo the repo to walk through * @param repo the repo to walk through
* @return 0 on success; error code otherwise * @return 0 on success; error code otherwise
...@@ -76,48 +88,87 @@ GIT_BEGIN_DECL ...@@ -76,48 +88,87 @@ GIT_BEGIN_DECL
GIT_EXTERN(int) git_revwalk_new(git_revwalk **walker, git_repository *repo); 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. * @param walker handle to reset.
*/ */
GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
/** /**
* Mark a commit to start traversal from. * 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 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. * 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 walker the walker being used for the traversal.
* @param commit the commit that will be ignored during 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.
*
* The initial call to this method is *not* blocking when
* iterating through a repo with a time-sorting mode.
* *
* @param commit Pointer where to store the next commit * 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. * @param walk the walker to pop the commit from.
* @return GIT_SUCCESS if the next commit was found; * @return GIT_SUCCESS if the next commit was found;
* GIT_EREVWALKOVER if there are no commits left to iterate * 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 * Change the sorting mode when iterating through the
* repository's contents. * repository's contents.
*
* Changing the sorting mode resets the walker. * Changing the sorting mode resets the walker.
*
* @param walk the walker being used for the traversal. * @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. * @param walk traversal handle to close. If NULL nothing occurs.
*/ */
GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk); GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk);
......
...@@ -45,9 +45,9 @@ GIT_BEGIN_DECL ...@@ -45,9 +45,9 @@ GIT_BEGIN_DECL
* @email email of the person * @email email of the person
* @time time when the action happened * @time time when the action happened
* @offset timezone offset in minutes for the time * @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. * Create a copy of an existing signature.
......
...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL ...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL
/** /**
* Lookup a tag object from the repository. * 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 tag pointer to the looked up tag
* @param repo the repo to use when locating the 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 ...@@ -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 * This is a wrapper around git_object_close()
* setter methods before it can be written to its
* repository.
* *
* @param tag pointer to the new tag * IMPORTANT:
* @param repo The repository where the object will reside * It *is* necessary to call this method when you stop
* @return 0 on success; error code otherwise * 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. * Get the id of a tag.
*
* @param tag a previously loaded tag. * @param tag a previously loaded tag.
* @return object identity for the tag. * @return object identity for the tag.
*/ */
...@@ -79,13 +80,27 @@ GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag); ...@@ -79,13 +80,27 @@ GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag);
/** /**
* Get the tagged object of a 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 0 on success; error code otherwise
*/
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. * @param tag a previously loaded tag.
* @return reference to a repository object * @return pointer to the OID
*/ */
GIT_EXTERN(const git_object *) git_tag_target(git_tag *t); GIT_EXTERN(const git_oid *) git_tag_target_oid(git_tag *t);
/** /**
* Get the type of a tag's tagged object * Get the type of a tag's tagged object
*
* @param tag a previously loaded tag. * @param tag a previously loaded tag.
* @return type of the tagged object * @return type of the tagged object
*/ */
...@@ -93,6 +108,7 @@ GIT_EXTERN(git_otype) git_tag_type(git_tag *t); ...@@ -93,6 +108,7 @@ GIT_EXTERN(git_otype) git_tag_type(git_tag *t);
/** /**
* Get the name of a tag * Get the name of a tag
*
* @param tag a previously loaded tag. * @param tag a previously loaded tag.
* @return name of the tag * @return name of the tag
*/ */
...@@ -100,6 +116,7 @@ GIT_EXTERN(const char *) git_tag_name(git_tag *t); ...@@ -100,6 +116,7 @@ GIT_EXTERN(const char *) git_tag_name(git_tag *t);
/** /**
* Get the tagger (author) of a tag * Get the tagger (author) of a tag
*
* @param tag a previously loaded tag. * @param tag a previously loaded tag.
* @return reference to the tag's author * @return reference to the tag's author
*/ */
...@@ -107,38 +124,69 @@ GIT_EXTERN(const git_signature *) git_tag_tagger(git_tag *t); ...@@ -107,38 +124,69 @@ GIT_EXTERN(const git_signature *) git_tag_tagger(git_tag *t);
/** /**
* Get the message of a tag * Get the message of a tag
*
* @param tag a previously loaded tag. * @param tag a previously loaded tag.
* @return message of the tag * @return message of the tag
*/ */
GIT_EXTERN(const char *) git_tag_message(git_tag *t); 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 * Create a new tag in the repository from an OID
* @param tag The tag to modify *
* @param name the new name for the tag * @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
*/
GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig);
/** /**
* Set the message of a tag * Create a new tag in the repository from an existing
* @param tag The tag to modify * `git_object` instance
* @param message the new tagger for the tag *
* 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_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 GIT_END_DECL
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
*/ */
#define GIT_HAS_TLS 1 #define GIT_HAS_TLS 1
#define GIT_HAS_PTHREAD 1
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
# undef GIT_TLS # undef GIT_TLS
...@@ -47,7 +46,6 @@ ...@@ -47,7 +46,6 @@
#elif defined(__INTEL_COMPILER) #elif defined(__INTEL_COMPILER)
# if defined(_WIN32) || defined(_WIN32_CE) # if defined(_WIN32) || defined(_WIN32_CE)
# define GIT_TLS __declspec(thread) # define GIT_TLS __declspec(thread)
# undef GIT_HAS_PTHREAD
# else # else
# define GIT_TLS __thread # define GIT_TLS __thread
# endif # endif
...@@ -56,11 +54,9 @@ ...@@ -56,11 +54,9 @@
defined(_WIN32_CE) || \ defined(_WIN32_CE) || \
defined(__BORLANDC__) defined(__BORLANDC__)
# define GIT_TLS __declspec(thread) # define GIT_TLS __declspec(thread)
# undef GIT_HAS_PTHREAD
#else #else
# undef GIT_HAS_TLS # undef GIT_HAS_TLS
# undef GIT_HAS_PTHREAD
# define GIT_TLS /* nothing: tls vars are thread-global */ # define GIT_TLS /* nothing: tls vars are thread-global */
#endif #endif
...@@ -71,10 +67,4 @@ ...@@ -71,10 +67,4 @@
# define GIT_TLS # define GIT_TLS
#endif #endif
#ifdef GIT_HAS_PTHREAD
# define GIT_THREADS 1
#else
# undef GIT_THREADS
#endif
#endif /* INCLUDE_git_thread_utils_h__ */ #endif /* INCLUDE_git_thread_utils_h__ */
...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL ...@@ -41,8 +41,6 @@ GIT_BEGIN_DECL
/** /**
* Lookup a tree object from the repository. * 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 tree pointer to the looked up tree
* @param repo the repo to use when locating the 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 ...@@ -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 * This is a wrapper around git_object_close()
* setter methods before it can be written to its
* repository.
* *
* @param tree pointer to the new tree * IMPORTANT:
* @param repo The repository where the object will reside * It *is* necessary to call this method when you stop
* @return 0 on success; error code otherwise * 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. * Get the id of a tree.
*
* @param tree a previously loaded tree. * @param tree a previously loaded tree.
* @return object identity for the tree. * @return object identity for the tree.
*/ */
GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree); GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
/** /**
* Get the number of entries listed in a tree * Get the number of entries listed in a tree
*
* @param tree a previously loaded tree. * @param tree a previously loaded tree.
* @return the number of entries in the tree * @return the number of entries in the tree
*/ */
...@@ -87,6 +88,7 @@ GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree); ...@@ -87,6 +88,7 @@ GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree);
/** /**
* Lookup a tree entry by its filename * Lookup a tree entry by its filename
*
* @param tree a previously loaded tree. * @param tree a previously loaded tree.
* @param filename the filename of the desired entry * @param filename the filename of the desired entry
* @return the tree entry; NULL if not found * @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 ...@@ -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 * Lookup a tree entry by its position in the tree
*
* @param tree a previously loaded tree. * @param tree a previously loaded tree.
* @param idx the position in the entry list * @param idx the position in the entry list
* @return the tree entry; NULL if not found * @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); ...@@ -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 * Get the UNIX file attributes of a tree entry
*
* @param entry a tree entry * @param entry a tree entry
* @return attributes as an integer * @return attributes as an integer
*/ */
...@@ -110,6 +114,7 @@ GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry); ...@@ -110,6 +114,7 @@ GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry);
/** /**
* Get the filename of a tree entry * Get the filename of a tree entry
*
* @param entry a tree entry * @param entry a tree entry
* @return the name of the file * @return the name of the file
*/ */
...@@ -117,6 +122,7 @@ GIT_EXTERN(const char *) git_tree_entry_name(git_tree_entry *entry); ...@@ -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 * Get the id of the object pointed by the entry
*
* @param entry a tree entry * @param entry a tree entry
* @return the oid of the object * @return the oid of the object
*/ */
...@@ -126,97 +132,11 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry); ...@@ -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. * Convert a tree entry to the git_object it points too.
* *
* @param object pointer to the converted object * @param object pointer to the converted object
* @param repo repository where to lookup the pointed object
* @param entry a tree entry * @param entry a tree entry
* @return a reference to the pointed object in the repository * @return a reference to the pointed object in the repository
*/ */
GIT_EXTERN(int) git_tree_entry_2object(git_object **object, git_tree_entry *entry); GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, 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_END_DECL GIT_END_DECL
......
...@@ -52,12 +52,12 @@ GIT_BEGIN_DECL ...@@ -52,12 +52,12 @@ GIT_BEGIN_DECL
#if defined(_MSC_VER) #if defined(_MSC_VER)
typedef __int64 git_off_t; typedef __int64 git_off_t;
typedef __time64_t git_time_t; typedef __time64_t git_time_t;
#elif defined(__MINGW32__) #elif defined(__MINGW32__)
typedef off64_t git_off_t; typedef off64_t git_off_t;
typedef time_t git_time_t; typedef __time64_t git_time_t;
#else /* POSIX */ #else /* POSIX */
...@@ -66,12 +66,11 @@ typedef time_t git_time_t; ...@@ -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 * before us (directly or indirectly), they'll get 32 bit off_t in their client
* app, even though /we/ define _FILE_OFFSET_BITS=64. * app, even though /we/ define _FILE_OFFSET_BITS=64.
*/ */
typedef long long git_off_t; typedef int64_t git_off_t;
typedef time_t git_time_t; typedef int64_t git_time_t;
#endif #endif
/** Basic type (loose or packed) of any Git object. */ /** Basic type (loose or packed) of any Git object. */
typedef enum { typedef enum {
GIT_OBJ_ANY = -2, /**< Object can be any of the following */ GIT_OBJ_ANY = -2, /**< Object can be any of the following */
...@@ -92,6 +91,12 @@ typedef struct git_odb git_odb; ...@@ -92,6 +91,12 @@ typedef struct git_odb git_odb;
/** A custom backend in an ODB */ /** A custom backend in an ODB */
typedef struct git_odb_backend git_odb_backend; 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, * Representation of an existing git repository,
* including all its object contents * including all its object contents
...@@ -130,7 +135,7 @@ typedef struct git_cvar git_cvar; ...@@ -130,7 +135,7 @@ typedef struct git_cvar git_cvar;
/** Time in a signature */ /** Time in a signature */
typedef struct git_time { 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 */ int offset; /** timezone offset, in minutes */
} git_time; } git_time;
...@@ -151,6 +156,7 @@ typedef enum { ...@@ -151,6 +156,7 @@ typedef enum {
GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */ GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */
GIT_REF_PACKED = 4, GIT_REF_PACKED = 4,
GIT_REF_HAS_PEEL = 8, GIT_REF_HAS_PEEL = 8,
GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED,
} git_rtype; } git_rtype;
/** @} */ /** @} */
......
...@@ -44,21 +44,20 @@ typedef struct { ...@@ -44,21 +44,20 @@ typedef struct {
sqlite3_stmt *st_read_header; sqlite3_stmt *st_read_header;
} sqlite_backend; } 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; sqlite_backend *backend;
int error; int error;
assert(obj && _backend && oid); assert(len_p && type_p && _backend && oid);
backend = (sqlite_backend *)_backend; backend = (sqlite_backend *)_backend;
error = GIT_ERROR; 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_bind_text(backend->st_read_header, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) == SQLITE_OK) {
if (sqlite3_step(backend->st_read_header) == SQLITE_ROW) { if (sqlite3_step(backend->st_read_header) == SQLITE_ROW) {
obj->type = sqlite3_column_int(backend->st_read_header, 0); *type_p = (git_otype)sqlite3_column_int(backend->st_read_header, 0);
obj->len = sqlite3_column_int(backend->st_read_header, 1); *len_p = (size_t)sqlite3_column_int(backend->st_read_header, 1);
assert(sqlite3_step(backend->st_read_header) == SQLITE_DONE); assert(sqlite3_step(backend->st_read_header) == SQLITE_DONE);
error = GIT_SUCCESS; error = GIT_SUCCESS;
} else { } else {
...@@ -71,26 +70,26 @@ int sqlite_backend__read_header(git_rawobj *obj, git_odb_backend *_backend, cons ...@@ -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; sqlite_backend *backend;
int error; int error;
assert(obj && _backend && oid); assert(data_p && len_p && type_p && _backend && oid);
backend = (sqlite_backend *)_backend; backend = (sqlite_backend *)_backend;
error = GIT_ERROR; error = GIT_ERROR;
if (sqlite3_bind_text(backend->st_read, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) == SQLITE_OK) { if (sqlite3_bind_text(backend->st_read, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) == SQLITE_OK) {
if (sqlite3_step(backend->st_read) == SQLITE_ROW) { if (sqlite3_step(backend->st_read) == SQLITE_ROW) {
obj->type = sqlite3_column_int(backend->st_read, 0); *type_p = (git_otype)sqlite3_column_int(backend->st_read, 0);
obj->len = sqlite3_column_int(backend->st_read, 1); *len_p = (size_t)sqlite3_column_int(backend->st_read, 1);
obj->data = git__malloc(obj->len); *data_p = git__malloc(*len_p);
if (obj->data == NULL) { if (*data_p == NULL) {
error = GIT_ENOMEM; error = GIT_ENOMEM;
} else { } 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; error = GIT_SUCCESS;
} }
...@@ -126,27 +125,24 @@ int sqlite_backend__exists(git_odb_backend *_backend, const git_oid *oid) ...@@ -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; int error;
sqlite_backend *backend; sqlite_backend *backend;
assert(id && _backend && obj); assert(id && _backend && data);
backend = (sqlite_backend *)_backend; 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; return error;
error = SQLITE_ERROR; error = SQLITE_ERROR;
if (sqlite3_bind_text(backend->st_write, 1, (char *)id->id, 20, SQLITE_TRANSIENT) == SQLITE_OK && 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, 2, (int)type) == SQLITE_OK &&
sqlite3_bind_int(backend->st_write, 3, obj->len) == SQLITE_OK && sqlite3_bind_int(backend->st_write, 3, len) == SQLITE_OK &&
sqlite3_bind_blob(backend->st_write, 4, obj->data, obj->len, SQLITE_TRANSIENT) == SQLITE_OK) { sqlite3_bind_blob(backend->st_write, 4, data, len, SQLITE_TRANSIENT) == SQLITE_OK) {
error = sqlite3_step(backend->st_write); error = sqlite3_step(backend->st_write);
} }
...@@ -272,4 +268,13 @@ cleanup: ...@@ -272,4 +268,13 @@ cleanup:
return GIT_ERROR; 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 */ #endif /* HAVE_SQLITE3 */
...@@ -33,106 +33,89 @@ ...@@ -33,106 +33,89 @@
const void *git_blob_rawcontent(git_blob *blob) const void *git_blob_rawcontent(git_blob *blob)
{ {
assert(blob); assert(blob);
return blob->odb_object->raw.data;
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;
} }
int git_blob_rawsize(git_blob *blob) int git_blob_rawsize(git_blob *blob)
{ {
assert(blob); assert(blob);
return blob->odb_object->raw.len;
if (blob->content.data != NULL)
return blob->content.len;
return blob->object.source.raw.len;
} }
void git_blob__free(git_blob *blob) void git_blob__free(git_blob *blob)
{ {
gitfo_free_buf(&blob->content); git_odb_object_close(blob->odb_object);
free(blob); free(blob);
} }
int git_blob__parse(git_blob *blob) int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
{ {
assert(blob); assert(blob);
git_cached_obj_incref((git_cached_obj *)odb_obj);
blob->odb_object = odb_obj;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_blob__writeback(git_blob *blob, git_odb_source *src) int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
{
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); int error;
git_odb_stream *stream;
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); if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
blob->content.len = len; return error;
if (blob->content.data == NULL) stream->write(stream, buffer, len);
return GIT_ENOMEM;
memcpy(blob->content.data, buffer, len); error = stream->finalize_write(oid, stream);
stream->free(stream);
return GIT_SUCCESS; return error;
} }
int git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename) int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
{ {
assert(blob && filename); int error, fd;
blob->object.modified = 1; char full_path[GIT_PATH_MAX];
char buffer[2048];
git_off_t size;
git_odb_stream *stream;
if (blob->content.data != NULL) if (repo->path_workdir == NULL)
gitfo_free_buf(&blob->content); return GIT_ENOTFOUND;
return gitfo_read_file(&blob->content, filename);
}
int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path) git__joinpath(full_path, repo->path_workdir, path);
{
int error;
git_blob *blob;
if (gitfo_exists(path) < 0) if ((fd = gitfo_open(full_path, O_RDONLY)) < 0)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
if ((error = git_blob_new(&blob, repo)) < GIT_SUCCESS) if ((size = gitfo_size(fd)) < 0 || !git__is_sizet(size)) {
return error; gitfo_close(fd);
return GIT_EOSERR;
}
if ((error = git_blob_set_rawcontent_fromfile(blob, path)) < GIT_SUCCESS) if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) {
gitfo_close(fd);
return error; return error;
}
if ((error = git_object_write((git_object *)blob)) < GIT_SUCCESS) while (size > 0) {
return error; ssize_t read_len;
git_oid_cpy(written_id, git_object_id((git_object *)blob)); read_len = read(fd, buffer, sizeof(buffer));
/* FIXME: maybe we don't want to free this already? if (read_len < 0) {
* the user may want to access it again */ gitfo_close(fd);
GIT_OBJECT_DECREF(repo, blob); stream->free(stream);
return GIT_SUCCESS; return GIT_EOSERR;
}
stream->write(stream, buffer, read_len);
size -= read_len;
}
error = stream->finalize_write(oid, stream);
stream->free(stream);
return error;
} }
...@@ -3,15 +3,15 @@ ...@@ -3,15 +3,15 @@
#include "git2/blob.h" #include "git2/blob.h"
#include "repository.h" #include "repository.h"
#include "odb.h"
#include "fileops.h" #include "fileops.h"
struct git_blob { struct git_blob {
git_object object; git_object object;
gitfo_buf content; git_odb_object *odb_object;
}; };
void git_blob__free(git_blob *blob); void git_blob__free(git_blob *blob);
int git_blob__parse(git_blob *blob); int git_blob__parse(git_blob *blob, git_odb_object *obj);
int git_blob__writeback(git_blob *blob, git_odb_source *src);
#endif #endif
/*
* 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;
}
#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
...@@ -11,22 +11,17 @@ ...@@ -11,22 +11,17 @@
struct git_commit { struct git_commit {
git_object object; git_object object;
git_vector parents; git_vector parent_oids;
git_oid tree_oid;
git_tree *tree;
git_signature *author; git_signature *author;
git_signature *committer; git_signature *committer;
char *message; char *message;
char *message_short; char *message_short;
unsigned full_parse:1;
}; };
void git_commit__free(git_commit *c); void git_commit__free(git_commit *c);
int git_commit__parse(git_commit *commit); int git_commit__parse(git_commit *commit, git_odb_object *obj);
int git_commit__parse_full(git_commit *commit);
int git_commit__writeback(git_commit *commit, git_odb_source *src);
#endif #endif
...@@ -11,9 +11,6 @@ ...@@ -11,9 +11,6 @@
#include "git2/thread-utils.h" #include "git2/thread-utils.h"
#include "cc-compat.h" #include "cc-compat.h"
#ifdef GIT_HAS_PTHREAD
# include <pthread.h>
#endif
#ifdef GIT_HAVE_INTTYPES_H #ifdef GIT_HAVE_INTTYPES_H
# include <inttypes.h> # include <inttypes.h>
#endif #endif
...@@ -34,16 +31,21 @@ ...@@ -34,16 +31,21 @@
# include <windows.h> # include <windows.h>
# include "msvc-compat.h" # include "msvc-compat.h"
# include "mingw-compat.h" # include "mingw-compat.h"
# ifdef GIT_THREADS
# include "win32/pthread.h"
#endif
# define snprintf _snprintf # define snprintf _snprintf
typedef SSIZE_T ssize_t; typedef SSIZE_T ssize_t;
#else #else
# include <unistd.h> # include <unistd.h>
# include <arpa/inet.h> # include <arpa/inet.h>
# ifdef GIT_THREADS
# include <pthread.h>
# endif
#endif #endif
#include "git2/common.h" #include "git2/common.h"
......
#ifndef INCLUDE_delta_apply_h__ #ifndef INCLUDE_delta_apply_h__
#define INCLUDE_delta_apply_h__ #define INCLUDE_delta_apply_h__
#include "odb.h"
/** /**
* Apply a git binary delta to recover the original content. * Apply a git binary delta to recover the original content.
* *
......
...@@ -27,7 +27,9 @@ static struct { ...@@ -27,7 +27,9 @@ static struct {
{GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"}, {GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},
{GIT_EINVALIDPATH, "The path is invalid" }, {GIT_EINVALIDPATH, "The path is invalid" },
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"}, {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) const char *git_strerror(int num)
......
...@@ -77,44 +77,81 @@ void git_filebuf_cleanup(git_filebuf *file) ...@@ -77,44 +77,81 @@ void git_filebuf_cleanup(git_filebuf *file)
if (file->fd >= 0) if (file->fd >= 0)
gitfo_close(file->fd); 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); gitfo_unlink(file->path_lock);
if (file->digest) if (file->digest)
git_hash_free_ctx(file->digest); git_hash_free_ctx(file->digest);
free(file->buffer); free(file->buffer);
free(file->z_buf);
#ifdef GIT_FILEBUF_THREADS deflateEnd(&file->zs);
free(file->buffer_back);
#endif
free(file->path_original); free(file->path_original);
free(file->path_lock); 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) { static int write_normal(git_filebuf *file, const void *source, size_t len)
result = gitfo_write(file->fd, file->buffer, file->buf_pos); {
if (file->digest) int result = 0;
git_hash_update(file->digest, file->buffer, file->buf_pos);
file->buf_pos = 0; if (len > 0) {
result = gitfo_write(file->fd, (void *)source, len);
if (file->digest)
git_hash_update(file->digest, source, len);
} }
return result; 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 git_filebuf_open(git_filebuf *file, const char *path, int flags)
{ {
int error; int error;
size_t path_len; size_t path_len;
if (file == NULL || path == NULL) assert(file && path);
return GIT_ERROR;
memset(file, 0x0, sizeof(git_filebuf)); memset(file, 0x0, sizeof(git_filebuf));
...@@ -122,46 +159,87 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) ...@@ -122,46 +159,87 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
file->buf_pos = 0; file->buf_pos = 0;
file->fd = -1; file->fd = -1;
path_len = strlen(path); /* Allocate the main cache buffer */
file->buffer = git__malloc(file->buf_size);
file->path_original = git__strdup(path); if (file->buffer == NULL){
if (file->path_original == NULL) {
error = GIT_ENOMEM; error = GIT_ENOMEM;
goto cleanup; goto cleanup;
} }
file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH); /* If we are hashing on-write, allocate a new hash context */
if (file->path_lock == NULL) { if (flags & GIT_FILEBUF_HASH_CONTENTS) {
error = GIT_ENOMEM; if ((file->digest = git_hash_new_ctx()) == NULL) {
goto cleanup; error = GIT_ENOMEM;
goto cleanup;
}
} }
memcpy(file->path_lock, file->path_original, path_len); /* If we are deflating on-write, */
memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH); if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) {
file->buffer = git__malloc(file->buf_size); /* Initialize the ZLib stream */
if (file->buffer == NULL){ if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
error = GIT_ENOMEM; error = GIT_EZLIB;
goto cleanup; goto cleanup;
} }
#ifdef GIT_FILEBUF_THREADS /* Allocate the Zlib cache buffer */
file->buffer_back = git__malloc(file->buf_size); file->z_buf = git__malloc(file->buf_size);
if (file->buffer_back == NULL){ if (file->z_buf == NULL){
error = GIT_ENOMEM; error = GIT_ENOMEM;
goto cleanup; goto cleanup;
}
/* Never flush */
file->flush_mode = Z_NO_FLUSH;
file->write = &write_deflate;
} else {
file->write = &write_normal;
} }
#endif
if (flags & GIT_FILEBUF_HASH_CONTENTS) { /* If we are writing to a temp file */
if ((file->digest = git_hash_new_ctx()) == NULL) { 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; error = GIT_ENOMEM;
goto cleanup; goto cleanup;
} }
} } else {
path_len = strlen(path);
if ((error = lock_file(file, flags)) < GIT_SUCCESS) /* Save the original path of the file */
goto cleanup; 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; return GIT_SUCCESS;
...@@ -187,10 +265,25 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file) ...@@ -187,10 +265,25 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file)
return GIT_SUCCESS; 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 git_filebuf_commit(git_filebuf *file)
{ {
int error; 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) if ((error = flush_buffer(file)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -204,16 +297,16 @@ cleanup: ...@@ -204,16 +297,16 @@ cleanup:
return error; 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); memcpy(file->buffer + file->buf_pos, buf, len);
file->buf_pos += 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; int error;
unsigned char *buf = buff; const unsigned char *buf = buff;
for (;;) { for (;;) {
size_t space_left = file->buf_size - file->buf_pos; 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) ...@@ -237,9 +330,9 @@ int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
/* write too-large chunks immediately */ /* write too-large chunks immediately */
if (len > file->buf_size) { if (len > file->buf_size) {
error = gitfo_write(file->fd, buf, len); error = file->write(file, buf, len);
if (file->digest) if (error < GIT_SUCCESS)
git_hash_update(file->digest, buf, len); return error;
} }
} }
} }
......
...@@ -3,14 +3,17 @@ ...@@ -3,14 +3,17 @@
#include "fileops.h" #include "fileops.h"
#include "hash.h" #include "hash.h"
#include "git2/zlib.h"
#ifdef GIT_THREADS #ifdef GIT_THREADS
# define GIT_FILEBUF_THREADS # define GIT_FILEBUF_THREADS
#endif #endif
#define GIT_FILEBUF_HASH_CONTENTS 0x1 #define GIT_FILEBUF_HASH_CONTENTS (1 << 0)
#define GIT_FILEBUF_APPEND 0x2 #define GIT_FILEBUF_APPEND (1 << 2)
#define GIT_FILEBUF_FORCE 0x4 #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_EXTENSION ".lock\0"
#define GIT_FILELOCK_EXTLENGTH 6 #define GIT_FILELOCK_EXTLENGTH 6
...@@ -19,12 +22,16 @@ struct git_filebuf { ...@@ -19,12 +22,16 @@ struct git_filebuf {
char *path_original; char *path_original;
char *path_lock; char *path_lock;
int (*write)(struct git_filebuf *file,
const void *source, size_t len);
git_hash_ctx *digest; git_hash_ctx *digest;
unsigned char *buffer; unsigned char *buffer;
#ifdef GIT_FILEBUF_THREADS unsigned char *z_buf;
unsigned char *buffer_back;
#endif z_stream zs;
int flush_mode;
size_t buf_size, buf_pos; size_t buf_size, buf_pos;
git_file fd; git_file fd;
...@@ -32,12 +39,13 @@ struct git_filebuf { ...@@ -32,12 +39,13 @@ struct git_filebuf {
typedef struct git_filebuf 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_reserve(git_filebuf *file, void **buff, size_t len);
int git_filebuf_printf(git_filebuf *file, const char *format, ...); 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_open(git_filebuf *lock, const char *path, int flags);
int git_filebuf_commit(git_filebuf *lock); 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); void git_filebuf_cleanup(git_filebuf *lock);
int git_filebuf_hash(git_oid *oid, git_filebuf *file); int git_filebuf_hash(git_oid *oid, git_filebuf *file);
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
#include "fileops.h" #include "fileops.h"
#include <ctype.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 ? */ const int mode = 0755; /* or 0777 ? */
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
char target_folder_path[GIT_PATH_MAX]; 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) if (error < GIT_SUCCESS)
return error; return error;
...@@ -25,6 +25,27 @@ static int force_path(const char *to) ...@@ -25,6 +25,27 @@ static int force_path(const char *to)
return GIT_SUCCESS; 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 gitfo_open(const char *path, int flags)
{ {
int fd = open(path, flags | O_BINARY); int fd = open(path, flags | O_BINARY);
...@@ -39,7 +60,7 @@ int gitfo_creat(const char *path, int mode) ...@@ -39,7 +60,7 @@ int gitfo_creat(const char *path, int mode)
int gitfo_creat_force(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 GIT_EOSERR;
return gitfo_creat(path, mode); return gitfo_creat(path, mode);
...@@ -117,6 +138,7 @@ int gitfo_isdir(const char *path) ...@@ -117,6 +138,7 @@ int gitfo_isdir(const char *path)
int gitfo_exists(const char *path) int gitfo_exists(const char *path)
{ {
assert(path);
return access(path, F_OK); return access(path, F_OK);
} }
...@@ -181,7 +203,7 @@ int gitfo_mv(const char *from, const char *to) ...@@ -181,7 +203,7 @@ int gitfo_mv(const char *from, const char *to)
* file exists, the `rename` call fails. This is as * file exists, the `rename` call fails. This is as
* close as it gets with the Win32 API. * 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 #else
/* Don't even try this on Win32 */ /* Don't even try this on Win32 */
if (!link(from, to)) { if (!link(from, to)) {
...@@ -198,7 +220,7 @@ int gitfo_mv(const char *from, const char *to) ...@@ -198,7 +220,7 @@ int gitfo_mv(const char *from, const char *to)
int gitfo_mv_force(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 GIT_EOSERR;
return gitfo_mv(from, to); return gitfo_mv(from, to);
...@@ -361,22 +383,29 @@ int gitfo_dirent( ...@@ -361,22 +383,29 @@ int gitfo_dirent(
return GIT_SUCCESS; return GIT_SUCCESS;
} }
#ifdef GIT_WIN32
static int is_windows_rooted_path(const char *path) int retrieve_path_root_offset(const char *path)
{ {
int offset = 0;
#ifdef GIT_WIN32
/* Does the root of the path look like a windows drive ? */ /* Does the root of the path look like a windows drive ? */
if (isalpha(path[0]) && (path[1] == ':')) if (isalpha(path[0]) && (path[1] == ':'))
return GIT_SUCCESS; offset += 2;
#endif
if (*(path + offset) == '/')
return offset;
return GIT_ERROR; return GIT_ERROR;
} }
#endif
int gitfo_mkdir_recurs(const char *path, int mode) int gitfo_mkdir_recurs(const char *path, int mode)
{ {
int error; int error, root_path_offset;
char *pp, *sp; char *pp, *sp;
char *path_copy = git__strdup(path); char *path_copy = git__strdup(path);
...@@ -386,12 +415,9 @@ int gitfo_mkdir_recurs(const char *path, int mode) ...@@ -386,12 +415,9 @@ int gitfo_mkdir_recurs(const char *path, int mode)
error = GIT_SUCCESS; error = GIT_SUCCESS;
pp = path_copy; pp = path_copy;
#ifdef GIT_WIN32 root_path_offset = retrieve_path_root_offset(pp);
if (root_path_offset > 0)
if (!is_windows_rooted_path(pp)) pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
pp += 2; /* Skip the drive name (eg. C: or D:) */
#endif
while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != 0) { while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != 0) {
if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) { if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) {
...@@ -417,8 +443,12 @@ int gitfo_mkdir_recurs(const char *path, int mode) ...@@ -417,8 +443,12 @@ int gitfo_mkdir_recurs(const char *path, int mode)
static int retrieve_previous_path_component_start(const char *path) 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); len = strlen(path);
offset = len - 1; offset = len - 1;
...@@ -430,7 +460,7 @@ static int retrieve_previous_path_component_start(const char *path) ...@@ -430,7 +460,7 @@ static int retrieve_previous_path_component_start(const char *path)
if (path[offset] == '/') if (path[offset] == '/')
offset--; offset--;
if (offset < 0) if (offset < root_offset)
return GIT_ERROR; return GIT_ERROR;
while (offset > start && path[offset-1] != '/') { while (offset > start && path[offset-1] != '/') {
...@@ -440,15 +470,25 @@ static int retrieve_previous_path_component_start(const char *path) ...@@ -440,15 +470,25 @@ static int retrieve_previous_path_component_start(const char *path)
return offset; 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; char *current;
const char *buffer_out_start, *buffer_end; const char *buffer_out_start, *buffer_end;
buffer_out_start = buffer_out;
current = (char *)path; current = (char *)path;
buffer_end = path + strlen(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) { while (current < buffer_end) {
/* Prevent multiple slashes from being added to the output */ /* Prevent multiple slashes from being added to the output */
...@@ -461,7 +501,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) ...@@ -461,7 +501,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
segment_len = 0; segment_len = 0;
/* Copy path segment to the output */ /* Copy path segment to the output */
while (current < buffer_end && *current !='/') while (current < buffer_end && *current != '/')
{ {
only_dots &= (*current == '.'); only_dots &= (*current == '.');
*buffer_out++ = *current++; *buffer_out++ = *current++;
...@@ -486,7 +526,9 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) ...@@ -486,7 +526,9 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
*buffer_out ='\0'; *buffer_out ='\0';
len = retrieve_previous_path_component_start(buffer_out_start); 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; return GIT_EINVALIDPATH;
buffer_out = (char *)buffer_out_start + len; buffer_out = (char *)buffer_out_start + len;
...@@ -494,7 +536,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) ...@@ -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) */ /* 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; return GIT_EINVALIDPATH;
*buffer_out++ = '/'; *buffer_out++ = '/';
...@@ -506,20 +548,24 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) ...@@ -506,20 +548,24 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
return GIT_SUCCESS; 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; int error, path_len, i;
const char* pattern = "/.."; const char* pattern = "/..";
path_len = strlen(path); 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 "/.." */ /* Let's make sure the filename doesn't end with "/", "/." or "/.." */
for (i = 1; path_len > i && i < 4; i++) { for (i = 1; path_len > i && i < 4; i++) {
if (!strncmp(path + path_len - i, pattern, i)) if (!strncmp(path + path_len - i, pattern, i))
return GIT_EINVALIDPATH; return GIT_EINVALIDPATH;
} }
error = gitfo_prettify_dir_path(buffer_out, path); error = gitfo_prettify_dir_path(buffer_out, size, path);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
...@@ -551,3 +597,34 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1, ...@@ -551,3 +597,34 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1,
return 0; return 0;
} }
static void posixify_path(char *path)
{
while (*path) {
if (*path == '\\')
*path = '/';
path++;
}
}
int gitfo_getcwd(char *buffer_out, size_t size)
{
char *cwd_buffer;
assert(buffer_out && size > 0);
#ifdef GIT_WIN32
cwd_buffer = _getcwd(buffer_out, size);
#else
cwd_buffer = getcwd(buffer_out, size); //TODO: Fixme. Ensure the required headers are correctly included
#endif
if (cwd_buffer == NULL)
return GIT_EOSERR;
posixify_path(buffer_out);
git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash
return GIT_SUCCESS;
}
...@@ -58,8 +58,10 @@ extern int gitfo_exists(const char *path); ...@@ -58,8 +58,10 @@ extern int gitfo_exists(const char *path);
extern int gitfo_open(const char *path, int flags); extern int gitfo_open(const char *path, int flags);
extern int gitfo_creat(const char *path, int mode); extern int gitfo_creat(const char *path, int mode);
extern int gitfo_creat_force(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_isdir(const char *path);
extern int gitfo_mkdir_recurs(const char *path, int mode); extern int gitfo_mkdir_recurs(const char *path, int mode);
extern int gitfo_mkdir_2file(const char *path);
#define gitfo_close(fd) close(fd) #define gitfo_close(fd) close(fd)
extern int gitfo_read(git_file fd, void *buf, size_t cnt); extern int gitfo_read(git_file fd, void *buf, size_t cnt);
...@@ -142,6 +144,8 @@ extern int gitfo_close_cached(gitfo_cache *ioc); ...@@ -142,6 +144,8 @@ extern int gitfo_close_cached(gitfo_cache *ioc);
extern int gitfo_cmp_path(const char *name1, int len1, int isdir1, extern int gitfo_cmp_path(const char *name1, int len1, int isdir1,
const char *name2, int len2, int isdir2); 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. * 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, ...@@ -159,12 +163,13 @@ extern int gitfo_cmp_path(const char *name1, int len1, int isdir1,
* the file system perspective. * the file system perspective.
* *
* @param buffer_out buffer to populate with the normalized path. * @param buffer_out buffer to populate with the normalized path.
* @param size buffer size.
* @param path directory path to clean up. * @param path directory path to clean up.
* @return * @return
* - GIT_SUCCESS on success; * - GIT_SUCCESS on success;
* - GIT_ERROR when the input path is invalid or escapes the current directory. * - 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. * 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); ...@@ -181,11 +186,13 @@ GIT_EXTERN(int) gitfo_prettify_dir_path(char *buffer_out, const char *path);
* the file system perspective. * the file system perspective.
* *
* @param buffer_out buffer to populate with the normalized path. * @param buffer_out buffer to populate with the normalized path.
* @param size buffer size.
* @param path file path to clean up. * @param path file path to clean up.
* @return * @return
* - GIT_SUCCESS on success; * - GIT_SUCCESS on success;
* - GIT_ERROR when the input path is invalid or escapes the current directory. * - 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__ */ #endif /* INCLUDE_fileops_h__ */
...@@ -184,6 +184,8 @@ int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, voi ...@@ -184,6 +184,8 @@ int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, voi
int hash_id; int hash_id;
git_hashtable_node *node; git_hashtable_node *node;
assert(self && self->nodes);
*old_value = NULL; *old_value = NULL;
for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { 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) ...@@ -218,6 +220,8 @@ void *git_hashtable_lookup(git_hashtable *self, const void *key)
int hash_id; int hash_id;
git_hashtable_node *node; git_hashtable_node *node;
assert(self && self->nodes);
for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {
node = node_with_hash(self, key, hash_id); node = node_with_hash(self, key, hash_id);
if (node->key && self->key_equal(key, node->key) == 0) if (node->key && self->key_equal(key, node->key) == 0)
...@@ -232,6 +236,8 @@ int git_hashtable_remove(git_hashtable *self, const void *key) ...@@ -232,6 +236,8 @@ int git_hashtable_remove(git_hashtable *self, const void *key)
int hash_id; int hash_id;
git_hashtable_node *node; git_hashtable_node *node;
assert(self && self->nodes);
for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {
node = node_with_hash(self, key, hash_id); node = node_with_hash(self, key, hash_id);
if (node->key && self->key_equal(key, node->key) == 0) { if (node->key && self->key_equal(key, node->key) == 0) {
......
...@@ -74,7 +74,7 @@ struct entry_short { ...@@ -74,7 +74,7 @@ struct entry_short {
uint32_t file_size; uint32_t file_size;
git_oid oid; git_oid oid;
uint16_t flags; uint16_t flags;
char path[1]; /* arbritrary length */ char path[1]; /* arbitrary length */
}; };
struct entry_long { struct entry_long {
...@@ -89,7 +89,7 @@ struct entry_long { ...@@ -89,7 +89,7 @@ struct entry_long {
git_oid oid; git_oid oid;
uint16_t flags; uint16_t flags;
uint16_t flags_extended; uint16_t flags_extended;
char path[1]; /* arbritrary length */ char path[1]; /* arbitrary length */
}; };
/* local declarations */ /* local declarations */
...@@ -148,7 +148,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const ...@@ -148,7 +148,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const
index->on_disk = 1; index->on_disk = 1;
*index_out = index; *index_out = index;
return GIT_SUCCESS; return git_index_read(index);
} }
int git_index_open_bare(git_index **index_out, const char *index_path) 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) ...@@ -312,8 +312,8 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
memset(&entry, 0x0, sizeof(git_index_entry)); memset(&entry, 0x0, sizeof(git_index_entry));
entry.ctime.seconds = st.st_ctime; entry.ctime.seconds = (git_time_t)st.st_ctime;
entry.mtime.seconds = st.st_mtime; entry.mtime.seconds = (git_time_t)st.st_mtime;
/* entry.mtime.nanoseconds = st.st_mtimensec; */ /* entry.mtime.nanoseconds = st.st_mtimensec; */
/* entry.ctime.nanoseconds = st.st_ctimensec; */ /* entry.ctime.nanoseconds = st.st_ctimensec; */
entry.dev= st.st_rdev; entry.dev= st.st_rdev;
...@@ -324,7 +324,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage) ...@@ -324,7 +324,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
entry.file_size = st.st_size; entry.file_size = st.st_size;
/* write the blob to disk and get the oid */ /* 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; return error;
entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT); 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 ...@@ -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); source = (const struct entry_short *)(buffer);
dest->ctime.seconds = (time_t)ntohl(source->ctime.seconds); dest->ctime.seconds = (git_time_t)ntohl(source->ctime.seconds);
dest->ctime.nanoseconds = (time_t)ntohl(source->ctime.nanoseconds); dest->ctime.nanoseconds = ntohl(source->ctime.nanoseconds);
dest->mtime.seconds = (time_t)ntohl(source->mtime.seconds); dest->mtime.seconds = (git_time_t)ntohl(source->mtime.seconds);
dest->mtime.nanoseconds = (time_t)ntohl(source->mtime.nanoseconds); dest->mtime.nanoseconds = ntohl(source->mtime.nanoseconds);
dest->dev = ntohl(source->dev); dest->dev = ntohl(source->dev);
dest->ino = ntohl(source->ino); dest->ino = ntohl(source->ino);
dest->mode = ntohl(source->mode); dest->mode = ntohl(source->mode);
......
...@@ -66,153 +66,6 @@ static struct { ...@@ -66,153 +66,6 @@ static struct {
{ "REF_DELTA", 0, 0 } { "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) static int create_object(git_object **object_out, git_otype type)
{ {
git_object *object = NULL; git_object *object = NULL;
...@@ -225,43 +78,19 @@ static int create_object(git_object **object_out, git_otype type) ...@@ -225,43 +78,19 @@ static int create_object(git_object **object_out, git_otype type)
case GIT_OBJ_COMMIT: case GIT_OBJ_COMMIT:
case GIT_OBJ_TAG: case GIT_OBJ_TAG:
case GIT_OBJ_BLOB: case GIT_OBJ_BLOB:
case GIT_OBJ_TREE:
object = git__malloc(git_object__size(type)); object = git__malloc(git_object__size(type));
if (object == NULL) if (object == NULL)
return GIT_ENOMEM; return GIT_ENOMEM;
memset(object, 0x0, git_object__size(type)); memset(object, 0x0, git_object__size(type));
break; break;
case GIT_OBJ_TREE:
object = (git_object *)git_tree__new();
if (object == NULL)
return GIT_ENOMEM;
break;
default: default:
return GIT_EINVALIDTYPE; return GIT_EINVALIDTYPE;
} }
*object_out = object; object->type = type;
return GIT_SUCCESS;
}
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; *object_out = object;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -269,122 +98,77 @@ int git_object_new(git_object **object_out, git_repository *repo, git_otype type ...@@ -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) int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type)
{ {
git_object *object = NULL; git_object *object = NULL;
git_rawobj obj_file; git_odb_object *odb_obj;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
assert(repo && object_out && id); assert(repo && object_out && id);
object = git_hashtable_lookup(repo->objects, id); object = git_cache_get(&repo->objects, id);
if (object != NULL) { if (object != NULL) {
if (type != GIT_OBJ_ANY && type != object->type)
return GIT_EINVALIDTYPE;
*object_out = object; *object_out = object;
GIT_OBJECT_INCREF(repo, object);
return GIT_SUCCESS; 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) if (error < GIT_SUCCESS)
return error; return error;
if (type != GIT_OBJ_ANY && type != obj_file.type) { if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
git_rawobj_close(&obj_file); git_odb_object_close(odb_obj);
return GIT_EINVALIDTYPE; return GIT_EINVALIDTYPE;
} }
type = obj_file.type; type = odb_obj->raw.type;
if ((error = create_object(&object, type)) < GIT_SUCCESS) if ((error = create_object(&object, type)) < GIT_SUCCESS)
return error; return error;
/* Initialize parent object */ /* Initialize parent object */
git_oid_cpy(&object->id, id); git_oid_cpy(&object->cached.oid, id);
object->repo = repo; object->repo = repo;
memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj));
object->source.open = 1;
switch (type) { switch (type) {
case GIT_OBJ_COMMIT: case GIT_OBJ_COMMIT:
error = git_commit__parse((git_commit *)object); error = git_commit__parse((git_commit *)object, odb_obj);
break; break;
case GIT_OBJ_TREE: case GIT_OBJ_TREE:
error = git_tree__parse((git_tree *)object); error = git_tree__parse((git_tree *)object, odb_obj);
break; break;
case GIT_OBJ_TAG: case GIT_OBJ_TAG:
error = git_tag__parse((git_tag *)object); error = git_tag__parse((git_tag *)object, odb_obj);
break; break;
case GIT_OBJ_BLOB: case GIT_OBJ_BLOB:
error = git_blob__parse((git_blob *)object); error = git_blob__parse((git_blob *)object, odb_obj);
break; break;
default: default:
break; break;
} }
git_odb_object_close(odb_obj);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS) {
git_object__free(object); git_object__free(object);
return error; return error;
} }
git_object__source_close(object); *object_out = git_cache_try_store(&repo->objects, object);
git_hashtable_insert(repo->objects, &object->id, object);
GIT_OBJECT_INCREF(repo, object);
*object_out = object;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_object_write(git_object *object) void git_object__free(void *_obj)
{ {
int error; git_object *object = (git_object *)_obj;
git_odb_source *source;
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); assert(object);
git_object__source_close(object); switch (object->type) {
switch (object->source.raw.type) {
case GIT_OBJ_COMMIT: case GIT_OBJ_COMMIT:
git_commit__free((git_commit *)object); git_commit__free((git_commit *)object);
break; break;
...@@ -412,34 +196,19 @@ void git_object_close(git_object *object) ...@@ -412,34 +196,19 @@ void git_object_close(git_object *object)
if (object == NULL) if (object == NULL)
return; return;
if (--object->refcount <= 0) { git_cached_obj_decref((git_cached_obj *)object, git_object__free);
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);
}
} }
const git_oid *git_object_id(const git_object *obj) const git_oid *git_object_id(const git_object *obj)
{ {
assert(obj); assert(obj);
return &obj->cached.oid;
if (obj->in_memory)
return NULL;
return &obj->id;
} }
git_otype git_object_type(const git_object *obj) git_otype git_object_type(const git_object *obj)
{ {
assert(obj); assert(obj);
return obj->source.raw.type; return obj->type;
} }
git_repository *git_object_owner(const git_object *obj) git_repository *git_object_owner(const git_object *obj)
......
...@@ -87,54 +87,67 @@ int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *ob ...@@ -87,54 +87,67 @@ int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *ob
return GIT_SUCCESS; return GIT_SUCCESS;
} }
void git_rawobj_close(git_rawobj *obj)
{
free(obj->data);
obj->data = NULL;
}
int git_rawobj_hash(git_oid *id, git_rawobj *obj) static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source)
{ {
char hdr[64]; git_odb_object *object = git__malloc(sizeof(git_odb_object));
int hdrlen; memset(object, 0x0, sizeof(git_odb_object));
assert(id && obj); git_oid_cpy(&object->cached.oid, oid);
memcpy(&object->raw, source, sizeof(git_rawobj));
return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj); return object;
} }
int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) static void free_odb_object(void *o)
{ {
z_stream zs; git_odb_object *object = (git_odb_object *)o;
int status = Z_OK;
memset(&zs, 0x0, sizeof(zs));
zs.next_out = out; if (object != NULL) {
zs.avail_out = outlen; free(object->raw.data);
free(object);
zs.next_in = in; }
zs.avail_in = inlen; }
if (inflateInit(&zs) < Z_OK)
return GIT_ERROR;
while (status == Z_OK) const git_oid *git_odb_object_id(git_odb_object *object)
status = inflate(&zs, Z_FINISH); {
return &object->cached.oid;
}
inflateEnd(&zs); const void *git_odb_object_data(git_odb_object *object)
{
return object->raw.data;
}
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */) size_t git_odb_object_size(git_odb_object *object)
return GIT_ERROR; {
return object->raw.len;
}
if (zs.total_out != outlen) git_otype git_odb_object_type(git_odb_object *object)
return GIT_ERROR; {
return object->raw.type;
}
return GIT_SUCCESS; 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);
raw.data = (void *)data;
raw.len = len;
raw.type = type;
return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, &raw);
}
/*********************************************************** /***********************************************************
...@@ -162,6 +175,8 @@ int git_odb_new(git_odb **out) ...@@ -162,6 +175,8 @@ int git_odb_new(git_odb **out)
if (!db) if (!db)
return GIT_ENOMEM; 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) { if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
free(db); free(db);
return GIT_ENOMEM; return GIT_ENOMEM;
...@@ -306,16 +321,23 @@ void git_odb_close(git_odb *db) ...@@ -306,16 +321,23 @@ void git_odb_close(git_odb *db)
} }
git_vector_free(&db->backends); git_vector_free(&db->backends);
git_cache_free(&db->cache);
free(db); free(db);
} }
int git_odb_exists(git_odb *db, const git_oid *id) int git_odb_exists(git_odb *db, const git_oid *id)
{ {
git_odb_object *object;
unsigned int i; unsigned int i;
int found = 0; int found = 0;
assert(db && id); 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) { for (i = 0; i < db->backends.length && !found; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
...@@ -327,19 +349,27 @@ int git_odb_exists(git_odb *db, const git_oid *id) ...@@ -327,19 +349,27 @@ int git_odb_exists(git_odb *db, const git_oid *id)
return found; 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; unsigned int i;
int error = GIT_ENOTFOUND; 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) { for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
if (b->read_header != NULL) 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) ...@@ -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 * try reading the whole object and freeing the contents
*/ */
if (error < 0) { if (error < 0) {
error = git_odb_read(out, db, id); if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS)
git_rawobj_close(out); 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; unsigned int i;
int error = GIT_ENOTFOUND; int error = GIT_ENOTFOUND;
git_rawobj raw;
assert(out && db && id); 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) { for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
if (b->read != NULL) 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; 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; unsigned int i;
int error = GIT_ERROR; int error = GIT_ERROR;
assert(obj && db && id); assert(oid && db);
for (i = 0; i < db->backends.length && error < 0; ++i) { for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, 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) ...@@ -388,7 +431,60 @@ int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
continue; continue;
if (b->write != NULL) 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; return error;
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment